The original behavior of C<isl_union_pw_multi_aff_add> was
confused and is no longer available.
+=item * Band forests have been replaced by schedule trees.
+
+=item * The function C<isl_union_map_compute_flow> has been
+replaced by the function C<isl_union_access_info_compute_flow>.
+Note that the may dependence relation returned by
+C<isl_union_flow_get_may_dependence> is the union of
+the two dependence relations returned by
+C<isl_union_map_compute_flow>. Similarly for the no source relations.
+The function C<isl_union_map_compute_flow> is still available
+for backward compatibility, but it will be removed in the future.
+
+=item * The function C<isl_basic_set_drop_constraint> has been
+deprecated.
+
=back
=head1 License
__isl_give isl_set *isl_set_add_constraint(
__isl_take isl_set *set,
__isl_take isl_constraint *constraint);
- __isl_give isl_basic_set *isl_basic_set_drop_constraint(
- __isl_take isl_basic_set *bset,
- __isl_take isl_constraint *constraint);
For example, to create a set containing the even integers
between 10 and 42, you would use the following code.
__isl_null isl_schedule *isl_schedule_free(
__isl_take isl_schedule *sched);
+The following functions checks whether two C<isl_schedule> objects
+are obviously the same.
+
+ #include <isl/schedule.h>
+ int isl_schedule_plain_is_equal(
+ __isl_keep isl_schedule *schedule1,
+ __isl_keep isl_schedule *schedule2);
+
The domain of the schedule, i.e., the domain described by the root node,
can be obtained using the following function.
__isl_give isl_union_set *isl_schedule_get_domain(
__isl_keep isl_schedule *schedule);
+An extra top-level band node (right underneath the domain node) can
+be introduced into the schedule using the following function.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *
+ isl_schedule_insert_partial_schedule(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_multi_union_pw_aff *partial);
+
+A schedule that combines two schedules either in the given
+order or in an arbitrary order, i.e., with an C<isl_schedule_node_sequence>
+or an C<isl_schedule_node_set> node,
+can be created using the following functions.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *isl_schedule_sequence(
+ __isl_take isl_schedule *schedule1,
+ __isl_take isl_schedule *schedule2);
+ __isl_give isl_schedule *isl_schedule_set(
+ __isl_take isl_schedule *schedule1,
+ __isl_take isl_schedule *schedule2);
+
+The domains of the two input schedules need to be disjoint.
+
+The following function can be used to restrict the domain
+of a schedule to be a subset of the given union set.
+This operation may remove nodes in the tree that have become
+redundant.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *isl_schedule_intersect_domain(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_union_set *domain);
+
+The following function resets the user pointers on all parameter
+and tuple identifiers referenced by the nodes of the given schedule.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *isl_schedule_reset_user(
+ __isl_take isl_schedule *schedule);
+
+The following function aligns the parameters of all nodes
+in the given schedule to the given space.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *isl_schedule_align_params(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_space *space);
+
+The following function allows the user to plug in a given function
+in the iteration domains.
+
+ #include <isl/schedule.h>
+ __isl_give isl_schedule *
+ isl_schedule_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_union_pw_multi_aff *upma);
+
An C<isl_union_map> representation of the schedule can be obtained
from an C<isl_schedule> using the following function.
__isl_null isl_schedule_node *isl_schedule_node_free(
__isl_take isl_schedule_node *node);
+The following functions can be used to check if two schedule
+nodes point to the same position in the same schedule.
+
+ #include <isl/schedule_node.h>
+ int isl_schedule_node_is_equal(
+ __isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2);
+
The following properties can be obtained from a schedule node.
#include <isl/schedule_node.h>
__isl_keep isl_schedule_node *node);
__isl_give isl_schedule_node *isl_schedule_node_parent(
__isl_take isl_schedule_node *node);
+ __isl_give isl_schedule_node *isl_schedule_node_root(
+ __isl_take isl_schedule_node *node);
+ __isl_give isl_schedule_node *isl_schedule_node_ancestor(
+ __isl_take isl_schedule_node *node,
+ int generation);
int isl_schedule_node_n_children(
__isl_keep isl_schedule_node *node);
__isl_give isl_schedule_node *isl_schedule_node_child(
isl_schedule_node_next_sibling(
__isl_take isl_schedule_node *node);
+For C<isl_schedule_node_ancestor>, the ancestor of generation 0
+is the node itself, the ancestor of generation 1 is its parent and so on.
+
It is also possible to query the number of ancestors of a node,
the position of the current node
-within the children of its parent or to obtain a copy of a given
+within the children of its parent, the position of the subtree
+containing a node within the children of an ancestor
+or to obtain a copy of a given
child without destroying the current node.
+Given two nodes that point to the same schedule, their closest
+shared ancestor can be obtained using
+C<isl_schedule_node_get_shared_ancestor>.
#include <isl/schedule_node.h>
int isl_schedule_node_get_tree_depth(
__isl_keep isl_schedule_node *node);
int isl_schedule_node_get_child_position(
__isl_keep isl_schedule_node *node);
+ int isl_schedule_node_get_ancestor_child_position(
+ __isl_keep isl_schedule_node *node,
+ __isl_keep isl_schedule_node *ancestor);
__isl_give isl_schedule_node *isl_schedule_node_get_child(
__isl_keep isl_schedule_node *node, int pos);
+ __isl_give isl_schedule_node *
+ isl_schedule_node_get_shared_ancestor(
+ __isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2);
All nodes in a schedule tree or
all descendants of a specific node (including the node) can be visited
returns a positive value, then the children are visited, but if
the callback returns zero, then the children are not visited.
+The ancestors of a node in a schedule tree can be visited from
+the root down to and including the parent of the node using
+the following function.
+
+ #include <isl/schedule_node.h>
+ int isl_schedule_node_foreach_ancestor_top_down(
+ __isl_keep isl_schedule_node *node,
+ int (*fn)(__isl_keep isl_schedule_node *node,
+ void *user), void *user);
+
The following functions allows for a depth-first post-order
traversal of the nodes in a schedule tree or
of the descendants of a specific node (including the node
lead to an infinite loop. It is safest to always return a pointer
to the same position (same ancestors and child positions) as the input node.
+The following function removes a node (along with its descendants)
+from a schedule tree and returns a pointer to the leaf at the
+same position in the updated tree.
+It is not allowed to remove the root of a schedule tree or
+a child of a set or sequence node.
+
+ #include <isl/schedule_node.h>
+ __isl_give isl_schedule_node *isl_schedule_node_cut(
+ __isl_take isl_schedule_node *node);
+
+The following function removes a single node
+from a schedule tree and returns a pointer to the child
+of the node, now located at the position of the original node
+or to a leaf node at that position if there was no child.
+It is not allowed to remove the root of a schedule tree,
+a set or sequence node or a child of a set or sequence node.
+
+ #include <isl/schedule_node.h>
+ __isl_give isl_schedule_node *isl_schedule_node_delete(
+ __isl_take isl_schedule_node *node);
+
+The following function resets the user pointers on all parameter
+and tuple identifiers referenced by the given schedule node.
+
+ #include <isl/schedule_node.h>
+ __isl_give isl_schedule_node *isl_schedule_node_reset_user(
+ __isl_take isl_schedule_node *node);
+
+The following function aligns the parameters of the given schedule
+node to the given space.
+
+ #include <isl/schedule_node.h>
+ __isl_give isl_schedule_node *
+ isl_schedule_node_align_params(
+ __isl_take isl_schedule_node *node,
+ __isl_take isl_space *space);
+
Several node types have their own functions for querying
(and in some cases setting) some node type specific properties.
returns a representation of the partial schedule defined by the
subtree rooted at the given node.
+The total number of outer band members of given node, i.e.,
+the shared output dimension of the maps in the result
+of C<isl_schedule_node_get_prefix_schedule_union_map> can be obtained
+using the following function.
+
+ #include <isl/schedule_node.h>
+ int isl_schedule_node_get_schedule_depth(
+ __isl_keep isl_schedule_node *node);
+
The following function returns the union of universes in the spaces that
contain elements that reach the given node.
If, on the other hand, all sources are I<must> accesses,
then value based dependence analysis is performed.
+=head3 High-level Interface
+
+A high-level interface to dependence analysis is provided
+by the following function.
+
+ #include <isl/flow.h>
+ __isl_give isl_union_flow *
+ isl_union_access_info_compute_flow(
+ __isl_take isl_union_access_info *access);
+
+The input C<isl_union_access_info> object describes the sink
+access relations, the source access relations and a schedule,
+while the output C<isl_union_flow> object describes
+the resulting dependence relations and the subsets of the
+sink relations for which no source was found.
+
+An C<isl_union_access_info> is created, modified and freed using
+the following functions.
+
+ #include <isl/flow.h>
+ __isl_give isl_union_access_info *
+ isl_union_access_info_from_sink(
+ __isl_take isl_union_map *sink);
+ __isl_give isl_union_access_info *
+ isl_union_access_info_set_must_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *must_source);
+ __isl_give isl_union_access_info *
+ isl_union_access_info_set_may_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *may_source);
+ __isl_give isl_union_access_info *
+ isl_union_access_info_set_schedule(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_schedule *schedule);
+ __isl_give isl_union_access_info *
+ isl_union_access_info_set_schedule_map(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *schedule_map);
+ __isl_null isl_union_access_info *
+ isl_union_access_info_free(
+ __isl_take isl_union_access_info *access);
+
+The may sources set by C<isl_union_access_info_set_may_source>
+do not need to include the must sources set by
+C<isl_union_access_info_set_must_source> as a subset.
+The user is free not to call one (or both) of these functions,
+in which case the corresponding set is kept to its empty default.
+Similarly, the default schedule initialized by
+C<isl_union_access_info_from_sink> is empty.
+The current schedule is determined by the last call to either
+C<isl_union_access_info_set_schedule> or
+C<isl_union_access_info_set_schedule_map>.
+The domain of the schedule corresponds to the domains of
+the access relations. In particular, the domains of the access
+relations are effectively intersected with the domain of the schedule
+and only the resulting accesses are considered by the dependence analysis.
+
+The output of C<isl_union_access_info_compute_flow> can be examined
+and freed using the following functions.
+
+ #include <isl/flow.h>
+ __isl_give isl_union_map *isl_union_flow_get_must_dependence(
+ __isl_keep isl_union_flow *flow);
+ __isl_give isl_union_map *isl_union_flow_get_may_dependence(
+ __isl_keep isl_union_flow *flow);
+ __isl_give isl_union_map *isl_union_flow_get_must_no_source(
+ __isl_keep isl_union_flow *flow);
+ __isl_give isl_union_map *isl_union_flow_get_may_no_source(
+ __isl_keep isl_union_flow *flow);
+ __isl_null isl_union_flow *isl_union_flow_free(
+ __isl_take isl_union_flow *flow);
+
+The relation returned by C<isl_union_flow_get_must_dependence>
+relates domain elements of must sources to domain elements of the sink.
+The relation returned by C<isl_union_flow_get_may_dependence>
+relates domain elements of must or may sources to domain elements of the sink
+and includes the previous relation as a subset.
+The relation returned by C<isl_union_flow_get_must_no_source> is the subset
+of the sink relation for which no dependences have been found.
+The relation returned by C<isl_union_flow_get_may_no_source> is the subset
+of the sink relation for which no definite dependences have been found.
+That is, it contains those sink access that do not contribute to any
+of the elements in the relation returned
+by C<isl_union_flow_get_must_dependence>.
+
+=head3 Low-level Interface
+
+A lower-level interface is provided by the following functions.
+
#include <isl/flow.h>
typedef int (*isl_access_level_before)(void *first, void *second);
After finishing with an C<isl_flow>, the user should call
C<isl_flow_free> to free all associated memory.
-A higher-level interface to dependence analysis is provided
-by the following function.
-
- #include <isl/flow.h>
-
- int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
- __isl_take isl_union_map *must_source,
- __isl_take isl_union_map *may_source,
- __isl_take isl_union_map *schedule,
- __isl_give isl_union_map **must_dep,
- __isl_give isl_union_map **may_dep,
- __isl_give isl_union_map **must_no_source,
- __isl_give isl_union_map **may_no_source);
-
-The arrays are identified by the tuple names of the ranges
-of the accesses. The iteration domains by the tuple names
-of the domains of the accesses and of the schedule.
-The relative order of the iteration domains is given by the
-schedule. The relations returned through C<must_no_source>
-and C<may_no_source> are subsets of C<sink>.
-Any of C<must_dep>, C<may_dep>, C<must_no_source>
-or C<may_no_source> may be C<NULL>, but a C<NULL> value for
-any of the other arguments is treated as an error.
-
-=head3 Interaction with Dependence Analysis
+=head3 Interaction with the Low-level Interface
During the dependence analysis, we frequently need to perform
the following operation. Given a relation between sink iterations
For more information on schedule trees, see
L</"Schedule Trees">.
-A representation of the schedule as a forest of bands can be obtained
-using the following function.
-
- __isl_give isl_band_list *isl_schedule_get_band_forest(
- __isl_keep isl_schedule *schedule);
-
-If the input schedule is represented by a schedule tree, then a call
-to C<isl_schedule_get_band_forest> replaces the internal schedule tree
-representation by a band forest representation.
-
-The individual bands can be visited in depth-first post-order
-using the following function.
-
- #include <isl/schedule.h>
- int isl_schedule_foreach_band(
- __isl_keep isl_schedule *sched,
- int (*fn)(__isl_keep isl_band *band, void *user),
- void *user);
-
-The list can be manipulated as explained in L<"Lists">.
-The bands inside the list can be copied and freed using the following
-functions.
-
- #include <isl/band.h>
- __isl_give isl_band *isl_band_copy(
- __isl_keep isl_band *band);
- __isl_null isl_band *isl_band_free(
- __isl_take isl_band *band);
-
-Each band contains zero or more scheduling dimensions.
-These are referred to as the members of the band.
-The section of the schedule that corresponds to the band is
-referred to as the partial schedule of the band.
-For those nodes that participate in a band, the outer scheduling
-dimensions form the prefix schedule, while the inner scheduling
-dimensions form the suffix schedule.
-That is, if we take a cut of the band forest, then the union of
-the concatenations of the prefix, partial and suffix schedules of
-each band in the cut is equal to the entire schedule (modulo
-some possible padding at the end with zero scheduling dimensions).
-The properties of a band can be inspected using the following functions.
-
- #include <isl/band.h>
- int isl_band_has_children(__isl_keep isl_band *band);
- __isl_give isl_band_list *isl_band_get_children(
- __isl_keep isl_band *band);
-
- __isl_give isl_union_map *isl_band_get_prefix_schedule(
- __isl_keep isl_band *band);
- __isl_give isl_union_map *isl_band_get_partial_schedule(
- __isl_keep isl_band *band);
- __isl_give isl_union_map *isl_band_get_suffix_schedule(
- __isl_keep isl_band *band);
-
- int isl_band_n_member(__isl_keep isl_band *band);
- int isl_band_member_is_coincident(
- __isl_keep isl_band *band, int pos);
-
- int isl_band_list_foreach_band(
- __isl_keep isl_band_list *list,
- int (*fn)(__isl_keep isl_band *band, void *user),
- void *user);
-
-Note that a scheduling dimension is considered to be ``coincident''
-if it satisfies the coincidence constraints within its band.
-That is, if the dependence distances of the coincidence
-constraints are all zero in that direction (for fixed
-iterations of outer bands).
-Like C<isl_schedule_foreach_band>,
-the function C<isl_band_list_foreach_band> calls C<fn> on the bands
-in depth-first post-order.
-
-A band can be tiled using the following function.
-
- #include <isl/band.h>
- int isl_band_tile(__isl_keep isl_band *band,
- __isl_take isl_vec *sizes);
-
- int isl_options_set_tile_scale_tile_loops(isl_ctx *ctx,
- int val);
- int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
- int isl_options_set_tile_shift_point_loops(isl_ctx *ctx,
- int val);
- int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
-
-The C<isl_band_tile> function tiles the band using the given tile sizes
-inside its schedule.
-A new child band is created to represent the point loops and it is
-inserted between the modified band and its children.
-The C<tile_scale_tile_loops> option specifies whether the tile
-loops iterators should be scaled by the tile sizes.
-If the C<tile_shift_point_loops> option is set, then the point loops
-are shifted to start at zero.
-
-A band can be split into two nested bands using the following function.
-
- int isl_band_split(__isl_keep isl_band *band, int pos);
-
-The resulting outer band contains the first C<pos> dimensions of C<band>
-while the inner band contains the remaining dimensions.
-
-A representation of the band can be printed using
-
- #include <isl/band.h>
- __isl_give isl_printer *isl_printer_print_band(
- __isl_take isl_printer *p,
- __isl_keep isl_band *band);
-
=head3 Options
#include <isl/schedule.h>
#include <isl/map_type.h>
#include <isl/union_set_type.h>
#include <isl/union_map_type.h>
+#include <isl/schedule.h>
#if defined(__cplusplus)
extern "C" {
isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps);
+struct isl_union_access_info;
+typedef struct isl_union_access_info isl_union_access_info;
+struct isl_union_flow;
+typedef struct isl_union_flow isl_union_flow;
+
+__isl_give isl_union_access_info *isl_union_access_info_from_sink(
+ __isl_take isl_union_map *sink);
+__isl_give isl_union_access_info *isl_union_access_info_set_must_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *must_source);
+__isl_give isl_union_access_info *isl_union_access_info_set_may_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *may_source);
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_schedule *schedule);
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *schedule_map);
+__isl_null isl_union_access_info *isl_union_access_info_free(
+ __isl_take isl_union_access_info *access);
+
+__isl_give isl_union_flow *isl_union_access_info_compute_flow(
+ __isl_take isl_union_access_info *access);
+
+__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+ __isl_keep isl_union_flow *flow);
+__isl_give isl_union_map *isl_union_flow_get_may_dependence(
+ __isl_keep isl_union_flow *flow);
+__isl_give isl_union_map *isl_union_flow_get_must_no_source(
+ __isl_keep isl_union_flow *flow);
+__isl_give isl_union_map *isl_union_flow_get_may_no_source(
+ __isl_keep isl_union_flow *flow);
+__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow);
+
int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
__isl_take isl_union_map *must_source,
__isl_take isl_union_map *may_source,
#include <isl/union_set_type.h>
#include <isl/union_map_type.h>
#include <isl/schedule_type.h>
+#include <isl/aff_type.h>
#include <isl/band.h>
#include <isl/space.h>
#include <isl/list.h>
__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched);
isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *sched);
+int isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1,
+ __isl_keep isl_schedule *schedule2);
__isl_give isl_schedule_node *isl_schedule_get_root(
__isl_keep isl_schedule *schedule);
__isl_give isl_schedule_node *(*fn)(
__isl_take isl_schedule_node *node, void *user), void *user);
+__isl_give isl_schedule *isl_schedule_insert_partial_schedule(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_multi_union_pw_aff *partial);
+__isl_give isl_schedule *isl_schedule_sequence(
+ __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2);
+__isl_give isl_schedule *isl_schedule_set(
+ __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2);
+__isl_give isl_schedule *isl_schedule_intersect_domain(
+ __isl_take isl_schedule *schedule, __isl_take isl_union_set *domain);
+
+__isl_give isl_schedule *isl_schedule_reset_user(
+ __isl_take isl_schedule *schedule);
+__isl_give isl_schedule *isl_schedule_align_params(
+ __isl_take isl_schedule *schedule, __isl_take isl_space *space);
+__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_union_pw_multi_aff *upma);
+
__isl_give isl_band_list *isl_schedule_get_band_forest(
__isl_keep isl_schedule *schedule);
__isl_null isl_schedule_node *isl_schedule_node_free(
__isl_take isl_schedule_node *node);
+int isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2);
+
isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node);
enum isl_schedule_node_type isl_schedule_node_get_type(
__isl_keep isl_schedule_node *node);
int isl_schedule_node_foreach_descendant(__isl_keep isl_schedule_node *node,
int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user);
+int isl_schedule_node_foreach_ancestor_top_down(
+ __isl_keep isl_schedule_node *node,
+ int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user);
__isl_give isl_schedule_node *isl_schedule_node_map_descendant(
__isl_take isl_schedule_node *node,
__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
int isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node);
int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node);
int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node);
+int isl_schedule_node_get_ancestor_child_position(
+ __isl_keep isl_schedule_node *node,
+ __isl_keep isl_schedule_node *ancestor);
__isl_give isl_schedule_node *isl_schedule_node_get_child(
__isl_keep isl_schedule_node *node, int pos);
+__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor(
+ __isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2);
+__isl_give isl_schedule_node *isl_schedule_node_root(
+ __isl_take isl_schedule_node *node);
__isl_give isl_schedule_node *isl_schedule_node_parent(
__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_ancestor(
+ __isl_take isl_schedule_node *node, int generation);
__isl_give isl_schedule_node *isl_schedule_node_child(
__isl_take isl_schedule_node *node, int pos);
__isl_give isl_schedule_node *isl_schedule_node_first_child(
__isl_give isl_union_set *isl_schedule_node_filter_get_filter(
__isl_keep isl_schedule_node *node);
+int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node);
__isl_give isl_union_set *isl_schedule_node_get_universe_domain(
__isl_keep isl_schedule_node *node);
__isl_give isl_union_pw_multi_aff *
__isl_take isl_schedule_node *node,
__isl_take isl_union_set_list *filters);
+__isl_give isl_schedule_node *isl_schedule_node_cut(
+ __isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_delete(
+ __isl_take isl_schedule_node *node);
+
+__isl_give isl_schedule_node *isl_schedule_node_reset_user(
+ __isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_align_params(
+ __isl_take isl_schedule_node *node, __isl_take isl_space *space);
+
__isl_give isl_printer *isl_printer_print_schedule_node(
__isl_take isl_printer *p, __isl_keep isl_schedule_node *node);
void isl_schedule_node_dump(__isl_keep isl_schedule_node *node);
static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff)
{
int i, j, n;
- unsigned off;
if (!aff)
return NULL;
- off = isl_local_space_offset(aff->ls, isl_dim_div);
n = isl_aff_dim(aff, isl_dim_div);
for (i = 1; i < n; ++i) {
for (j = i - 1; j >= 0; --j) {
map = set;
else
map = isl_set_unwrap(set);
- pma = isl_pw_multi_aff_from_map(set);
+ pma = isl_pw_multi_aff_from_map(map);
if (!is_set) {
space = isl_pw_multi_aff_get_domain_space(pma);
static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned(
__isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)
{
- int i, n_param, n_in, n_div;
+ int i, n_in, n_div;
isl_space *space;
isl_val *v;
isl_pw_aff *pa;
isl_aff *tmp;
- n_param = isl_aff_dim(aff, isl_dim_param);
n_in = isl_aff_dim(aff, isl_dim_in);
n_div = isl_aff_dim(aff, isl_dim_div);
printf("\n%30s", "");
else
printf("%*s", 30 - pos, "");
- pos = 0;
} else {
if (pos + len >= 48)
printf("\n%30s", "");
printf("\n%30s", "");
else
printf("%*s", 30 - pos, "");
- pos = 0;
} else {
if (pos + len >= 48)
printf("\n%30s", "");
int equal;
equal = isl_ast_expr_is_equal(expr1->u.op.args[i],
expr2->u.op.args[i]);
- return 0;
if (equal < 0 || !equal)
return equal;
}
__isl_keep isl_aff *aff, __isl_keep isl_val *d,
__isl_keep isl_ast_build *build)
{
- isl_ctx *ctx;
isl_ast_expr *expr;
isl_ast_expr *c;
if (!aff)
return NULL;
- ctx = isl_aff_get_ctx(aff);
expr = isl_ast_expr_from_aff(isl_aff_copy(aff), build);
c = isl_ast_expr_from_val(isl_val_copy(d));
static __isl_give isl_ast_expr *isl_ast_expr_add_int(
__isl_take isl_ast_expr *expr, __isl_take isl_val *v)
{
- isl_ctx *ctx;
isl_ast_expr *expr_int;
if (!expr || !v)
return expr;
}
- ctx = isl_ast_expr_get_ctx(expr);
if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) {
v = isl_val_neg(v);
expr_int = isl_ast_expr_from_val(v);
r = isl_pw_aff_foreach_piece(pa, &aff_constant_is_negative, user);
isl_pw_aff_free(pa);
- return *neg ? 0 : -1;
+ return (*neg && r >= 0) ? 0 : -1;
}
/* Does each element in "list" have a negative constant term?
{
int i, n;
int depth;
- isl_ctx *ctx;
isl_aff *lower;
isl_multi_aff *expansion;
isl_basic_map *bmap;
if (!domain)
return isl_set_free(class_domain);
- ctx = isl_set_get_ctx(domain);
depth = isl_ast_build_get_depth(domains->build);
build = isl_ast_build_copy(domains->build);
domain = isl_ast_build_eliminate_inner(build, domain);
isl_ast_graft_list *list;
int first;
int depth;
- isl_ctx *ctx;
isl_val *val;
isl_multi_val *mv;
isl_space *space;
isl_multi_aff *ma, *zero;
isl_union_map *executed;
- ctx = isl_ast_build_get_ctx(build);
depth = isl_ast_build_get_depth(build);
first = first_offset(domain, order, n, build);
* In particular, this means that the local spaces of "bset" and
* "constraint" need to be the same.
*
- * Since the given constraint may actually be a pointer into the bset,
- * we have to be careful not to reorder the constraints as the user
- * may be holding on to other constraints from the same bset.
- * This should be cleaned up when the internal representation of
- * isl_constraint is changed to use isl_aff.
+ * We manually set ISL_BASIC_SET_FINAL instead of calling
+ * isl_basic_set_finalize because this function is called by CLooG,
+ * which does not expect any variables to disappear.
*/
__isl_give isl_basic_set *isl_basic_set_drop_constraint(
__isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint)
unsigned total;
isl_local_space *ls1;
int equal;
+ int equality;
if (!bset || !constraint)
goto error;
return bset;
}
- if (isl_constraint_is_equality(constraint)) {
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ goto error;
+
+ equality = isl_constraint_is_equality(constraint);
+ if (equality) {
n = bset->n_eq;
row = bset->eq;
} else {
}
total = isl_constraint_dim(constraint, isl_dim_all);
- for (i = 0; i < n; ++i)
- if (isl_seq_eq(row[i], constraint->v->el, 1 + total))
- isl_seq_clr(row[i], 1 + total);
+ for (i = 0; i < n; ++i) {
+ if (!isl_seq_eq(row[i], constraint->v->el, 1 + total))
+ continue;
+ if (equality && isl_basic_set_drop_equality(bset, i) < 0)
+ goto error;
+ if (!equality && isl_basic_set_drop_inequality(bset, i) < 0)
+ goto error;
+ break;
+ }
isl_constraint_free(constraint);
+ ISL_F_SET(bset, ISL_BASIC_SET_FINAL);
return bset;
error:
isl_constraint_free(constraint);
if (!bset1 || !bset2)
goto error;
- ctx = bset1->ctx;
+ ctx = isl_basic_set_get_ctx(bset1);
dir = valid_direction(isl_basic_set_copy(bset1),
isl_basic_set_copy(bset2));
if (!dir)
goto error;
- T = isl_mat_alloc(bset1->ctx, dir->size, dir->size);
+ T = isl_mat_alloc(ctx, dir->size, dir->size);
if (!T)
goto error;
isl_seq_cpy(T->row[0], dir->block.data, dir->size);
struct isl_basic_set *affine_hull = NULL;
struct isl_basic_map *convex_hull = NULL;
struct isl_set *set = NULL;
- struct isl_ctx *ctx;
map = isl_map_detect_equalities(map);
map = isl_map_align_divs(map);
if (!map)
goto error;
- ctx = map->ctx;
if (map->n == 0) {
convex_hull = isl_basic_map_empty_like_map(map);
isl_map_free(map);
return 0;
}
- ctx = bset->ctx;
+ ctx = isl_basic_set_get_ctx(bset);
total = isl_basic_set_total_dim(bset);
nparam = isl_basic_set_n_param(bset);
- H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
+ H = isl_mat_sub_alloc6(ctx, bset->eq, 0, bset->n_eq, 1, total);
H = isl_mat_left_hermite(H, 0, &U, NULL);
if (!H)
return -1;
return 0;
}
- C = isl_mat_alloc(bset->ctx, 1+bset->n_eq, 1);
+ C = isl_mat_alloc(ctx, 1 + bset->n_eq, 1);
if (!C)
goto error;
isl_int_set_si(C->row[0][0], 1);
- isl_mat_sub_neg(C->ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
+ isl_mat_sub_neg(ctx, C->row + 1, bset->eq, bset->n_eq, 0, 0, 1);
H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
H1 = isl_mat_lin_to_aff(H1);
C = isl_mat_inverse_product(H1, C);
* Copyright 2008-2009 Katholieke Universiteit Leuven
* Copyright 2010 INRIA Saclay
* Copyright 2012 Universiteit Leiden
+ * Copyright 2014 Ecole Normale Superieure
*
* Use of this software is governed by the MIT license
*
* B-3001 Leuven, Belgium
* and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
* ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
*/
#include <isl/set.h>
#include <isl/map.h>
#include <isl/flow.h>
+#include <isl/schedule_node.h>
#include <isl_sort.h>
enum isl_restriction_type {
return NULL;
}
-struct isl_compute_flow_data {
+/* This structure represents the input for a dependence analysis computation.
+ *
+ * "sink" represents the sink accesses.
+ * "must_source" represents the definite source accesses.
+ * "may_source" represents the possible source accesses.
+ *
+ * "schedule" or "schedule_map" represents the execution order.
+ * Exactly one of these fields should be NULL. The other field
+ * determines the execution order.
+ *
+ * The domains of these four maps refer to the same iteration spaces(s).
+ * The ranges of the first three maps also refer to the same data space(s).
+ *
+ * After a call to isl_union_access_info_introduce_schedule,
+ * the "schedule_map" field no longer contains useful information.
+ */
+struct isl_union_access_info {
+ isl_union_map *sink;
isl_union_map *must_source;
isl_union_map *may_source;
+
+ isl_schedule *schedule;
+ isl_union_map *schedule_map;
+};
+
+/* Free "access" and return NULL.
+ */
+__isl_null isl_union_access_info *isl_union_access_info_free(
+ __isl_take isl_union_access_info *access)
+{
+ if (!access)
+ return NULL;
+
+ isl_union_map_free(access->sink);
+ isl_union_map_free(access->must_source);
+ isl_union_map_free(access->may_source);
+ isl_schedule_free(access->schedule);
+ isl_union_map_free(access->schedule_map);
+ free(access);
+
+ return NULL;
+}
+
+/* Return the isl_ctx to which "access" belongs.
+ */
+isl_ctx *isl_union_access_info_get_ctx(__isl_keep isl_union_access_info *access)
+{
+ return access ? isl_union_map_get_ctx(access->sink) : NULL;
+}
+
+/* Create a new isl_union_access_info with the given sink accesses and
+ * and no source accesses or schedule information.
+ *
+ * By default, we use the schedule field of the isl_union_access_info,
+ * but this may be overridden by a call
+ * to isl_union_access_info_set_schedule_map.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_from_sink(
+ __isl_take isl_union_map *sink)
+{
+ isl_ctx *ctx;
+ isl_space *space;
+ isl_union_map *empty;
+ isl_union_access_info *access;
+
+ if (!sink)
+ return NULL;
+ ctx = isl_union_map_get_ctx(sink);
+ access = isl_alloc_type(ctx, isl_union_access_info);
+ if (!access)
+ goto error;
+
+ space = isl_union_map_get_space(sink);
+ empty = isl_union_map_empty(isl_space_copy(space));
+ access->sink = sink;
+ access->must_source = isl_union_map_copy(empty);
+ access->may_source = empty;
+ access->schedule = isl_schedule_empty(space);
+ access->schedule_map = NULL;
+
+ if (!access->sink || !access->must_source ||
+ !access->may_source || !access->schedule)
+ return isl_union_access_info_free(access);
+
+ return access;
+error:
+ isl_union_map_free(sink);
+ return NULL;
+}
+
+/* Replace the definite source accesses of "access" by "must_source".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_must_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *must_source)
+{
+ if (!access || !must_source)
+ goto error;
+
+ isl_union_map_free(access->must_source);
+ access->must_source = must_source;
+
+ return access;
+error:
+ isl_union_access_info_free(access);
+ isl_union_map_free(must_source);
+ return NULL;
+}
+
+/* Replace the possible source accesses of "access" by "may_source".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_may_source(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *may_source)
+{
+ if (!access || !may_source)
+ goto error;
+
+ isl_union_map_free(access->may_source);
+ access->may_source = may_source;
+
+ return access;
+error:
+ isl_union_access_info_free(access);
+ isl_union_map_free(may_source);
+ return NULL;
+}
+
+/* Replace the schedule of "access" by "schedule".
+ * Also free the schedule_map in case it was set last.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_schedule *schedule)
+{
+ if (!access || !schedule)
+ goto error;
+
+ access->schedule_map = isl_union_map_free(access->schedule_map);
+ isl_schedule_free(access->schedule);
+ access->schedule = schedule;
+
+ return access;
+error:
+ isl_union_access_info_free(access);
+ isl_schedule_free(schedule);
+ return NULL;
+}
+
+/* Replace the schedule map of "access" by "schedule_map".
+ * Also free the schedule in case it was set last.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map(
+ __isl_take isl_union_access_info *access,
+ __isl_take isl_union_map *schedule_map)
+{
+ if (!access || !schedule_map)
+ goto error;
+
+ isl_union_map_free(access->schedule_map);
+ access->schedule = isl_schedule_free(access->schedule);
+ access->schedule_map = schedule_map;
+
+ return access;
+error:
+ isl_union_access_info_free(access);
+ isl_union_map_free(schedule_map);
+ return NULL;
+}
+
+/* Update the fields of "access" such that they all have the same parameters,
+ * keeping in mind that the schedule_map field may be NULL and ignoring
+ * the schedule field.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_align_params(
+ __isl_take isl_union_access_info *access)
+{
+ isl_space *space;
+
+ if (!access)
+ return NULL;
+
+ space = isl_union_map_get_space(access->sink);
+ space = isl_space_align_params(space,
+ isl_union_map_get_space(access->must_source));
+ space = isl_space_align_params(space,
+ isl_union_map_get_space(access->may_source));
+ if (access->schedule_map)
+ space = isl_space_align_params(space,
+ isl_union_map_get_space(access->schedule_map));
+ access->sink = isl_union_map_align_params(access->sink,
+ isl_space_copy(space));
+ access->must_source = isl_union_map_align_params(access->must_source,
+ isl_space_copy(space));
+ access->may_source = isl_union_map_align_params(access->may_source,
+ isl_space_copy(space));
+ if (!access->schedule_map) {
+ isl_space_free(space);
+ } else {
+ access->schedule_map =
+ isl_union_map_align_params(access->schedule_map, space);
+ if (!access->schedule_map)
+ return isl_union_access_info_free(access);
+ }
+
+ if (!access->sink || !access->must_source || !access->may_source)
+ return isl_union_access_info_free(access);
+
+ return access;
+}
+
+/* Prepend the schedule dimensions to the iteration domains.
+ *
+ * That is, if the schedule is of the form
+ *
+ * D -> S
+ *
+ * while the access relations are of the form
+ *
+ * D -> A
+ *
+ * then the updated access relations are of the form
+ *
+ * [S -> D] -> A
+ *
+ * The schedule map is also replaced by the map
+ *
+ * [S -> D] -> D
+ *
+ * that is used during the internal computation.
+ * Neither the original schedule map nor this updated schedule map
+ * are used after the call to this function.
+ */
+static __isl_give isl_union_access_info *
+isl_union_access_info_introduce_schedule(
+ __isl_take isl_union_access_info *access)
+{
+ isl_union_map *sm;
+
+ if (!access)
+ return NULL;
+
+ sm = isl_union_map_reverse(access->schedule_map);
+ sm = isl_union_map_range_map(sm);
+ access->sink = isl_union_map_apply_range(isl_union_map_copy(sm),
+ access->sink);
+ access->may_source = isl_union_map_apply_range(isl_union_map_copy(sm),
+ access->may_source);
+ access->must_source = isl_union_map_apply_range(isl_union_map_copy(sm),
+ access->must_source);
+ access->schedule_map = sm;
+
+ if (!access->sink || !access->must_source ||
+ !access->may_source || !access->schedule_map)
+ return isl_union_access_info_free(access);
+
+ return access;
+}
+
+/* This structure epresents the result of a dependence analysis computation.
+ *
+ * "must_dep" represents the definite dependences.
+ * "may_dep" represents the non-definite dependences.
+ * "must_no_source" represents the subset of the sink accesses for which
+ * definitely no source was found.
+ * "may_no_source" represents the subset of the sink accesses for which
+ * possibly, but not definitely, no source was found.
+ */
+struct isl_union_flow {
isl_union_map *must_dep;
isl_union_map *may_dep;
isl_union_map *must_no_source;
isl_union_map *may_no_source;
+};
+
+/* Free "flow" and return NULL.
+ */
+__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ isl_union_map_free(flow->must_dep);
+ isl_union_map_free(flow->may_dep);
+ isl_union_map_free(flow->must_no_source);
+ isl_union_map_free(flow->may_no_source);
+ free(flow);
+ return NULL;
+}
+
+void isl_union_flow_dump(__isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return;
+
+ fprintf(stderr, "must dependences: ");
+ isl_union_map_dump(flow->must_dep);
+ fprintf(stderr, "may dependences: ");
+ isl_union_map_dump(flow->may_dep);
+ fprintf(stderr, "must no source: ");
+ isl_union_map_dump(flow->must_no_source);
+ fprintf(stderr, "may no source: ");
+ isl_union_map_dump(flow->may_no_source);
+}
+
+/* Return the definite dependences in "flow".
+ */
+__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_copy(flow->must_dep);
+}
+
+/* Return the possible dependences in "flow", including the definite
+ * dependences.
+ */
+__isl_give isl_union_map *isl_union_flow_get_may_dependence(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_union(isl_union_map_copy(flow->must_dep),
+ isl_union_map_copy(flow->may_dep));
+}
+
+/* Return the non-definite dependences in "flow".
+ */
+static __isl_give isl_union_map *isl_union_flow_get_non_must_dependence(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_copy(flow->may_dep);
+}
+
+/* Return the subset of the sink accesses for which definitely
+ * no source was found.
+ */
+__isl_give isl_union_map *isl_union_flow_get_must_no_source(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_copy(flow->must_no_source);
+}
+
+/* Return the subset of the sink accesses for which possibly
+ * no source was found, including those for which definitely
+ * no source was found.
+ */
+__isl_give isl_union_map *isl_union_flow_get_may_no_source(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_union(isl_union_map_copy(flow->must_no_source),
+ isl_union_map_copy(flow->may_no_source));
+}
+
+/* Return the subset of the sink accesses for which possibly, but not
+ * definitely, no source was found.
+ */
+static __isl_give isl_union_map *isl_union_flow_get_non_must_no_source(
+ __isl_keep isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+ return isl_union_map_copy(flow->may_no_source);
+}
+
+/* Create a new isl_union_flow object, initialized with empty
+ * dependence relations and sink subsets.
+ */
+static __isl_give isl_union_flow *isl_union_flow_alloc(
+ __isl_take isl_space *space)
+{
+ isl_ctx *ctx;
+ isl_union_map *empty;
+ isl_union_flow *flow;
+
+ if (!space)
+ return NULL;
+ ctx = isl_space_get_ctx(space);
+ flow = isl_alloc_type(ctx, isl_union_flow);
+ if (!flow)
+ goto error;
+
+ empty = isl_union_map_empty(space);
+ flow->must_dep = isl_union_map_copy(empty);
+ flow->may_dep = isl_union_map_copy(empty);
+ flow->must_no_source = isl_union_map_copy(empty);
+ flow->may_no_source = empty;
+
+ if (!flow->must_dep || !flow->may_dep ||
+ !flow->must_no_source || !flow->may_no_source)
+ return isl_union_flow_free(flow);
+
+ return flow;
+error:
+ isl_space_free(space);
+ return NULL;
+}
+
+/* Drop the schedule dimensions from the iteration domains in "flow".
+ * In particular, the schedule dimensions have been prepended
+ * to the iteration domains prior to the dependence analysis by
+ * replacing the iteration domain D, by the wrapped map [S -> D].
+ * Replace these wrapped maps by the original D.
+ */
+static __isl_give isl_union_flow *isl_union_flow_drop_schedule(
+ __isl_take isl_union_flow *flow)
+{
+ if (!flow)
+ return NULL;
+
+ flow->must_dep = isl_union_map_factor_range(flow->must_dep);
+ flow->may_dep = isl_union_map_factor_range(flow->may_dep);
+ flow->must_no_source =
+ isl_union_map_domain_factor_range(flow->must_no_source);
+ flow->may_no_source =
+ isl_union_map_domain_factor_range(flow->may_no_source);
+
+ if (!flow->must_dep || !flow->may_dep ||
+ !flow->must_no_source || !flow->may_no_source)
+ return isl_union_flow_free(flow);
+
+ return flow;
+}
+
+struct isl_compute_flow_data {
+ isl_union_map *must_source;
+ isl_union_map *may_source;
+ isl_union_flow *flow;
int count;
int must;
isl_ctx *ctx;
struct isl_compute_flow_data *data;
isl_flow *flow;
+ isl_union_flow *df;
data = (struct isl_compute_flow_data *)user;
+ df = data->flow;
ctx = isl_map_get_ctx(map);
if (!flow)
goto error;
- data->must_no_source = isl_union_map_union(data->must_no_source,
+ df->must_no_source = isl_union_map_union(df->must_no_source,
isl_union_map_from_map(isl_flow_get_no_source(flow, 1)));
- data->may_no_source = isl_union_map_union(data->may_no_source,
+ df->may_no_source = isl_union_map_union(df->may_no_source,
isl_union_map_from_map(isl_flow_get_no_source(flow, 0)));
for (i = 0; i < flow->n_source; ++i) {
isl_union_map *dep;
dep = isl_union_map_from_map(isl_map_copy(flow->dep[i].map));
if (flow->dep[i].must)
- data->must_dep = isl_union_map_union(data->must_dep, dep);
+ df->must_dep = isl_union_map_union(df->must_dep, dep);
else
- data->may_dep = isl_union_map_union(data->may_dep, dep);
+ df->may_dep = isl_union_map_union(df->may_dep, dep);
}
isl_flow_free(flow);
return -1;
}
+/* Remove the must accesses from the may accesses.
+ *
+ * A must access always trumps a may access, so there is no need
+ * for a must access to also be considered as a may access. Doing so
+ * would only cost extra computations only to find out that
+ * the duplicated may access does not make any difference.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_normalize(
+ __isl_take isl_union_access_info *access)
+{
+ if (!access)
+ return NULL;
+ access->may_source = isl_union_map_subtract(access->may_source,
+ isl_union_map_copy(access->must_source));
+ if (!access->may_source)
+ return isl_union_access_info_free(access);
+
+ return access;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink. The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * This function is used when only the schedule map representation
+ * is available.
+ *
+ * We first prepend the schedule dimensions to the domain
+ * of the accesses so that we can easily compare their relative order.
+ * Then we consider each sink access individually in compute_flow.
+ */
+static __isl_give isl_union_flow *compute_flow_union_map(
+ __isl_take isl_union_access_info *access)
+{
+ struct isl_compute_flow_data data;
+
+ access = isl_union_access_info_align_params(access);
+ access = isl_union_access_info_introduce_schedule(access);
+ if (!access)
+ return NULL;
+
+ data.must_source = access->must_source;
+ data.may_source = access->may_source;
+
+ data.flow = isl_union_flow_alloc(isl_union_map_get_space(access->sink));
+
+ if (isl_union_map_foreach_map(access->sink, &compute_flow, &data) < 0)
+ goto error;
+
+ data.flow = isl_union_flow_drop_schedule(data.flow);
+
+ isl_union_access_info_free(access);
+ return data.flow;
+error:
+ isl_union_access_info_free(access);
+ isl_union_flow_free(data.flow);
+ return NULL;
+}
+
+/* A schedule access relation.
+ *
+ * The access relation "access" is of the form [S -> D] -> A,
+ * where S corresponds to the prefix schedule at "node".
+ * "must" is only relevant for source accesses and indicates
+ * whether the access is a must source or a may source.
+ */
+struct isl_scheduled_access {
+ isl_map *access;
+ int must;
+ isl_schedule_node *node;
+};
+
+/* Data structure for keeping track of individual scheduled sink and source
+ * accesses when computing dependence analysis based on a schedule tree.
+ *
+ * "n_sink" is the number of used entries in "sink"
+ * "n_source" is the number of used entries in "source"
+ *
+ * "set_sink", "must" and "node" are only used inside collect_sink_source,
+ * to keep track of the current node and
+ * of what extract_sink_source needs to do.
+ */
+struct isl_compute_flow_schedule_data {
+ isl_union_access_info *access;
+
+ int n_sink;
+ int n_source;
+
+ struct isl_scheduled_access *sink;
+ struct isl_scheduled_access *source;
+
+ int set_sink;
+ int must;
+ isl_schedule_node *node;
+};
+
+/* Align the parameters of all sinks with all sources.
+ *
+ * If there are no sinks or no sources, then no alignment is needed.
+ */
+static void isl_compute_flow_schedule_data_align_params(
+ struct isl_compute_flow_schedule_data *data)
+{
+ int i;
+ isl_space *space;
+
+ if (data->n_sink == 0 || data->n_source == 0)
+ return;
+
+ space = isl_map_get_space(data->sink[0].access);
+
+ for (i = 1; i < data->n_sink; ++i)
+ space = isl_space_align_params(space,
+ isl_map_get_space(data->sink[i].access));
+ for (i = 0; i < data->n_source; ++i)
+ space = isl_space_align_params(space,
+ isl_map_get_space(data->source[i].access));
+
+ for (i = 0; i < data->n_sink; ++i)
+ data->sink[i].access =
+ isl_map_align_params(data->sink[i].access,
+ isl_space_copy(space));
+ for (i = 0; i < data->n_source; ++i)
+ data->source[i].access =
+ isl_map_align_params(data->source[i].access,
+ isl_space_copy(space));
+
+ isl_space_free(space);
+}
+
+/* Free all the memory referenced from "data".
+ * Do not free "data" itself as it may be allocated on the stack.
+ */
+static void isl_compute_flow_schedule_data_clear(
+ struct isl_compute_flow_schedule_data *data)
+{
+ int i;
+
+ for (i = 0; i < data->n_sink; ++i) {
+ isl_map_free(data->sink[i].access);
+ isl_schedule_node_free(data->sink[i].node);
+ }
+
+ for (i = 0; i < data->n_source; ++i) {
+ isl_map_free(data->source[i].access);
+ isl_schedule_node_free(data->source[i].node);
+ }
+
+ free(data->sink);
+}
+
+/* isl_schedule_foreach_schedule_node callback for counting
+ * (an upper bound on) the number of sinks and sources.
+ *
+ * Sinks and sources are only extracted at leaves of the tree,
+ * so we skip the node if it is not a leaf.
+ * Otherwise we increment data->n_sink and data->n_source with
+ * the number of spaces in the sink and source access domains
+ * that reach this node.
+ */
+static int count_sink_source(__isl_keep isl_schedule_node *node, void *user)
+{
+ struct isl_compute_flow_schedule_data *data = user;
+ isl_union_set *domain;
+ isl_union_map *umap;
+ int r = 0;
+
+ if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+ return 1;
+
+ domain = isl_schedule_node_get_universe_domain(node);
+
+ umap = isl_union_map_copy(data->access->sink);
+ umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+ data->n_sink += isl_union_map_n_map(umap);
+ isl_union_map_free(umap);
+ if (!umap)
+ r = -1;
+
+ umap = isl_union_map_copy(data->access->must_source);
+ umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+ data->n_source += isl_union_map_n_map(umap);
+ isl_union_map_free(umap);
+ if (!umap)
+ r = -1;
+
+ umap = isl_union_map_copy(data->access->may_source);
+ umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+ data->n_source += isl_union_map_n_map(umap);
+ isl_union_map_free(umap);
+ if (!umap)
+ r = -1;
+
+ isl_union_set_free(domain);
+
+ return r;
+}
+
+/* Add a single scheduled sink or source (depending on data->set_sink)
+ * with scheduled access relation "map", must property data->must and
+ * schedule node data->node to the list of sinks or sources.
+ */
+static int extract_sink_source(__isl_take isl_map *map, void *user)
+{
+ struct isl_compute_flow_schedule_data *data = user;
+ struct isl_scheduled_access *access;
+
+ if (data->set_sink)
+ access = data->sink + data->n_sink++;
+ else
+ access = data->source + data->n_source++;
+
+ access->access = map;
+ access->must = data->must;
+ access->node = isl_schedule_node_copy(data->node);
+
+ return 0;
+}
+
+/* isl_schedule_foreach_schedule_node callback for collecting
+ * individual scheduled source and sink accesses.
+ *
+ * We only collect accesses at the leaves of the schedule tree.
+ * We prepend the schedule dimensions at the leaf to the iteration
+ * domains of the source and sink accesses and then extract
+ * the individual accesses (per space).
+ *
+ * In particular, if the prefix schedule at the node is of the form
+ *
+ * D -> S
+ *
+ * while the access relations are of the form
+ *
+ * D -> A
+ *
+ * then the updated access relations are of the form
+ *
+ * [S -> D] -> A
+ *
+ * Note that S consists of a single space such that introducing S
+ * in the access relations does not increase the number of spaces.
+ */
+static int collect_sink_source(__isl_keep isl_schedule_node *node, void *user)
+{
+ struct isl_compute_flow_schedule_data *data = user;
+ isl_union_map *prefix;
+ isl_union_map *umap;
+ int r = 0;
+
+ if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+ return 1;
+
+ data->node = node;
+
+ prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+ prefix = isl_union_map_reverse(prefix);
+ prefix = isl_union_map_range_map(prefix);
+
+ data->set_sink = 1;
+ umap = isl_union_map_copy(data->access->sink);
+ umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+ if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+ r = -1;
+ isl_union_map_free(umap);
+
+ data->set_sink = 0;
+ data->must = 1;
+ umap = isl_union_map_copy(data->access->must_source);
+ umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+ if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+ r = -1;
+ isl_union_map_free(umap);
+
+ data->set_sink = 0;
+ data->must = 0;
+ umap = isl_union_map_copy(data->access->may_source);
+ umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+ if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+ r = -1;
+ isl_union_map_free(umap);
+
+ isl_union_map_free(prefix);
+
+ return r;
+}
+
+/* isl_access_info_compute_flow callback for determining whether
+ * the shared nesting level and the ordering within that level
+ * for two scheduled accesses for use in compute_single_flow.
+ *
+ * The tokens passed to this function refer to the leaves
+ * in the schedule tree where the accesses take place.
+ *
+ * If n is the shared number of loops, then we need to return
+ * "2 * n + 1" if "first" precedes "second" inside the innermost
+ * shared loop and "2 * n" otherwise.
+ *
+ * The innermost shared ancestor may be the leaves themselves
+ * if the accesses take place in the same leaf. Otherwise,
+ * it is either a set node or a sequence node. Only in the case
+ * of a sequence node do we consider one access to precede the other.
+ */
+static int before_node(void *first, void *second)
+{
+ isl_schedule_node *node1 = first;
+ isl_schedule_node *node2 = second;
+ isl_schedule_node *shared;
+ int depth;
+ int before = 0;
+
+ shared = isl_schedule_node_get_shared_ancestor(node1, node2);
+ if (!shared)
+ return -1;
+
+ depth = isl_schedule_node_get_schedule_depth(shared);
+ if (isl_schedule_node_get_type(shared) == isl_schedule_node_sequence) {
+ int pos1, pos2;
+
+ pos1 = isl_schedule_node_get_ancestor_child_position(node1,
+ shared);
+ pos2 = isl_schedule_node_get_ancestor_child_position(node2,
+ shared);
+ before = pos1 < pos2;
+ }
+
+ isl_schedule_node_free(shared);
+
+ return 2 * depth + before;
+}
+
+/* Add the scheduled sources from "data" that access
+ * the same data space as "sink" to "access".
+ */
+static __isl_give isl_access_info *add_matching_sources(
+ __isl_take isl_access_info *access, struct isl_scheduled_access *sink,
+ struct isl_compute_flow_schedule_data *data)
+{
+ int i;
+ isl_space *space;
+
+ space = isl_space_range(isl_map_get_space(sink->access));
+ for (i = 0; i < data->n_source; ++i) {
+ struct isl_scheduled_access *source;
+ isl_space *source_space;
+ int eq;
+
+ source = &data->source[i];
+ source_space = isl_map_get_space(source->access);
+ source_space = isl_space_range(source_space);
+ eq = isl_space_is_equal(space, source_space);
+ isl_space_free(source_space);
+
+ if (!eq)
+ continue;
+ if (eq < 0)
+ goto error;
+
+ access = isl_access_info_add_source(access,
+ isl_map_copy(source->access), source->must, source->node);
+ }
+
+ isl_space_free(space);
+ return access;
+error:
+ isl_space_free(space);
+ isl_access_info_free(access);
+ return NULL;
+}
+
+/* Given a scheduled sink access relation "sink", compute the corresponding
+ * dependences on the sources in "data" and add the computed dependences
+ * to "uf".
+ */
+static __isl_give isl_union_flow *compute_single_flow(
+ __isl_take isl_union_flow *uf, struct isl_scheduled_access *sink,
+ struct isl_compute_flow_schedule_data *data)
+{
+ int i;
+ isl_access_info *access;
+ isl_flow *flow;
+ isl_map *map;
+
+ if (!uf)
+ return NULL;
+
+ access = isl_access_info_alloc(isl_map_copy(sink->access), sink->node,
+ &before_node, data->n_source);
+ access = add_matching_sources(access, sink, data);
+
+ flow = isl_access_info_compute_flow(access);
+ if (!flow)
+ return isl_union_flow_free(uf);
+
+ map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 1));
+ uf->must_no_source = isl_union_map_union(uf->must_no_source,
+ isl_union_map_from_map(map));
+ map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 0));
+ uf->may_no_source = isl_union_map_union(uf->may_no_source,
+ isl_union_map_from_map(map));
+
+ for (i = 0; i < flow->n_source; ++i) {
+ isl_union_map *dep;
+
+ map = isl_map_factor_range(isl_map_copy(flow->dep[i].map));
+ dep = isl_union_map_from_map(map);
+ if (flow->dep[i].must)
+ uf->must_dep = isl_union_map_union(uf->must_dep, dep);
+ else
+ uf->may_dep = isl_union_map_union(uf->may_dep, dep);
+ }
+
+ isl_flow_free(flow);
+
+ return uf;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink. The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * This function is used when a schedule tree representation
+ * is available.
+ *
+ * We extract the individual scheduled source and sink access relations and
+ * then compute dependences for each scheduled sink individually.
+ */
+static __isl_give isl_union_flow *compute_flow_schedule(
+ __isl_take isl_union_access_info *access)
+{
+ struct isl_compute_flow_schedule_data data = { access };
+ int i, n;
+ isl_ctx *ctx;
+ isl_union_flow *flow;
+
+ ctx = isl_union_access_info_get_ctx(access);
+
+ data.n_sink = 0;
+ data.n_source = 0;
+ if (isl_schedule_foreach_schedule_node(access->schedule,
+ &count_sink_source, &data) < 0)
+ goto error;
+
+ n = data.n_sink + data.n_source;
+ data.sink = isl_calloc_array(ctx, struct isl_scheduled_access, n);
+ if (n && !data.sink)
+ goto error;
+ data.source = data.sink + data.n_sink;
+
+ data.n_sink = 0;
+ data.n_source = 0;
+ if (isl_schedule_foreach_schedule_node(access->schedule,
+ &collect_sink_source, &data) < 0)
+ goto error;
+
+ flow = isl_union_flow_alloc(isl_union_map_get_space(access->sink));
+
+ isl_compute_flow_schedule_data_align_params(&data);
+
+ for (i = 0; i < data.n_sink; ++i)
+ flow = compute_single_flow(flow, &data.sink[i], &data);
+
+ isl_compute_flow_schedule_data_clear(&data);
+
+ isl_union_access_info_free(access);
+ return flow;
+error:
+ isl_union_access_info_free(access);
+ isl_compute_flow_schedule_data_clear(&data);
+ return NULL;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink. The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * We check whether the schedule is available as a schedule tree
+ * or a schedule map and call the correpsonding function to perform
+ * the analysis.
+ */
+__isl_give isl_union_flow *isl_union_access_info_compute_flow(
+ __isl_take isl_union_access_info *access)
+{
+ access = isl_union_access_info_normalize(access);
+ if (!access)
+ return NULL;
+ if (access->schedule)
+ return compute_flow_schedule(access);
+ else
+ return compute_flow_union_map(access);
+}
+
/* Given a collection of "sink" and "source" accesses,
* compute for each iteration of a sink access
* and for each element accessed by that iteration,
* corresponding to those iterations that access an element
* not previously accessed.
*
- * We first prepend the schedule dimensions to the domain
- * of the accesses so that we can easily compare their relative order.
- * Then we consider each sink access individually in compute_flow.
+ * We collect the inputs in an isl_union_access_info object,
+ * call isl_union_access_info_compute_flow and extract
+ * the outputs from the result.
*/
int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
__isl_take isl_union_map *must_source,
__isl_give isl_union_map **must_no_source,
__isl_give isl_union_map **may_no_source)
{
- isl_space *dim;
- isl_union_map *range_map = NULL;
- struct isl_compute_flow_data data;
-
- sink = isl_union_map_align_params(sink,
- isl_union_map_get_space(must_source));
- sink = isl_union_map_align_params(sink,
- isl_union_map_get_space(may_source));
- sink = isl_union_map_align_params(sink,
- isl_union_map_get_space(schedule));
- dim = isl_union_map_get_space(sink);
- must_source = isl_union_map_align_params(must_source, isl_space_copy(dim));
- may_source = isl_union_map_align_params(may_source, isl_space_copy(dim));
- schedule = isl_union_map_align_params(schedule, isl_space_copy(dim));
-
- schedule = isl_union_map_reverse(schedule);
- range_map = isl_union_map_range_map(schedule);
- schedule = isl_union_map_reverse(isl_union_map_copy(range_map));
- sink = isl_union_map_apply_domain(sink, isl_union_map_copy(schedule));
- must_source = isl_union_map_apply_domain(must_source,
- isl_union_map_copy(schedule));
- may_source = isl_union_map_apply_domain(may_source, schedule);
-
- data.must_source = must_source;
- data.may_source = may_source;
- data.must_dep = must_dep ?
- isl_union_map_empty(isl_space_copy(dim)) : NULL;
- data.may_dep = may_dep ? isl_union_map_empty(isl_space_copy(dim)) : NULL;
- data.must_no_source = must_no_source ?
- isl_union_map_empty(isl_space_copy(dim)) : NULL;
- data.may_no_source = may_no_source ?
- isl_union_map_empty(isl_space_copy(dim)) : NULL;
-
- isl_space_free(dim);
+ isl_union_access_info *access;
+ isl_union_flow *flow;
- if (isl_union_map_foreach_map(sink, &compute_flow, &data) < 0)
- goto error;
+ access = isl_union_access_info_from_sink(sink);
+ access = isl_union_access_info_set_must_source(access, must_source);
+ access = isl_union_access_info_set_may_source(access, may_source);
+ access = isl_union_access_info_set_schedule_map(access, schedule);
+ flow = isl_union_access_info_compute_flow(access);
- isl_union_map_free(sink);
- isl_union_map_free(must_source);
- isl_union_map_free(may_source);
+ if (must_dep)
+ *must_dep = isl_union_flow_get_must_dependence(flow);
+ if (may_dep)
+ *may_dep = isl_union_flow_get_non_must_dependence(flow);
+ if (must_no_source)
+ *must_no_source = isl_union_flow_get_must_no_source(flow);
+ if (may_no_source)
+ *may_no_source = isl_union_flow_get_non_must_no_source(flow);
- if (must_dep) {
- data.must_dep = isl_union_map_apply_domain(data.must_dep,
- isl_union_map_copy(range_map));
- data.must_dep = isl_union_map_apply_range(data.must_dep,
- isl_union_map_copy(range_map));
- *must_dep = data.must_dep;
- }
- if (may_dep) {
- data.may_dep = isl_union_map_apply_domain(data.may_dep,
- isl_union_map_copy(range_map));
- data.may_dep = isl_union_map_apply_range(data.may_dep,
- isl_union_map_copy(range_map));
- *may_dep = data.may_dep;
- }
- if (must_no_source) {
- data.must_no_source = isl_union_map_apply_domain(
- data.must_no_source, isl_union_map_copy(range_map));
- *must_no_source = data.must_no_source;
- }
- if (may_no_source) {
- data.may_no_source = isl_union_map_apply_domain(
- data.may_no_source, isl_union_map_copy(range_map));
- *may_no_source = data.may_no_source;
- }
+ isl_union_flow_free(flow);
- isl_union_map_free(range_map);
+ if ((must_dep && !*must_dep) || (may_dep && !*may_dep) ||
+ (must_no_source && !*must_no_source) ||
+ (may_no_source && !*may_no_source))
+ goto error;
return 0;
error:
- isl_union_map_free(range_map);
- isl_union_map_free(sink);
- isl_union_map_free(must_source);
- isl_union_map_free(may_source);
- isl_union_map_free(data.must_dep);
- isl_union_map_free(data.may_dep);
- isl_union_map_free(data.must_no_source);
- isl_union_map_free(data.may_no_source);
-
if (must_dep)
- *must_dep = NULL;
+ *must_dep = isl_union_map_free(*must_dep);
if (may_dep)
- *may_dep = NULL;
+ *may_dep = isl_union_map_free(*may_dep);
if (must_no_source)
- *must_no_source = NULL;
+ *must_no_source = isl_union_map_free(*must_no_source);
if (may_no_source)
- *may_no_source = NULL;
+ *may_no_source = isl_union_map_free(*may_no_source);
return -1;
}
if (id->user != nu->user)
return 0;
- if (!id->name && !nu->name)
+ if (id->name == nu->name)
return 1;
+ if (!id->name || !nu->name)
+ return 0;
return !strcmp(id->name, nu->name);
}
int type;
int k;
isl_int *c;
- unsigned nparam;
- unsigned dim;
if (!bmap)
return NULL;
- nparam = isl_basic_map_dim(bmap, isl_dim_param);
- dim = isl_basic_map_dim(bmap, isl_dim_out);
-
tok = isl_stream_next_token(s);
if (!tok || tok->type != ISL_TOKEN_VALUE) {
isl_stream_error(s, tok, "expecting coefficient");
pos += isl_local_space_offset(ls, type);
isl_int_init(v);
- for (i = first; i < ls->div->n_row; ++i) {
+ for (i = first; i < first + n; ++i) {
if (isl_int_is_zero(ls->div->row[i][1 + pos]))
continue;
isl_seq_substitute(ls->div->row[i], pos, subs,
if (k <= 0)
return bmap;
- elim_for = isl_calloc_array(ctx, int, bmap->n_div);
size = round_up(4 * bmap->n_div / 3 - 1);
+ if (size == 0)
+ return bmap;
+ elim_for = isl_calloc_array(ctx, int, bmap->n_div);
bits = ffs(size) - 1;
index = isl_calloc_array(ctx, int, size);
- if (!index)
- return bmap;
+ if (!elim_for || !index)
+ goto out;
eq = isl_blk_alloc(ctx, 1+total);
if (isl_blk_is_error(eq))
goto out;
return bmap;
size = round_up(4 * (bmap->n_ineq+1) / 3 - 1);
+ if (size == 0)
+ return bmap;
bits = ffs(size) - 1;
ctx = isl_basic_map_get_ctx(bmap);
index = isl_calloc_array(ctx, isl_int **, size);
return NULL;
size = round_up(4 * (context->n_ineq+1) / 3 - 1);
+ if (size == 0)
+ return bset;
bits = ffs(size) - 1;
ctx = isl_basic_set_get_ctx(bset);
index = isl_calloc_array(ctx, isl_int **, size);
n_eq = bset->n_eq;
n_ineq = bset->n_ineq;
eq = isl_basic_set_copy(bset);
- eq = isl_basic_set_cow(bset);
+ eq = isl_basic_set_cow(eq);
if (isl_basic_set_free_inequality(eq, n_ineq) < 0)
eq = isl_basic_set_free(eq);
if (isl_basic_set_free_equality(bset, n_eq) < 0)
struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat)
{
- struct isl_ctx *ctx;
int i;
set = isl_set_cow(set);
if (!set)
return NULL;
- ctx = set->ctx;
for (i = 0; i < set->n; ++i) {
set->p[i] = isl_basic_set_preimage(set->p[i],
isl_mat_copy(mat));
static __isl_give isl_printer *isl_union_map_print_isl(
__isl_keep isl_union_map *umap, __isl_take isl_printer *p)
{
- struct isl_union_print_data data = { p, 1 };
+ struct isl_union_print_data data;
struct isl_print_space_data space_data = { 0 };
isl_space *dim;
}
isl_space_free(dim);
p = isl_printer_print_str(p, s_open_set[0]);
+ data.p = p;
+ data.first = 1;
isl_union_map_foreach_map(umap, &print_map_body, &data);
p = data.p;
p = isl_printer_print_str(p, s_close_set[0]);
static __isl_give isl_printer *print_union_pw_qpolynomial_isl(
__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp)
{
- struct isl_union_print_data data = { p, 1 };
+ struct isl_union_print_data data;
struct isl_print_space_data space_data = { 0 };
isl_space *dim;
}
isl_space_free(dim);
p = isl_printer_print_str(p, "{ ");
+ data.p = p;
+ data.first = 1;
isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &print_pwqp_body,
&data);
p = data.p;
__isl_take isl_printer *p,
__isl_keep isl_union_pw_qpolynomial_fold *upwf)
{
- struct isl_union_print_data data = { p, 1 };
+ struct isl_union_print_data data;
struct isl_print_space_data space_data = { 0 };
isl_space *dim;
}
isl_space_free(dim);
p = isl_printer_print_str(p, "{ ");
+ data.p = p;
+ data.first = 1;
isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(upwf,
&print_pwf_body, &data);
p = data.p;
__isl_keep isl_local_space *ls)
{
struct isl_print_space_data data = { 0 };
- unsigned total;
unsigned n_div;
if (!ls)
goto error;
- total = isl_local_space_dim(ls, isl_dim_all);
if (isl_local_space_dim(ls, isl_dim_param) > 0) {
p = print_tuple(ls->dim, p, isl_dim_param, &data);
p = isl_printer_print_str(p, " -> ");
static __isl_give isl_printer *print_union_pw_multi_aff_isl(
__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma)
{
- struct isl_union_print_data data = { p, 1 };
+ struct isl_union_print_data data;
struct isl_print_space_data space_data = { 0 };
isl_space *space;
}
isl_space_free(space);
p = isl_printer_print_str(p, s_open_set[0]);
+ data.p = p;
+ data.first = 1;
isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
&print_pw_multi_aff_body_wrap, &data);
p = data.p;
__isl_keep isl_qpolynomial *poly, int sign, int *signs)
{
struct range_data data_m;
- unsigned nvar;
unsigned nparam;
isl_space *dim;
isl_val *opt;
enum isl_fold type;
nparam = isl_basic_set_dim(bset, isl_dim_param);
- nvar = isl_basic_set_dim(bset, isl_dim_set);
bset = isl_basic_set_copy(bset);
poly = isl_qpolynomial_copy(poly);
static struct isl_vec *sample_bounded(struct isl_basic_set *bset)
{
unsigned dim;
- struct isl_ctx *ctx;
struct isl_vec *sample;
struct isl_tab *tab = NULL;
isl_factorizer *f;
if (f->n_group != 0)
return factored_sample(bset, f);
isl_factorizer_free(f);
-
- ctx = bset->ctx;
tab = isl_tab_from_basic_set(bset, 1);
if (tab && tab->empty) {
isl_tab_free(tab);
ISL_F_SET(bset, ISL_BASIC_SET_EMPTY);
- sample = isl_vec_alloc(bset->ctx, 0);
+ sample = isl_vec_alloc(isl_basic_set_get_ctx(bset), 0);
isl_basic_set_free(bset);
return sample;
}
if (!bset || !cone)
goto error;
- ctx = bset->ctx;
+ ctx = isl_basic_set_get_ctx(bset);
total = isl_basic_set_total_dim(cone);
cone_dim = total - cone->n_eq;
- M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
+ M = isl_mat_sub_alloc6(ctx, cone->eq, 0, cone->n_eq, 1, total);
M = isl_mat_left_hermite(M, 0, &U, NULL);
if (!M)
goto error;
return schedule ? &schedule->leaf : NULL;
}
+/* Are "schedule1" and "schedule2" obviously equal to each other?
+ */
+int isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1,
+ __isl_keep isl_schedule *schedule2)
+{
+ if (!schedule1 || !schedule2)
+ return -1;
+ if (schedule1 == schedule2)
+ return 1;
+ return isl_schedule_tree_plain_is_equal(schedule1->root,
+ schedule2->root);
+}
+
/* Return the (parameter) space of the schedule, i.e., the space
* of the root domain.
*/
return schedule;
}
+/* Wrapper around isl_schedule_node_reset_user for use as
+ * an isl_schedule_map_schedule_node callback.
+ */
+static __isl_give isl_schedule_node *reset_user(
+ __isl_take isl_schedule_node *node, void *user)
+{
+ return isl_schedule_node_reset_user(node);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the schedule "schedule".
+ */
+__isl_give isl_schedule *isl_schedule_reset_user(
+ __isl_take isl_schedule *schedule)
+{
+ return isl_schedule_map_schedule_node(schedule, &reset_user, NULL);
+}
+
+/* Wrapper around isl_schedule_node_align_params for use as
+ * an isl_schedule_map_schedule_node callback.
+ */
+static __isl_give isl_schedule_node *align_params(
+ __isl_take isl_schedule_node *node, void *user)
+{
+ isl_space *space = user;
+
+ return isl_schedule_node_align_params(node, isl_space_copy(space));
+}
+
+/* Align the parameters of all nodes in schedule "schedule"
+ * to those of "space".
+ */
+__isl_give isl_schedule *isl_schedule_align_params(
+ __isl_take isl_schedule *schedule, __isl_take isl_space *space)
+{
+ schedule = isl_schedule_map_schedule_node(schedule,
+ &align_params, space);
+ isl_space_free(space);
+ return schedule;
+}
+
+/* Wrapper around isl_schedule_node_pullback_union_pw_multi_aff for use as
+ * an isl_schedule_map_schedule_node callback.
+ */
+static __isl_give isl_schedule_node *pullback_upma(
+ __isl_take isl_schedule_node *node, void *user)
+{
+ isl_union_pw_multi_aff *upma = user;
+
+ return isl_schedule_node_pullback_union_pw_multi_aff(node,
+ isl_union_pw_multi_aff_copy(upma));
+}
+
+/* Compute the pullback of "schedule" by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of "schedule".
+ */
+__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_union_pw_multi_aff *upma)
+{
+ schedule = isl_schedule_map_schedule_node(schedule,
+ &pullback_upma, upma);
+ isl_union_pw_multi_aff_free(upma);
+ return schedule;
+}
+
+/* Intersect the domain of the schedule "schedule" with "domain".
+ */
+__isl_give isl_schedule *isl_schedule_intersect_domain(
+ __isl_take isl_schedule *schedule, __isl_take isl_union_set *domain)
+{
+ enum isl_schedule_node_type root_type;
+ isl_schedule_node *node;
+
+ if (!schedule || !domain)
+ goto error;
+
+ root_type = isl_schedule_tree_get_type(schedule->root);
+ if (root_type != isl_schedule_node_domain)
+ isl_die(isl_schedule_get_ctx(schedule), isl_error_internal,
+ "root node not a domain node", goto error);
+
+ node = isl_schedule_get_root(schedule);
+ isl_schedule_free(schedule);
+ node = isl_schedule_node_domain_intersect_domain(node, domain);
+ schedule = isl_schedule_node_get_schedule(node);
+ isl_schedule_node_free(node);
+
+ return schedule;
+error:
+ isl_schedule_free(schedule);
+ isl_union_set_free(domain);
+ return NULL;
+}
+
/* Return an isl_union_map representation of the schedule.
* If we still have access to the schedule tree, then we return
* an isl_union_map corresponding to the subtree schedule of the child
return p;
}
+/* Insert a band node with partial schedule "partial" between the domain
+ * root node of "schedule" and its single child.
+ * Return a pointer to the updated schedule.
+ */
+__isl_give isl_schedule *isl_schedule_insert_partial_schedule(
+ __isl_take isl_schedule *schedule,
+ __isl_take isl_multi_union_pw_aff *partial)
+{
+ isl_schedule_node *node;
+
+ node = isl_schedule_get_root(schedule);
+ isl_schedule_free(schedule);
+ if (!node)
+ goto error;
+ if (isl_schedule_node_get_type(node) != isl_schedule_node_domain)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+ "root node not a domain node", goto error);
+
+ node = isl_schedule_node_child(node, 0);
+ node = isl_schedule_node_insert_partial_schedule(node, partial);
+
+ schedule = isl_schedule_node_get_schedule(node);
+ isl_schedule_node_free(node);
+
+ return schedule;
+error:
+ isl_schedule_node_free(node);
+ isl_multi_union_pw_aff_free(partial);
+ return NULL;
+}
+
+/* Return a tree with as top-level node a filter corresponding to "filter" and
+ * as child, the (single) child of "tree".
+ * However, if this single child is of type "type", then the filter is inserted
+ * in the children of this single child instead.
+ */
+static __isl_give isl_schedule_tree *insert_filter_in_child_of_type(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter,
+ enum isl_schedule_node_type type)
+{
+ if (!isl_schedule_tree_has_children(tree)) {
+ isl_schedule_tree_free(tree);
+ return isl_schedule_tree_from_filter(filter);
+ } else {
+ tree = isl_schedule_tree_child(tree, 0);
+ }
+
+ if (isl_schedule_tree_get_type(tree) == type)
+ tree = isl_schedule_tree_children_insert_filter(tree, filter);
+ else
+ tree = isl_schedule_tree_insert_filter(tree, filter);
+
+ return tree;
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * with a top-level node (underneath the domain node) of type "type",
+ * either isl_schedule_node_sequence or isl_schedule_node_set.
+ * The domains of the two schedules are assumed to be disjoint.
+ *
+ * The new schedule has as domain the union of the domains of the two
+ * schedules. The child of the domain node is a node of type "type"
+ * with two filters corresponding to the domains of the input schedules.
+ * If one (or both) of the top-level nodes of the two schedules is itself
+ * of type "type", then the filter is pushed into the children of that
+ * node and the sequence of set is flattened.
+ */
+__isl_give isl_schedule *isl_schedule_pair(enum isl_schedule_node_type type,
+ __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+ int disjoint;
+ isl_ctx *ctx;
+ enum isl_schedule_node_type root_type;
+ isl_schedule_tree *tree1, *tree2;
+ isl_union_set *filter1, *filter2, *domain;
+
+ if (!schedule1 || !schedule2)
+ goto error;
+
+ root_type = isl_schedule_tree_get_type(schedule1->root);
+ if (root_type != isl_schedule_node_domain)
+ isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal,
+ "root node not a domain node", goto error);
+ root_type = isl_schedule_tree_get_type(schedule2->root);
+ if (root_type != isl_schedule_node_domain)
+ isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal,
+ "root node not a domain node", goto error);
+
+ ctx = isl_schedule_get_ctx(schedule1);
+ tree1 = isl_schedule_tree_copy(schedule1->root);
+ filter1 = isl_schedule_tree_domain_get_domain(tree1);
+ tree2 = isl_schedule_tree_copy(schedule2->root);
+ filter2 = isl_schedule_tree_domain_get_domain(tree2);
+
+ isl_schedule_free(schedule1);
+ isl_schedule_free(schedule2);
+
+ disjoint = isl_union_set_is_disjoint(filter1, filter2);
+ if (disjoint < 0)
+ filter1 = isl_union_set_free(filter1);
+ if (!disjoint)
+ isl_die(ctx, isl_error_invalid,
+ "schedule domains not disjoint",
+ filter1 = isl_union_set_free(filter1));
+
+ domain = isl_union_set_union(isl_union_set_copy(filter1),
+ isl_union_set_copy(filter2));
+ filter1 = isl_union_set_gist(filter1, isl_union_set_copy(domain));
+ filter2 = isl_union_set_gist(filter2, isl_union_set_copy(domain));
+
+ tree1 = insert_filter_in_child_of_type(tree1, filter1, type);
+ tree2 = insert_filter_in_child_of_type(tree2, filter2, type);
+
+ tree1 = isl_schedule_tree_from_pair(type, tree1, tree2);
+ tree1 = isl_schedule_tree_insert_domain(tree1, domain);
+
+ return isl_schedule_from_schedule_tree(ctx, tree1);
+error:
+ isl_schedule_free(schedule1);
+ isl_schedule_free(schedule2);
+ return NULL;
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * through a sequence node.
+ * The domains of the input schedules are assumed to be disjoint.
+ */
+__isl_give isl_schedule *isl_schedule_sequence(
+ __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+ return isl_schedule_pair(isl_schedule_node_sequence,
+ schedule1, schedule2);
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * through a set node.
+ * The domains of the input schedules are assumed to be disjoint.
+ */
+__isl_give isl_schedule *isl_schedule_set(
+ __isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+ return isl_schedule_pair(isl_schedule_node_set, schedule1, schedule2);
+}
+
/* Print "schedule" to "p".
*
* If "schedule" was created from a schedule tree, then we print
/*
* Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014 INRIA Rocquencourt
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege,
* Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
*/
#include <isl/schedule_node.h>
return NULL;
}
+/* Are "band1" and "band2" obviously equal?
+ */
+int isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
+ __isl_keep isl_schedule_band *band2)
+{
+ int i;
+
+ if (!band1 || !band2)
+ return -1;
+ if (band1 == band2)
+ return 1;
+
+ if (band1->n != band2->n)
+ return 0;
+ for (i = 0; i < band1->n; ++i)
+ if (band1->coincident[i] != band2->coincident[i])
+ return 0;
+ if (band1->permutable != band2->permutable)
+ return 0;
+
+ return isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa);
+}
+
/* Return the number of scheduling dimensions in the band.
*/
int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band)
return band;
}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in "band".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_reset_user(
+ __isl_take isl_schedule_band *band)
+{
+ band = isl_schedule_band_cow(band);
+ if (!band)
+ return NULL;
+
+ band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa);
+ if (!band->mupa)
+ return isl_schedule_band_free(band);
+
+ return band;
+}
+
+/* Align the parameters of "band" to those of "space".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_align_params(
+ __isl_take isl_schedule_band *band, __isl_take isl_space *space)
+{
+ band = isl_schedule_band_cow(band);
+ if (!band || !space)
+ goto error;
+
+ band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, space);
+ if (!band->mupa)
+ return isl_schedule_band_free(band);
+
+ return band;
+error:
+ isl_space_free(space);
+ isl_schedule_band_free(band);
+ return NULL;
+}
+
+/* Compute the pullback of "band" by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of "band".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_band *band,
+ __isl_take isl_union_pw_multi_aff *upma)
+{
+ band = isl_schedule_band_cow(band);
+ if (!band || !upma)
+ goto error;
+
+ band->mupa =
+ isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa,
+ upma);
+ if (!band->mupa)
+ return isl_schedule_band_free(band);
+
+ return band;
+error:
+ isl_union_pw_multi_aff_free(upma);
+ isl_schedule_band_free(band);
+ return NULL;
+}
+
+/* Compute the gist of "band" with respect to "context".
+ * In particular, compute the gist of the associated partial schedule.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_gist(
+ __isl_take isl_schedule_band *band, __isl_take isl_union_set *context)
+{
+ if (!band || !context)
+ goto error;
+ if (band->n == 0) {
+ isl_union_set_free(context);
+ return band;
+ }
+ band = isl_schedule_band_cow(band);
+ if (!band)
+ goto error;
+ band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context);
+ if (!band->mupa)
+ return isl_schedule_band_free(band);
+ return band;
+error:
+ isl_union_set_free(context);
+ isl_schedule_band_free(band);
+ return NULL;
+}
isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band);
+int isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
+ __isl_keep isl_schedule_band *band2);
+
__isl_give isl_space *isl_schedule_band_get_space(
__isl_keep isl_schedule_band *band);
__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
__isl_take isl_multi_val *sizes);
__isl_give isl_schedule_band *isl_schedule_band_drop(
__isl_take isl_schedule_band *band, int pos, int n);
+__isl_give isl_schedule_band *isl_schedule_band_gist(
+ __isl_take isl_schedule_band *band, __isl_take isl_union_set *context);
+
+__isl_give isl_schedule_band *isl_schedule_band_reset_user(
+ __isl_take isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_align_params(
+ __isl_take isl_schedule_band *band, __isl_take isl_space *space);
+__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_band *band,
+ __isl_take isl_union_pw_multi_aff *upma);
#endif
/*
- * Copyright 2013 Ecole Normale Superieure
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014 INRIA Rocquencourt
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege,
* Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
*/
#include <isl/set.h>
return NULL;
}
+/* Do "node1" and "node2" point to the same position in the same
+ * schedule?
+ */
+int isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2)
+{
+ int i, n1, n2;
+
+ if (!node1 || !node2)
+ return -1;
+ if (node1 == node2)
+ return 1;
+ if (node1->schedule != node2->schedule)
+ return 0;
+
+ n1 = isl_schedule_node_get_tree_depth(node1);
+ n2 = isl_schedule_node_get_tree_depth(node2);
+ if (n1 != n2)
+ return 0;
+ for (i = 0; i < n1; ++i)
+ if (node1->child_pos[i] != node2->child_pos[i])
+ return 0;
+
+ return 1;
+}
+
+/* Return the number of outer schedule dimensions of "node"
+ * in its schedule tree.
+ *
+ * Return -1 on error.
+ */
+int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node)
+{
+ int i, n;
+ int depth = 0;
+
+ if (!node)
+ return -1;
+
+ n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+ for (i = n - 1; i >= 0; --i) {
+ isl_schedule_tree *tree;
+
+ tree = isl_schedule_tree_list_get_schedule_tree(
+ node->ancestors, i);
+ if (!tree)
+ return -1;
+ if (tree->type == isl_schedule_node_band)
+ depth += isl_schedule_tree_band_n_member(tree);
+ isl_schedule_tree_free(tree);
+ }
+
+ return depth;
+}
+
/* Internal data structure for
* isl_schedule_node_get_prefix_schedule_union_pw_multi_aff
*
return n;
}
-/* Move the "node" pointer to the parent of the node it currently points to.
+/* Move the "node" pointer to the ancestor of the given generation
+ * of the node it currently points to, where generation 0 is the node
+ * itself and generation 1 is its parent.
*/
-__isl_give isl_schedule_node *isl_schedule_node_parent(
- __isl_take isl_schedule_node *node)
+__isl_give isl_schedule_node *isl_schedule_node_ancestor(
+ __isl_take isl_schedule_node *node, int generation)
{
int n;
isl_schedule_tree *tree;
- node = isl_schedule_node_cow(node);
if (!node)
return NULL;
- if (!isl_schedule_node_has_parent(node))
+ if (generation == 0)
+ return node;
+ n = isl_schedule_node_get_tree_depth(node);
+ if (n < 0)
+ return isl_schedule_node_free(node);
+ if (generation < 0 || generation > n)
isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
- "node has no parent",
+ "generation out of bounds",
return isl_schedule_node_free(node));
- n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
- tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n - 1);
+ node = isl_schedule_node_cow(node);
+ if (!node)
+ return NULL;
+
+ tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors,
+ n - generation);
isl_schedule_tree_free(node->tree);
node->tree = tree;
node->ancestors = isl_schedule_tree_list_drop(node->ancestors,
- n - 1, 1);
+ n - generation, generation);
if (!node->ancestors || !node->tree)
return isl_schedule_node_free(node);
return node;
}
+/* Move the "node" pointer to the parent of the node it currently points to.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_parent(
+ __isl_take isl_schedule_node *node)
+{
+ if (!node)
+ return NULL;
+ if (!isl_schedule_node_has_parent(node))
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "node has no parent",
+ return isl_schedule_node_free(node));
+ return isl_schedule_node_ancestor(node, 1);
+}
+
+/* Move the "node" pointer to the root of its schedule tree.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_root(
+ __isl_take isl_schedule_node *node)
+{
+ int n;
+
+ if (!node)
+ return NULL;
+ n = isl_schedule_node_get_tree_depth(node);
+ if (n < 0)
+ return isl_schedule_node_free(node);
+ return isl_schedule_node_ancestor(node, n);
+}
+
/* Move the "node" pointer to the child at position "pos" of the node
* it currently points to.
*/
return traverse(node, &postorder_enter, &postorder_leave, &data);
}
+/* Traverse the ancestors of "node" from the root down to and including
+ * the parent of "node", calling "fn" on each of them.
+ *
+ * If "fn" returns -1 on any of the nodes, then the traversal is aborted.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+int isl_schedule_node_foreach_ancestor_top_down(
+ __isl_keep isl_schedule_node *node,
+ int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user)
+{
+ int i, n;
+
+ if (!node)
+ return -1;
+
+ n = isl_schedule_node_get_tree_depth(node);
+ for (i = 0; i < n; ++i) {
+ isl_schedule_node *ancestor;
+ int r;
+
+ ancestor = isl_schedule_node_copy(node);
+ ancestor = isl_schedule_node_ancestor(ancestor, n - i);
+ r = fn(ancestor, user);
+ isl_schedule_node_free(ancestor);
+ if (r < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
/* Return the number of members in the given band node.
*/
unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node)
isl_schedule_node_set, filters);
}
+/* Remove "node" from its schedule tree and return a pointer
+ * to the leaf at the same position in the updated schedule tree.
+ *
+ * It is not allowed to remove the root of a schedule tree or
+ * a child of a set or sequence node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_cut(
+ __isl_take isl_schedule_node *node)
+{
+ isl_schedule_tree *leaf;
+ enum isl_schedule_node_type parent_type;
+
+ if (!node)
+ return NULL;
+ if (!isl_schedule_node_has_parent(node))
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "cannot cut root", return isl_schedule_node_free(node));
+
+ parent_type = isl_schedule_node_get_parent_type(node);
+ if (parent_type == isl_schedule_node_set ||
+ parent_type == isl_schedule_node_sequence)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "cannot cut child of set or sequence",
+ return isl_schedule_node_free(node));
+
+ leaf = isl_schedule_node_get_leaf(node);
+ return isl_schedule_node_graft_tree(node, leaf);
+}
+
+/* Remove a single node from the schedule tree, attaching the child
+ * of "node" directly to its parent.
+ * Return a pointer to this former child or to the leaf the position
+ * of the original node if there was no child.
+ * It is not allowed to remove the root of a schedule tree,
+ * a set or sequence node or a child of a set or sequence node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_delete(
+ __isl_take isl_schedule_node *node)
+{
+ int n;
+ isl_schedule_tree *tree;
+ enum isl_schedule_node_type type;
+
+ if (!node)
+ return NULL;
+
+ if (isl_schedule_node_get_tree_depth(node) == 0)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "cannot delete root node",
+ return isl_schedule_node_free(node));
+ n = isl_schedule_node_n_children(node);
+ if (n != 1)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "can only delete node with a single child",
+ return isl_schedule_node_free(node));
+ type = isl_schedule_node_get_parent_type(node);
+ if (type == isl_schedule_node_sequence || type == isl_schedule_node_set)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "cannot delete child of set or sequence",
+ return isl_schedule_node_free(node));
+
+ tree = isl_schedule_node_get_tree(node);
+ if (!tree || isl_schedule_tree_has_children(tree)) {
+ tree = isl_schedule_tree_child(tree, 0);
+ } else {
+ isl_schedule_tree_free(tree);
+ tree = isl_schedule_node_get_leaf(node);
+ }
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ return node;
+}
+
+/* Compute the gist of the given band node with respect to "context".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_gist(
+ __isl_take isl_schedule_node *node, __isl_take isl_union_set *context)
+{
+ isl_schedule_tree *tree;
+
+ tree = isl_schedule_node_get_tree(node);
+ tree = isl_schedule_tree_band_gist(tree, context);
+ return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Internal data structure for isl_schedule_node_gist.
+ * "filters" contains an element for each outer filter node
+ * with respect to the current position, each representing
+ * the intersection of the previous element and the filter on the filter node.
+ * The first element in the original context passed to isl_schedule_node_gist.
+ */
+struct isl_node_gist_data {
+ isl_union_set_list *filters;
+};
+
+/* Can we finish gisting at this node?
+ * That is, is the filter on the current filter node a subset of
+ * the original context passed to isl_schedule_node_gist?
+ */
+static int gist_done(__isl_keep isl_schedule_node *node,
+ struct isl_node_gist_data *data)
+{
+ isl_union_set *filter, *outer;
+ int subset;
+
+ filter = isl_schedule_node_filter_get_filter(node);
+ outer = isl_union_set_list_get_union_set(data->filters, 0);
+ subset = isl_union_set_is_subset(filter, outer);
+ isl_union_set_free(outer);
+ isl_union_set_free(filter);
+
+ return subset;
+}
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * by isl_schedule_node_gist.
+ *
+ * The "filters" list is extended by one element each time
+ * we come across a filter node by the result of intersecting
+ * the last element in the list with the filter on the filter node.
+ *
+ * If the filter on the current filter node is a subset of
+ * the original context passed to isl_schedule_node_gist,
+ * then there is no need to go into its subtree since it cannot
+ * be further simplified by the context. The "filters" list is
+ * still extended for consistency, but the actual value of the
+ * added element is immaterial since it will not be used.
+ *
+ * Otherwise, the filter on the current filter node is replaced by
+ * the gist of the original filter with respect to the intersection
+ * of the original context with the intermediate filters.
+ *
+ * If the new element in the "filters" list is empty, then no elements
+ * can reach the descendants of the current filter node. The subtree
+ * underneath the filter node is therefore removed.
+ */
+static __isl_give isl_schedule_node *gist_enter(
+ __isl_take isl_schedule_node *node, void *user)
+{
+ struct isl_node_gist_data *data = user;
+
+ do {
+ isl_union_set *filter, *inner;
+ int done, empty;
+ int n;
+
+ switch (isl_schedule_node_get_type(node)) {
+ case isl_schedule_node_error:
+ return isl_schedule_node_free(node);
+ case isl_schedule_node_band:
+ case isl_schedule_node_domain:
+ case isl_schedule_node_leaf:
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ continue;
+ case isl_schedule_node_filter:
+ break;
+ }
+ done = gist_done(node, data);
+ filter = isl_schedule_node_filter_get_filter(node);
+ if (done < 0 || done) {
+ data->filters = isl_union_set_list_add(data->filters,
+ filter);
+ if (done < 0)
+ return isl_schedule_node_free(node);
+ return node;
+ }
+ n = isl_union_set_list_n_union_set(data->filters);
+ inner = isl_union_set_list_get_union_set(data->filters, n - 1);
+ filter = isl_union_set_gist(filter, isl_union_set_copy(inner));
+ node = isl_schedule_node_filter_set_filter(node,
+ isl_union_set_copy(filter));
+ filter = isl_union_set_intersect(filter, inner);
+ empty = isl_union_set_is_empty(filter);
+ data->filters = isl_union_set_list_add(data->filters, filter);
+ if (empty < 0)
+ return isl_schedule_node_free(node);
+ if (!empty)
+ continue;
+ node = isl_schedule_node_child(node, 0);
+ node = isl_schedule_node_cut(node);
+ node = isl_schedule_node_parent(node);
+ return node;
+ } while (isl_schedule_node_has_children(node) &&
+ (node = isl_schedule_node_first_child(node)) != NULL);
+
+ return node;
+}
+
+/* Callback for "traverse" to leave a node for isl_schedule_node_gist.
+ *
+ * In particular, if the current node is a filter node, then we remove
+ * the element on the "filters" list that was added when we entered
+ * the node. There is no need to compute any gist here, since we
+ * already did that when we entered the node.
+ *
+ * If the current node is a band node, then we compute the gist of
+ * the band node with respect to the intersection of the original context
+ * and the intermediate filters.
+ *
+ * If the current node is a sequence or set node, then some of
+ * the filter children may have become empty and so they are removed.
+ * If only one child is left, then the set or sequence node along with
+ * the single remaining child filter is removed. The filter can be
+ * removed because the filters on a sequence or set node are supposed
+ * to partition the incoming domain instances.
+ * In principle, it should then be impossible for there to be zero
+ * remaining children, but should this happen, we replace the entire
+ * subtree with an empty filter.
+ */
+static __isl_give isl_schedule_node *gist_leave(
+ __isl_take isl_schedule_node *node, void *user)
+{
+ struct isl_node_gist_data *data = user;
+ isl_schedule_tree *tree;
+ int i, n;
+ isl_union_set *filter;
+
+ switch (isl_schedule_node_get_type(node)) {
+ case isl_schedule_node_error:
+ return isl_schedule_node_free(node);
+ case isl_schedule_node_filter:
+ n = isl_union_set_list_n_union_set(data->filters);
+ data->filters = isl_union_set_list_drop(data->filters,
+ n - 1, 1);
+ break;
+ case isl_schedule_node_band:
+ n = isl_union_set_list_n_union_set(data->filters);
+ filter = isl_union_set_list_get_union_set(data->filters, n - 1);
+ node = isl_schedule_node_band_gist(node, filter);
+ break;
+ case isl_schedule_node_set:
+ case isl_schedule_node_sequence:
+ tree = isl_schedule_node_get_tree(node);
+ n = isl_schedule_tree_n_children(tree);
+ for (i = n - 1; i >= 0; --i) {
+ isl_schedule_tree *child;
+ isl_union_set *filter;
+ int empty;
+
+ child = isl_schedule_tree_get_child(tree, i);
+ filter = isl_schedule_tree_filter_get_filter(child);
+ empty = isl_union_set_is_empty(filter);
+ isl_union_set_free(filter);
+ isl_schedule_tree_free(child);
+ if (empty < 0)
+ tree = isl_schedule_tree_free(tree);
+ else if (empty)
+ tree = isl_schedule_tree_drop_child(tree, i);
+ }
+ n = isl_schedule_tree_n_children(tree);
+ node = isl_schedule_node_graft_tree(node, tree);
+ if (n == 1) {
+ node = isl_schedule_node_delete(node);
+ node = isl_schedule_node_delete(node);
+ } else if (n == 0) {
+ isl_space *space;
+
+ filter =
+ isl_union_set_list_get_union_set(data->filters, 0);
+ space = isl_union_set_get_space(filter);
+ isl_union_set_free(filter);
+ filter = isl_union_set_empty(space);
+ node = isl_schedule_node_cut(node);
+ node = isl_schedule_node_insert_filter(node, filter);
+ }
+ break;
+ case isl_schedule_node_domain:
+ case isl_schedule_node_leaf:
+ break;
+ }
+
+ return node;
+}
+
+/* Compute the gist of the subtree at "node" with respect to
+ * the reaching domain elements in "context".
+ * In particular, compute the gist of all band and filter nodes
+ * in the subtree with respect to "context". Children of set or sequence
+ * nodes that end up with an empty filter are removed completely.
+ *
+ * We keep track of the intersection of "context" with all outer filters
+ * of the current node within the subtree in the final element of "filters".
+ * Initially, this list contains the single element "context" and it is
+ * extended or shortened each time we enter or leave a filter node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_gist(
+ __isl_take isl_schedule_node *node, __isl_take isl_union_set *context)
+{
+ struct isl_node_gist_data data;
+
+ data.filters = isl_union_set_list_from_union_set(context);
+ node = traverse(node, &gist_enter, &gist_leave, &data);
+ isl_union_set_list_free(data.filters);
+ return node;
+}
+
+/* Intersect the domain of domain node "node" with "domain".
+ *
+ * If the domain of "node" is already a subset of "domain",
+ * then nothing needs to be changed.
+ *
+ * Otherwise, we replace the domain of the domain node by the intersection
+ * and simplify the subtree rooted at "node" with respect to this intersection.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain(
+ __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain)
+{
+ isl_schedule_tree *tree;
+ isl_union_set *uset;
+ int is_subset;
+
+ if (!node || !domain)
+ goto error;
+
+ uset = isl_schedule_tree_domain_get_domain(node->tree);
+ is_subset = isl_union_set_is_subset(uset, domain);
+ isl_union_set_free(uset);
+ if (is_subset < 0)
+ goto error;
+ if (is_subset) {
+ isl_union_set_free(domain);
+ return node;
+ }
+
+ tree = isl_schedule_tree_copy(node->tree);
+ uset = isl_schedule_tree_domain_get_domain(tree);
+ uset = isl_union_set_intersect(uset, domain);
+ tree = isl_schedule_tree_domain_set_domain(tree,
+ isl_union_set_copy(uset));
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ node = isl_schedule_node_child(node, 0);
+ node = isl_schedule_node_gist(node, uset);
+ node = isl_schedule_node_parent(node);
+
+ return node;
+error:
+ isl_schedule_node_free(node);
+ isl_union_set_free(domain);
+ return NULL;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the schedule node "node".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_reset_user(
+ __isl_take isl_schedule_node *node)
+{
+ isl_schedule_tree *tree;
+
+ tree = isl_schedule_node_get_tree(node);
+ tree = isl_schedule_tree_reset_user(tree);
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ return node;
+}
+
+/* Align the parameters of the schedule node "node" to those of "space".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_align_params(
+ __isl_take isl_schedule_node *node, __isl_take isl_space *space)
+{
+ isl_schedule_tree *tree;
+
+ tree = isl_schedule_node_get_tree(node);
+ tree = isl_schedule_tree_align_params(tree, space);
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ return node;
+}
+
+/* Compute the pullback of schedule node "node"
+ * by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains
+ * of schedule node "node".
+ *
+ * Note that this is only a helper function for
+ * isl_schedule_pullback_union_pw_multi_aff. In order to maintain consistency,
+ * this function should not be called on a single node without also
+ * calling it on all the other nodes.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_node *node,
+ __isl_take isl_union_pw_multi_aff *upma)
+{
+ isl_schedule_tree *tree;
+
+ tree = isl_schedule_node_get_tree(node);
+ tree = isl_schedule_tree_pullback_union_pw_multi_aff(tree, upma);
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ return node;
+}
+
+/* Return the position of the subtree containing "node" among the children
+ * of "ancestor". "node" is assumed to be a descendant of "ancestor".
+ * In particular, both nodes should point to the same schedule tree.
+ *
+ * Return -1 on error.
+ */
+int isl_schedule_node_get_ancestor_child_position(
+ __isl_keep isl_schedule_node *node,
+ __isl_keep isl_schedule_node *ancestor)
+{
+ int n1, n2;
+ isl_schedule_tree *tree;
+
+ if (!node || !ancestor)
+ return -1;
+
+ if (node->schedule != ancestor->schedule)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "not a descendant", return -1);
+
+ n1 = isl_schedule_node_get_tree_depth(ancestor);
+ n2 = isl_schedule_node_get_tree_depth(node);
+
+ if (n1 >= n2)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "not a descendant", return -1);
+ tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n1);
+ isl_schedule_tree_free(tree);
+ if (tree != ancestor->tree)
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+ "not a descendant", return -1);
+
+ return node->child_pos[n1];
+}
+
+/* Given two nodes that point to the same schedule tree, return their
+ * closest shared ancestor.
+ *
+ * Since the two nodes point to the same schedule, they share at least
+ * one ancestor, the root of the schedule. We move down from the root
+ * to the first ancestor where the respective children have a different
+ * child position. This is the requested ancestor.
+ * If there is no ancestor where the children have a different position,
+ * then one node is an ancestor of the other and then this node is
+ * the requested ancestor.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor(
+ __isl_keep isl_schedule_node *node1,
+ __isl_keep isl_schedule_node *node2)
+{
+ int i, n1, n2;
+
+ if (!node1 || !node2)
+ return NULL;
+ if (node1->schedule != node2->schedule)
+ isl_die(isl_schedule_node_get_ctx(node1), isl_error_invalid,
+ "not part of same schedule", return NULL);
+ n1 = isl_schedule_node_get_tree_depth(node1);
+ n2 = isl_schedule_node_get_tree_depth(node2);
+ if (n2 < n1)
+ return isl_schedule_node_get_shared_ancestor(node2, node1);
+ if (n1 == 0)
+ return isl_schedule_node_copy(node1);
+ if (isl_schedule_node_is_equal(node1, node2))
+ return isl_schedule_node_copy(node1);
+
+ for (i = 0; i < n1; ++i)
+ if (node1->child_pos[i] != node2->child_pos[i])
+ break;
+
+ node1 = isl_schedule_node_copy(node1);
+ return isl_schedule_node_ancestor(node1, n1 - i);
+}
+
/* Print "node" to "p".
*/
__isl_give isl_printer *isl_printer_print_schedule_node(
__isl_give isl_schedule_tree *isl_schedule_node_get_tree(
__isl_keep isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_node *node,
+ __isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain(
+ __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain);
+
#endif
/*
- * Copyright 2013 Ecole Normale Superieure
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014 INRIA Rocquencourt
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege,
* Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
*/
#include <isl/map.h>
return NULL;
}
+/* Construct a tree with a root node of type "type" and as children
+ * "tree1" and "tree2".
+ * If the root of one (or both) of the input trees is itself of type "type",
+ * then the tree is replaced by its children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
+ enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
+ __isl_take isl_schedule_tree *tree2)
+{
+ isl_ctx *ctx;
+ isl_schedule_tree_list *list;
+
+ if (!tree1 || !tree2)
+ goto error;
+
+ ctx = isl_schedule_tree_get_ctx(tree1);
+ if (isl_schedule_tree_get_type(tree1) == type) {
+ list = isl_schedule_tree_list_copy(tree1->children);
+ isl_schedule_tree_free(tree1);
+ } else {
+ list = isl_schedule_tree_list_alloc(ctx, 2);
+ list = isl_schedule_tree_list_add(list, tree1);
+ }
+ if (isl_schedule_tree_get_type(tree2) == type) {
+ isl_schedule_tree_list *children;
+
+ children = isl_schedule_tree_list_copy(tree2->children);
+ list = isl_schedule_tree_list_concat(list, children);
+ isl_schedule_tree_free(tree2);
+ } else {
+ list = isl_schedule_tree_list_add(list, tree2);
+ }
+
+ return isl_schedule_tree_from_children(type, list);
+error:
+ isl_schedule_tree_free(tree1);
+ isl_schedule_tree_free(tree2);
+ return NULL;
+}
+
/* Return the isl_ctx to which "tree" belongs.
*/
isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
return tree ? tree->type : isl_schedule_node_error;
}
+/* Are "tree1" and "tree2" obviously equal to each other?
+ */
+int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
+ __isl_keep isl_schedule_tree *tree2)
+{
+ int equal;
+ int i, n;
+
+ if (!tree1 || !tree2)
+ return -1;
+ if (tree1 == tree2)
+ return 1;
+ if (tree1->type != tree2->type)
+ return 0;
+
+ switch (tree1->type) {
+ case isl_schedule_node_band:
+ equal = isl_schedule_band_plain_is_equal(tree1->band,
+ tree2->band);
+ break;
+ case isl_schedule_node_domain:
+ equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
+ break;
+ case isl_schedule_node_filter:
+ equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
+ break;
+ case isl_schedule_node_leaf:
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ equal = 1;
+ break;
+ case isl_schedule_node_error:
+ equal = -1;
+ break;
+ }
+
+ if (equal < 0 || !equal)
+ return equal;
+
+ n = isl_schedule_tree_n_children(tree1);
+ if (n != isl_schedule_tree_n_children(tree2))
+ return 0;
+ for (i = 0; i < n; ++i) {
+ isl_schedule_tree *child1, *child2;
+
+ child1 = isl_schedule_tree_get_child(tree1, i);
+ child2 = isl_schedule_tree_get_child(tree2, i);
+ equal = isl_schedule_tree_plain_is_equal(child1, child2);
+ isl_schedule_tree_free(child1);
+ isl_schedule_tree_free(child2);
+
+ if (equal < 0 || !equal)
+ return equal;
+ }
+
+ return 1;
+}
+
/* Does "tree" have any children, other than an implicit leaf.
*/
int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
return tree;
}
+/* Remove the child at position "pos" from the children of "tree".
+ * If there was only one child to begin with, then remove all children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
+ __isl_take isl_schedule_tree *tree, int pos)
+{
+ int n;
+
+ tree = isl_schedule_tree_cow(tree);
+ if (!tree)
+ return NULL;
+
+ if (!isl_schedule_tree_has_children(tree))
+ isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+ "tree does not have any explicit children",
+ return isl_schedule_tree_free(tree));
+ n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+ if (pos < 0 || pos >= n)
+ isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+ "position out of bounds",
+ return isl_schedule_tree_free(tree));
+ if (n == 1)
+ return isl_schedule_tree_reset_children(tree);
+
+ tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
+ if (!tree->children)
+ return isl_schedule_tree_free(tree);
+
+ return tree;
+}
+
/* Replace the child at position "pos" of "tree" by "child".
*
* If the new child is a leaf, then it is not explicitly
return isl_schedule_tree_replace_child(res, 0, tree);
}
+/* Insert a filter node with filter set "filter"
+ * in each of the children of "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
+{
+ int i, n;
+
+ if (!tree || !filter)
+ goto error;
+
+ n = isl_schedule_tree_n_children(tree);
+ for (i = 0; i < n; ++i) {
+ isl_schedule_tree *child;
+
+ child = isl_schedule_tree_get_child(tree, i);
+ child = isl_schedule_tree_insert_filter(child,
+ isl_union_set_copy(filter));
+ tree = isl_schedule_tree_replace_child(tree, i, child);
+ }
+
+ isl_union_set_free(filter);
+ return tree;
+error:
+ isl_union_set_free(filter);
+ isl_schedule_tree_free(tree);
+ return NULL;
+}
+
/* Return the number of members in the band tree root.
*/
unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
return NULL;
}
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the root of "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
+ __isl_take isl_schedule_tree *tree)
+{
+ if (isl_schedule_tree_is_leaf(tree))
+ return tree;
+
+ tree = isl_schedule_tree_cow(tree);
+ if (!tree)
+ return NULL;
+
+ switch (tree->type) {
+ case isl_schedule_node_error:
+ return isl_schedule_tree_free(tree);
+ case isl_schedule_node_band:
+ tree->band = isl_schedule_band_reset_user(tree->band);
+ if (!tree->band)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_domain:
+ tree->domain = isl_union_set_reset_user(tree->domain);
+ if (!tree->domain)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_filter:
+ tree->filter = isl_union_set_reset_user(tree->filter);
+ if (!tree->filter)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_leaf:
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ break;
+ }
+
+ return tree;
+}
+
+/* Align the parameters of the root of "tree" to those of "space".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
+{
+ if (!space)
+ goto error;
+
+ if (isl_schedule_tree_is_leaf(tree)) {
+ isl_space_free(space);
+ return tree;
+ }
+
+ tree = isl_schedule_tree_cow(tree);
+ if (!tree)
+ goto error;
+
+ switch (tree->type) {
+ case isl_schedule_node_error:
+ goto error;
+ case isl_schedule_node_band:
+ tree->band = isl_schedule_band_align_params(tree->band, space);
+ if (!tree->band)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_domain:
+ tree->domain = isl_union_set_align_params(tree->domain, space);
+ if (!tree->domain)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_filter:
+ tree->filter = isl_union_set_align_params(tree->filter, space);
+ if (!tree->filter)
+ return isl_schedule_tree_free(tree);
+ break;
+ case isl_schedule_node_leaf:
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ isl_space_free(space);
+ break;
+ }
+
+ return tree;
+error:
+ isl_space_free(space);
+ isl_schedule_tree_free(tree);
+ return NULL;
+}
+
+/* Does "tree" involve the iteration domain?
+ * That is, does it need to be modified
+ * by isl_schedule_tree_pullback_union_pw_multi_aff?
+ */
+static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
+{
+ if (!tree)
+ return -1;
+
+ switch (tree->type) {
+ case isl_schedule_node_error:
+ return -1;
+ case isl_schedule_node_band:
+ case isl_schedule_node_domain:
+ case isl_schedule_node_filter:
+ return 1;
+ case isl_schedule_node_leaf:
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ return 0;
+ }
+}
+
+/* Compute the pullback of the root node of "tree" by the function
+ * represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of
+ * the root node of "tree".
+ *
+ * We first check if the root node involves any iteration domains.
+ * If so, we handle the specific cases.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_tree *tree,
+ __isl_take isl_union_pw_multi_aff *upma)
+{
+ int involves;
+
+ if (!tree || !upma)
+ goto error;
+
+ involves = involves_iteration_domain(tree);
+ if (involves < 0)
+ goto error;
+ if (!involves) {
+ isl_union_pw_multi_aff_free(upma);
+ return tree;
+ }
+
+ tree = isl_schedule_tree_cow(tree);
+ if (!tree)
+ goto error;
+
+ if (tree->type == isl_schedule_node_band) {
+ tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
+ tree->band, upma);
+ if (!tree->band)
+ return isl_schedule_tree_free(tree);
+ } else if (tree->type == isl_schedule_node_domain) {
+ tree->domain =
+ isl_union_set_preimage_union_pw_multi_aff(tree->domain,
+ upma);
+ if (!tree->domain)
+ return isl_schedule_tree_free(tree);
+ } else if (tree->type == isl_schedule_node_filter) {
+ tree->filter =
+ isl_union_set_preimage_union_pw_multi_aff(tree->filter,
+ upma);
+ if (!tree->filter)
+ return isl_schedule_tree_free(tree);
+ }
+
+ return tree;
+error:
+ isl_union_pw_multi_aff_free(upma);
+ isl_schedule_tree_free(tree);
+ return NULL;
+}
+
+/* Compute the gist of the band tree root with respect to "context".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
+{
+ if (!tree)
+ return NULL;
+ if (tree->type != isl_schedule_node_band)
+ isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+ "not a band node", goto error);
+ tree = isl_schedule_tree_cow(tree);
+ if (!tree)
+ goto error;
+
+ tree->band = isl_schedule_band_gist(tree->band, context);
+ if (!tree->band)
+ return isl_schedule_tree_free(tree);
+ return tree;
+error:
+ isl_union_set_free(context);
+ isl_schedule_tree_free(tree);
+ return NULL;
+}
+
/* Are any members in "band" marked coincident?
*/
static int any_coincident(__isl_keep isl_schedule_band *band)
__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx);
int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree);
+int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
+ __isl_keep isl_schedule_tree *tree2);
+
__isl_give isl_schedule_tree *isl_schedule_tree_copy(
__isl_keep isl_schedule_tree *tree);
__isl_null isl_schedule_tree *isl_schedule_tree_free(
__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
enum isl_schedule_node_type type,
__isl_take isl_schedule_tree_list *list);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
+ enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
+ __isl_take isl_schedule_tree *tree2);
__isl_give isl_space *isl_schedule_tree_band_get_space(
__isl_keep isl_schedule_tree *tree);
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain);
__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
__isl_take isl_schedule_tree *tree1,
__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes);
__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
__isl_take isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context);
__isl_give isl_schedule_tree *isl_schedule_tree_child(
__isl_take isl_schedule_tree *tree, int pos);
__isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
__isl_take isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
+ __isl_take isl_schedule_tree *tree, int pos);
__isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
__isl_take isl_schedule_tree *tree, int pos,
__isl_take isl_schedule_tree *new_child);
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
+ __isl_take isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_space *space);
+__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
+ __isl_take isl_schedule_tree *tree,
+ __isl_take isl_union_pw_multi_aff *upma);
+
__isl_give isl_printer *isl_printer_print_schedule_tree(
__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree);
__isl_give isl_printer *isl_printer_print_schedule_tree_mark(
isl_local_space *ls;
isl_aff *aff;
isl_multi_aff *ma;
- int nrow, ncol;
+ int nrow;
nrow = isl_mat_rows(node->sched);
- ncol = isl_mat_cols(node->sched) - 1;
if (node->compressed)
space = isl_multi_aff_get_domain_space(node->decompress);
else
nested = space->nested[0];
domain = isl_space_copy(space);
- domain = isl_space_drop_dims(space, isl_dim_in,
+ domain = isl_space_drop_dims(domain, isl_dim_in,
nested->n_in, nested->n_out);
if (!domain)
return isl_space_free(space);
nested = space->nested[0];
range = isl_space_copy(space);
- range = isl_space_drop_dims(space, isl_dim_in, 0, nested->n_in);
+ range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in);
if (!range)
return isl_space_free(space);
if (nested->tuple_id[1]) {
nested = space->nested[1];
domain = isl_space_copy(space);
- domain = isl_space_drop_dims(space, isl_dim_out,
+ domain = isl_space_drop_dims(domain, isl_dim_out,
nested->n_in, nested->n_out);
if (!domain)
return isl_space_free(space);
nested = space->nested[1];
range = isl_space_copy(space);
- range = isl_space_drop_dims(space, isl_dim_out, 0, nested->n_in);
+ range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in);
if (!range)
return isl_space_free(space);
if (nested->tuple_id[1]) {
struct isl_tab *tab)
{
struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
- struct isl_ctx *ctx;
unsigned n_ineq;
- ctx = cgbr->tab->mat->ctx;
-
if (!cgbr->cone) {
struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab);
cgbr->cone = isl_tab_from_recession_cone(bset, 0);
sol_inc_level(sol);
find_in_pos(sol, tab, ineq->el);
tab->row_sign[split] = isl_tab_row_neg;
- row = split;
isl_seq_neg(ineq->el, ineq->el, ineq->size);
isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
if (!sol->error)
int *first, int *second)
{
int i;
- isl_ctx *ctx = isl_basic_map_get_ctx(bmap);
+ isl_ctx *ctx;
struct isl_hash_table *table = NULL;
struct isl_hash_table_entry *entry;
struct isl_constraint_equal_info info;
{
int i, k;
isl_basic_set *bset = NULL;
- isl_ctx *ctx;
isl_set *set = NULL;
if (!dim || !var)
goto error;
- ctx = isl_space_get_ctx(dim);
set = isl_set_alloc_space(isl_space_copy(dim),
var->n_row, ISL_SET_DISJOINT);
int i;
isl_aff *aff = NULL;
isl_basic_set *bset = NULL;
- isl_ctx *ctx;
isl_pw_aff *paff = NULL;
isl_space *pw_space;
isl_local_space *ls = NULL;
if (!space || !var)
goto error;
- ctx = isl_space_get_ctx(space);
ls = isl_local_space_from_space(isl_space_copy(space));
pw_space = isl_space_copy(space);
pw_space = isl_space_from_domain(pw_space);
{ "{ B[i] -> C[([i/2])] }", "{ B[5] }", "{ C[2] }" },
{ "[n] -> { B[i,j] -> C[([i/2]) + 2j] }",
"[n] -> { B[n,[n/3]] }", "[n] -> { C[([n/2]) + 2*[n/3]] }", },
+ { "{ [i, j] -> [floor((i)/4) + floor((2*i+j)/5)] }",
+ "{ [i, j] -> [floor((i)/3), j] }",
+ "{ [i, j] -> [(floor((i)/12) + floor((j + 2*floor((i)/3))/5))] }" },
};
static int test_pullback(isl_ctx *ctx)
return 0;
}
-/* Check that negation is printed correctly.
+/* Check that negation is printed correctly and that equal expressions
+ * are correctly identified.
*/
static int test_ast(isl_ctx *ctx)
{
isl_ast_expr *expr, *expr1, *expr2, *expr3;
char *str;
- int ok;
+ int ok, equal;
expr1 = isl_ast_expr_from_id(isl_id_alloc(ctx, "A", NULL));
expr2 = isl_ast_expr_from_id(isl_id_alloc(ctx, "B", NULL));
expr = isl_ast_expr_add(expr1, expr2);
+ expr2 = isl_ast_expr_copy(expr);
expr = isl_ast_expr_neg(expr);
+ expr2 = isl_ast_expr_neg(expr2);
+ equal = isl_ast_expr_is_equal(expr, expr2);
str = isl_ast_expr_to_str(expr);
ok = str ? !strcmp(str, "-(A + B)") : -1;
free(str);
isl_ast_expr_free(expr);
+ isl_ast_expr_free(expr2);
- if (ok < 0)
+ if (ok < 0 || equal < 0)
return -1;
+ if (!equal)
+ isl_die(ctx, isl_error_unknown,
+ "equal expressions not considered equal", return -1);
if (!ok)
isl_die(ctx, isl_error_unknown,
"isl_ast_expr printed incorrectly", return -1);
{
struct isl_map *app = NULL;
isl_space *dim = NULL;
- unsigned d;
if (!map)
return NULL;
dim = isl_map_get_space(map);
- d = isl_space_dim(dim, isl_dim_in);
dim = isl_space_add_dims(dim, isl_dim_in, 1);
dim = isl_space_add_dims(dim, isl_dim_out, 1);
__isl_keep isl_basic_set *bset, struct isl_tab *tab)
{
unsigned nvar;
- unsigned nparam;
struct isl_vertex_list *v = NULL;
if (isl_tab_detect_implicit_equalities(tab) < 0)
return -1;
nvar = isl_basic_set_dim(bset, isl_dim_set);
- nparam = isl_basic_set_dim(bset, isl_dim_param);
v = isl_calloc_type(tab->mat->ctx, struct isl_vertex_list);
if (!v)
static __isl_give isl_vertices *vertices_empty(__isl_keep isl_basic_set *bset)
{
isl_vertices *vertices;
- unsigned nparam;
if (!bset)
return NULL;
- nparam = isl_basic_set_dim(bset, isl_dim_param);
-
vertices = isl_calloc_type(bset->ctx, isl_vertices);
if (!vertices)
return NULL;
static __isl_give isl_vertices *vertices_0D(__isl_keep isl_basic_set *bset)
{
isl_vertices *vertices;
- unsigned nparam;
if (!bset)
return NULL;
- nparam = isl_basic_set_dim(bset, isl_dim_param);
-
vertices = isl_calloc_type(bset->ctx, isl_vertices);
if (!vertices)
return NULL;
}
; VALUE: RAW dependences:
-; VALUE: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 >= 0 and i0 <= 35 and i1 >= 0 and i1 <= 35 and i2 >= 0 and i2 <= 34 }
+; VALUE: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 >= 0 and i0 <= 35 and i1 >= 0 and i1 <= 35 and i2 >= 0 and i2 <= 34 }
; VALUE: WAR dependences:
-; VALUE: { }
+; VALUE: { }
; VALUE: WAW dependences:
-; VALUE: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 >= 0 and i0 <= 35 and i1 >= 0 and i1 <= 35 and i2 >= 0 and i2 <= 34 }
+; VALUE: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 <= 34 and i2 >= 0 }
+
; MEMORY: RAW dependences:
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
;
; CHECK: RAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[i0] : i0 <= 1023 and i0 >= 0 and i1 <= 1023 and i1 >= 0
-; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 >= 0 and i0 <= 1022
+; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 <= 1022 and i0 >= 0
; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
; These are the important RAW dependences, as they need to originate/end in only one iteration:
; CHECK-DAG: Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
; CHECK: { }
; CHECK: WAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[i0] : i0 <= 1023 and i0 >= 0 and i1 <= 1023 and i1 >= 0
-; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 >= 0 and i0 <= 1022
+; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 <= 1022 and i0 >= 0
; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
; These are the important WAW dependences, as they need to originate/end in only one iteration:
; CHECK-DAG: Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
;
; CHECK: RAW dependences:
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : i0 <= 97 and i0 >= 0 and o1 <= 99 and o1 >= 0
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
; CHECK: WAR dependences:
; CHECK: { }
; CHECK: WAW dependences:
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : i0 <= 97 and i0 >= 0 and o1 <= 99 and o1 >= 0
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
; CHECK: Reduction dependences:
; CHECK: { Stmt_S2[i0, i1] -> Stmt_S2[i0, 1 + i1] : i0 <= 98 and i0 >= 0 and i1 <= 98 and i1 >= 0 }
;
; CHECK: RAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[o0] : o0 <= 1 and i1 <= 1 - i0 and o0 <= 1 + i0 - i1 and o0 >= 1 - i1
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : i0 <= 1 and i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 >= 0 and i0 <= 96
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 <= 96 and i0 >= 0
; CHECK: WAR dependences:
; CHECK: { }
; CHECK: WAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[o0] : o0 <= 1 and i1 <= 1 - i0 and o0 <= 1 + i0 - i1 and o0 >= 1 - i1
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : i0 <= 1 and i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 >= 0 and i0 <= 96
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 <= 96 and i0 >= 0
; CHECK: Reduction dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : i0 <= 97 and i0 >= 0 and i1 <= 98 - i0 and i1 >= 0 and i1 >= 2 - i0
; CHECK-DAG: Stmt_S2[0, 0] -> Stmt_S2[1, 0]
;
; CHECK: RAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= 98
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 >= 0 and i0 <= 98
-; CHECK-DAG: Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG: Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
; CHECK: WAR dependences:
; CHECK-DAG: { }
; CHECK: WAW dependences:
; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= 98
-; CHECK-DAG: Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 >= 0 and i0 <= 98
-; CHECK-DAG: Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG: Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
; CHECK-DAG: Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
; CHECK: Reduction dependences:
; CHECK-DAG: { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : (i0 >= 0 and i1 >= 2 + i0 and i1 <= 99) or (i0 <= 97 and i1 >= 0 and i1 <= -1 + i0) }
; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
;
; CHECK: RAW dependences:
-; CHECK-DAG: Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 >= 0 and i0 <= 97
-; CHECK-DAG: Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 <= 97 and i0 >= 0
+; CHECK-DAG: Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 <= 98 and i0 >= 0
; CHECK: WAR dependences:
; CHECK-DAG: { }
; CHECK: WAW dependences:
-; CHECK-DAG: Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 >= 0 and i0 <= 97
-; CHECK-DAG: Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 <= 97 and i0 >= 0
+; CHECK-DAG: Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 <= 98 and i0 >= 0
; CHECK: Reduction dependences:
; CHECK-DAG: { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : i0 <= 97 and i0 >= 0 and i1 <= 99 and i1 >= 1 }
;
; CHECK: }
; CHECK: Wrapped Dependences:
; CHECK: RAW dependences:
-; CHECK: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 >= 0 and i0 <= 99 }
+; CHECK: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
; CHECK: WAR dependences:
; CHECK: { }
; CHECK: WAW dependences:
-; CHECK: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 >= 0 and i0 <= 99 }
+; CHECK: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
; CHECK: Reduction dependences:
; CHECK: n/a
; CHECK: Final Wrapped Dependences:
; CHECK: RAW dependences:
; CHECK-DAG: Stmt_S1[i0, i1] -> Stmt_S2[i0] : i0 <= 99 and i0 >= 0 and i1 <= 99 and i1 >= 0
; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 99 and i0 >= 0 and o1 <= 99 and o1 >= 0
-; CHECK-DAG: Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 <= 98 and i0 >= 0
; CHECK: WAR dependences:
; CHECK-DAG: { }
; CHECK: WAW dependences:
; CHECK-DAG: Stmt_S1[i0, i1] -> Stmt_S2[i0] : i0 <= 99 and i0 >= 0 and i1 <= 99 and i1 >= 0
; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 99 and i0 >= 0 and o1 <= 99 and o1 >= 0
-; CHECK-DAG: Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 >= 0 and i0 <= 98
+; CHECK-DAG: Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 <= 98 and i0 >= 0
; CHECK: Reduction dependences:
; CHECK-DAG: Stmt_S1[i0, i1] -> Stmt_S1[i0, 1 + i1] : i0 <= 99 and i0 >= 0 and i1 <= 98 and i1 >= 0
;
; VALUE: RAW dependences:
; VALUE: [p] -> {
; VALUE: Stmt_S1[i0] -> Stmt_S2[-p + i0] :
-; VALUE: i0 >= p and i0 <= 9 + p and p <= 190 and i0 <= 99 and i0 >= 0
+; VALUE: p <= 190 and i0 >= p and i0 <= 9 + p and i0 >= 0 and i0 <= 99
; VALUE: }
; VALUE: WAR dependences:
; VALUE: [p] -> {