summaryrefslogtreecommitdiffstats
path: root/polly/lib/External/isl/isl_ast_codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'polly/lib/External/isl/isl_ast_codegen.c')
-rw-r--r--polly/lib/External/isl/isl_ast_codegen.c1391
1 files changed, 1299 insertions, 92 deletions
diff --git a/polly/lib/External/isl/isl_ast_codegen.c b/polly/lib/External/isl/isl_ast_codegen.c
index 84466f0ad6d..a2c1a380bc4 100644
--- a/polly/lib/External/isl/isl_ast_codegen.c
+++ b/polly/lib/External/isl/isl_ast_codegen.c
@@ -15,6 +15,7 @@
#include <isl/set.h>
#include <isl/ilp.h>
#include <isl/union_map.h>
+#include <isl/schedule_node.h>
#include <isl_sort.h>
#include <isl_tarjan.h>
#include <isl_ast_private.h>
@@ -251,8 +252,15 @@ static __isl_give isl_ast_graft_list *call_create_leaf(
return isl_ast_graft_list_from_ast_graft(graft);
}
+static __isl_give isl_ast_graft_list *build_ast_from_child(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed);
+
/* Generate an AST after having handled the complete schedule
- * of this call to the code generator.
+ * of this call to the code generator or the complete band
+ * if we are generating an AST from a schedule tree.
+ *
+ * If we are inside a band node, then move on to the child of the band.
*
* If the user has specified a create_leaf callback, control
* is passed to the user in call_create_leaf.
@@ -269,6 +277,13 @@ static __isl_give isl_ast_graft_list *generate_inner_level(
if (!build || !executed)
goto error;
+ if (isl_ast_build_has_schedule_node(build)) {
+ isl_schedule_node *node;
+ node = isl_ast_build_get_schedule_node(build);
+ build = isl_ast_build_reset_schedule_node(build);
+ return build_ast_from_child(build, node, executed);
+ }
+
if (build->create_leaf)
return call_create_leaf(executed, build);
@@ -2497,43 +2512,10 @@ error:
return isl_aff_free(data.lower);
}
-/* Data structure for storing the results and the intermediate objects
- * of compute_domains.
- *
- * "list" is the main result of the function and contains a list
- * of disjoint basic sets for which code should be generated.
- *
- * "executed" and "build" are inputs to compute_domains.
- * "schedule_domain" is the domain of "executed".
- *
- * "option" constains the domains at the current depth that should by
- * atomic, separated or unrolled. These domains are as specified by
- * the user, except that inner dimensions have been eliminated and
- * that they have been made pair-wise disjoint.
- *
- * "sep_class" contains the user-specified split into separation classes
- * specialized to the current depth.
- * "done" contains the union of the separation domains that have already
- * been handled.
- */
-struct isl_codegen_domains {
- isl_basic_set_list *list;
-
- isl_union_map *executed;
- isl_ast_build *build;
- isl_set *schedule_domain;
-
- isl_set *option[3];
-
- isl_map *sep_class;
- isl_set *done;
-};
-
-/* Extend domains->list with a list of basic sets, one for each value
- * of the current dimension in "domain" and remove the corresponding
- * sets from the class domain. Return the updated class domain.
- * The divs that involve the current dimension have not been projected out
- * from this domain.
+/* Call "fn" on each iteration of the current dimension of "domain".
+ * If "init" is not NULL, then it is called with the number of
+ * iterations before any call to "fn".
+ * Return -1 on failure.
*
* Since we are going to be iterating over the individual values,
* we first check if there are any strides on the current dimension.
@@ -2561,52 +2543,45 @@ struct isl_codegen_domains {
* will be taken into account at the next level, as in the case of the
* atomic option.
*
- * Finally, we map i' back to i and add each basic set to the list.
- * Since we may have dropped some constraints, we intersect with
- * the class domain again to ensure that each element in the list
- * is disjoint from the other class domains.
+ * Finally, we map i' back to i and call "fn".
*/
-static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains,
- __isl_take isl_set *domain, __isl_take isl_set *class_domain)
+static int foreach_iteration(__isl_take isl_set *domain,
+ __isl_keep isl_ast_build *build, int (*init)(int n, void *user),
+ int (*fn)(__isl_take isl_basic_set *bset, void *user), void *user)
{
int i, n;
int depth;
- isl_aff *lower;
isl_multi_aff *expansion;
isl_basic_map *bmap;
- isl_set *unroll_domain;
- isl_ast_build *build;
+ isl_aff *lower;
+ isl_ast_build *stride_build;
- if (!domain)
- return isl_set_free(class_domain);
+ depth = isl_ast_build_get_depth(build);
- depth = isl_ast_build_get_depth(domains->build);
- build = isl_ast_build_copy(domains->build);
domain = isl_ast_build_eliminate_inner(build, domain);
domain = isl_set_intersect(domain, isl_ast_build_get_domain(build));
- build = isl_ast_build_detect_strides(build, isl_set_copy(domain));
- expansion = isl_ast_build_get_stride_expansion(build);
+ stride_build = isl_ast_build_copy(build);
+ stride_build = isl_ast_build_detect_strides(stride_build,
+ isl_set_copy(domain));
+ expansion = isl_ast_build_get_stride_expansion(stride_build);
domain = isl_set_preimage_multi_aff(domain,
isl_multi_aff_copy(expansion));
- domain = isl_ast_build_eliminate_divs(build, domain);
-
- isl_ast_build_free(build);
+ domain = isl_ast_build_eliminate_divs(stride_build, domain);
+ isl_ast_build_free(stride_build);
bmap = isl_basic_map_from_multi_aff(expansion);
- lower = find_unroll_lower_bound(domains->build, domain, depth, bmap,
- &n);
+ lower = find_unroll_lower_bound(build, domain, depth, bmap, &n);
if (!lower)
- class_domain = isl_set_free(class_domain);
-
- unroll_domain = isl_set_empty(isl_set_get_space(domain));
+ domain = isl_set_free(domain);
- for (i = 0; class_domain && i < n; ++i) {
+ if (init && init(n, user) < 0)
+ domain = isl_set_free(domain);
+ for (i = 0; i < n; ++i) {
isl_set *set;
isl_basic_set *bset;
isl_constraint *slice;
- isl_basic_set_list *list;
slice = at_offset(depth, lower, i);
set = isl_set_copy(domain);
@@ -2614,20 +2589,117 @@ static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains,
bset = isl_set_unshifted_simple_hull(set);
bset = isl_basic_set_add_constraint(bset, slice);
bset = isl_basic_set_apply(bset, isl_basic_map_copy(bmap));
- set = isl_set_from_basic_set(bset);
- unroll_domain = isl_set_union(unroll_domain, isl_set_copy(set));
- set = isl_set_intersect(set, isl_set_copy(class_domain));
- set = isl_set_make_disjoint(set);
- list = isl_basic_set_list_from_set(set);
- domains->list = isl_basic_set_list_concat(domains->list, list);
- }
- class_domain = isl_set_subtract(class_domain, unroll_domain);
+ if (fn(bset, user) < 0)
+ break;
+ }
isl_aff_free(lower);
isl_set_free(domain);
isl_basic_map_free(bmap);
+ return i < n ? -1 : 0;
+}
+
+/* Data structure for storing the results and the intermediate objects
+ * of compute_domains.
+ *
+ * "list" is the main result of the function and contains a list
+ * of disjoint basic sets for which code should be generated.
+ *
+ * "executed" and "build" are inputs to compute_domains.
+ * "schedule_domain" is the domain of "executed".
+ *
+ * "option" constains the domains at the current depth that should by
+ * atomic, separated or unrolled. These domains are as specified by
+ * the user, except that inner dimensions have been eliminated and
+ * that they have been made pair-wise disjoint.
+ *
+ * "sep_class" contains the user-specified split into separation classes
+ * specialized to the current depth.
+ * "done" contains the union of the separation domains that have already
+ * been handled.
+ */
+struct isl_codegen_domains {
+ isl_basic_set_list *list;
+
+ isl_union_map *executed;
+ isl_ast_build *build;
+ isl_set *schedule_domain;
+
+ isl_set *option[4];
+
+ isl_map *sep_class;
+ isl_set *done;
+};
+
+/* Internal data structure for do_unroll.
+ *
+ * "domains" stores the results of compute_domains.
+ * "class_domain" is the original class domain passed to do_unroll.
+ * "unroll_domain" collects the unrolled iterations.
+ */
+struct isl_ast_unroll_data {
+ struct isl_codegen_domains *domains;
+ isl_set *class_domain;
+ isl_set *unroll_domain;
+};
+
+/* Given an iteration of an unrolled domain represented by "bset",
+ * add it to data->domains->list.
+ * Since we may have dropped some constraints, we intersect with
+ * the class domain again to ensure that each element in the list
+ * is disjoint from the other class domains.
+ */
+static int do_unroll_iteration(__isl_take isl_basic_set *bset, void *user)
+{
+ struct isl_ast_unroll_data *data = user;
+ isl_set *set;
+ isl_basic_set_list *list;
+
+ set = isl_set_from_basic_set(bset);
+ data->unroll_domain = isl_set_union(data->unroll_domain,
+ isl_set_copy(set));
+ set = isl_set_intersect(set, isl_set_copy(data->class_domain));
+ set = isl_set_make_disjoint(set);
+ list = isl_basic_set_list_from_set(set);
+ data->domains->list = isl_basic_set_list_concat(data->domains->list,
+ list);
+
+ return 0;
+}
+
+/* Extend domains->list with a list of basic sets, one for each value
+ * of the current dimension in "domain" and remove the corresponding
+ * sets from the class domain. Return the updated class domain.
+ * The divs that involve the current dimension have not been projected out
+ * from this domain.
+ *
+ * We call foreach_iteration to iterate over the individual values and
+ * in do_unroll_iteration we collect the individual basic sets in
+ * domains->list and their union in data->unroll_domain, which is then
+ * used to update the class domain.
+ */
+static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains,
+ __isl_take isl_set *domain, __isl_take isl_set *class_domain)
+{
+ struct isl_ast_unroll_data data;
+
+ if (!domain)
+ return isl_set_free(class_domain);
+ if (!class_domain)
+ return isl_set_free(domain);
+
+ data.domains = domains;
+ data.class_domain = class_domain;
+ data.unroll_domain = isl_set_empty(isl_set_get_space(domain));
+
+ if (foreach_iteration(domain, domains->build, NULL,
+ &do_unroll_iteration, &data) < 0)
+ data.unroll_domain = isl_set_free(data.unroll_domain);
+
+ class_domain = isl_set_subtract(class_domain, data.unroll_domain);
+
return class_domain;
}
@@ -2655,13 +2727,13 @@ static __isl_give isl_set *compute_unroll_domains(
int i, n;
int empty;
- empty = isl_set_is_empty(domains->option[unroll]);
+ empty = isl_set_is_empty(domains->option[isl_ast_loop_unroll]);
if (empty < 0)
return isl_set_free(class_domain);
if (empty)
return class_domain;
- unroll_domain = isl_set_copy(domains->option[unroll]);
+ unroll_domain = isl_set_copy(domains->option[isl_ast_loop_unroll]);
unroll_list = isl_basic_set_list_from_set(unroll_domain);
n = isl_basic_set_list_n_basic_set(unroll_list);
@@ -2714,7 +2786,7 @@ static __isl_give isl_set *compute_atomic_domain(
isl_set *domain, *atomic_domain;
int empty;
- domain = isl_set_copy(domains->option[atomic]);
+ domain = isl_set_copy(domains->option[isl_ast_loop_atomic]);
domain = isl_set_intersect(domain, isl_set_copy(class_domain));
domain = isl_set_intersect(domain,
isl_set_copy(domains->schedule_domain));
@@ -2761,7 +2833,7 @@ static int compute_separate_domain(struct isl_codegen_domains *domains,
isl_basic_set_list *list;
int empty;
- domain = isl_set_copy(domains->option[separate]);
+ domain = isl_set_copy(domains->option[isl_ast_loop_separate]);
domain = isl_set_intersect(domain, isl_set_copy(class_domain));
executed = isl_union_map_copy(domains->executed);
executed = isl_union_map_intersect_domain(executed,
@@ -2837,7 +2909,7 @@ static int compute_partial_domains(struct isl_codegen_domains *domains,
if (compute_separate_domain(domains, domain) < 0)
goto error;
domain = isl_set_subtract(domain,
- isl_set_copy(domains->option[separate]));
+ isl_set_copy(domains->option[isl_ast_loop_separate]));
domain = isl_set_intersect(domain,
isl_set_copy(domains->schedule_domain));
@@ -2897,20 +2969,24 @@ static int compute_class_domains(__isl_take isl_point *pnt, void *user)
* The domains specified by the user might overlap, so we make
* them disjoint by subtracting earlier domains from later domains.
*/
-static void compute_domains_init_options(isl_set *option[3],
+static void compute_domains_init_options(isl_set *option[4],
__isl_keep isl_ast_build *build)
{
- enum isl_ast_build_domain_type type, type2;
+ enum isl_ast_loop_type type, type2;
+ isl_set *unroll;
- for (type = atomic; type <= separate; ++type) {
+ for (type = isl_ast_loop_atomic;
+ type <= isl_ast_loop_separate; ++type) {
option[type] = isl_ast_build_get_option_domain(build, type);
- for (type2 = atomic; type2 < type; ++type2)
+ for (type2 = isl_ast_loop_atomic; type2 < type; ++type2)
option[type] = isl_set_subtract(option[type],
isl_set_copy(option[type2]));
}
- option[unroll] = isl_set_coalesce(option[unroll]);
- option[unroll] = isl_set_make_disjoint(option[unroll]);
+ unroll = option[isl_ast_loop_unroll];
+ unroll = isl_set_coalesce(unroll);
+ unroll = isl_set_make_disjoint(unroll);
+ option[isl_ast_loop_unroll] = unroll;
}
/* Split up the domain at the current depth into disjoint
@@ -2944,7 +3020,7 @@ static __isl_give isl_basic_set_list *compute_domains(
isl_set *classes;
isl_space *space;
int n_param;
- enum isl_ast_build_domain_type type;
+ enum isl_ast_loop_type type;
int empty;
if (!executed)
@@ -2989,20 +3065,20 @@ static __isl_give isl_basic_set_list *compute_domains(
isl_set_free(domains.schedule_domain);
isl_set_free(domains.done);
isl_map_free(domains.sep_class);
- for (type = atomic; type <= separate; ++type)
+ for (type = isl_ast_loop_atomic; type <= isl_ast_loop_separate; ++type)
isl_set_free(domains.option[type]);
return domains.list;
}
/* Generate code for a single component, after shifting (if any)
- * has been applied.
+ * has been applied, in case the schedule was specified as a union map.
*
* We first split up the domain at the current depth into disjoint
* basic sets based on the user-specified options.
* Then we generated code for each of them and concatenate the results.
*/
-static __isl_give isl_ast_graft_list *generate_shifted_component(
+static __isl_give isl_ast_graft_list *generate_shifted_component_flat(
__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
{
isl_basic_set_list *domain_list;
@@ -3018,6 +3094,306 @@ static __isl_give isl_ast_graft_list *generate_shifted_component(
return list;
}
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree
+ * and the separate option was specified.
+ *
+ * We perform separation on the domain of "executed" and then generate
+ * an AST for each of the resulting disjoint basic sets.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_separate(
+ __isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+ isl_space *space;
+ isl_set *domain;
+ isl_basic_set_list *domain_list;
+ isl_ast_graft_list *list;
+
+ space = isl_ast_build_get_space(build, 1);
+ domain = separate_schedule_domains(space,
+ isl_union_map_copy(executed), build);
+ domain_list = isl_basic_set_list_from_set(domain);
+
+ list = generate_parallel_domains(domain_list, executed, build);
+
+ isl_basic_set_list_free(domain_list);
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+
+ return list;
+}
+
+/* Internal data structure for generate_shifted_component_tree_unroll.
+ *
+ * "executed" and "build" are inputs to generate_shifted_component_tree_unroll.
+ * "list" collects the constructs grafts.
+ */
+struct isl_ast_unroll_tree_data {
+ isl_union_map *executed;
+ isl_ast_build *build;
+ isl_ast_graft_list *list;
+};
+
+/* Initialize data->list to a list of "n" elements.
+ */
+static int init_unroll_tree(int n, void *user)
+{
+ struct isl_ast_unroll_tree_data *data = user;
+ isl_ctx *ctx;
+
+ ctx = isl_ast_build_get_ctx(data->build);
+ data->list = isl_ast_graft_list_alloc(ctx, n);
+
+ return 0;
+}
+
+/* Given an iteration of an unrolled domain represented by "bset",
+ * generate the corresponding AST and add the result to data->list.
+ */
+static int do_unroll_tree_iteration(__isl_take isl_basic_set *bset, void *user)
+{
+ struct isl_ast_unroll_tree_data *data = user;
+
+ data->list = add_node(data->list, isl_union_map_copy(data->executed),
+ bset, isl_ast_build_copy(data->build));
+
+ return 0;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree
+ * and the unroll option was specified.
+ *
+ * We call foreach_iteration to iterate over the individual values and
+ * construct and collect the corresponding grafts in do_unroll_tree_iteration.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_unroll(
+ __isl_take isl_union_map *executed, __isl_take isl_set *domain,
+ __isl_take isl_ast_build *build)
+{
+ struct isl_ast_unroll_tree_data data = { executed, build, NULL };
+
+ if (foreach_iteration(domain, build, &init_unroll_tree,
+ &do_unroll_tree_iteration, &data) < 0)
+ data.list = isl_ast_graft_list_free(data.list);
+
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+
+ return data.list;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, handle the base case where there is either no isolated
+ * set or we are within the isolated set (in which case "isolated" is set)
+ * or the iterations that precede or follow the isolated set.
+ *
+ * The schedule domain is broken up or combined into basic sets
+ * according to the AST generation option specified in the current
+ * schedule node, which may be either atomic, separate, unroll or
+ * unspecified. If the option is unspecified, then we currently simply
+ * split the schedule domain into disjoint basic sets.
+ *
+ * In case the separate option is specified, the AST generation is
+ * handled by generate_shifted_component_tree_separate.
+ * In the other cases, we need the global schedule domain.
+ * In the unroll case, the AST generation is then handled by
+ * generate_shifted_component_tree_unroll which needs the actual
+ * schedule domain (with divs that may refer to the current dimension)
+ * so that stride detection can be performed.
+ * In the atomic or unspecified case, inner dimensions and divs involving
+ * the current dimensions should be eliminated.
+ * The result is then either combined into a single basic set or
+ * split up into disjoint basic sets.
+ * Finally an AST is generated for each basic set and the results are
+ * concatenated.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_base(
+ __isl_take isl_union_map *executed, __isl_take isl_ast_build *build,
+ int isolated)
+{
+ isl_union_set *schedule_domain;
+ isl_set *domain;
+ isl_basic_set_list *domain_list;
+ isl_ast_graft_list *list;
+ enum isl_ast_loop_type type;
+
+ type = isl_ast_build_get_loop_type(build, isolated);
+ if (type < 0)
+ goto error;
+
+ if (type == isl_ast_loop_separate)
+ return generate_shifted_component_tree_separate(executed,
+ build);
+
+ schedule_domain = isl_union_map_domain(isl_union_map_copy(executed));
+ domain = isl_set_from_union_set(schedule_domain);
+
+ if (type == isl_ast_loop_unroll)
+ return generate_shifted_component_tree_unroll(executed, domain,
+ build);
+
+ domain = isl_ast_build_eliminate(build, domain);
+ domain = isl_set_coalesce(domain);
+
+ if (type == isl_ast_loop_atomic) {
+ isl_basic_set *hull;
+ hull = isl_set_unshifted_simple_hull(domain);
+ domain_list = isl_basic_set_list_from_basic_set(hull);
+ } else {
+ domain = isl_set_make_disjoint(domain);
+ domain_list = isl_basic_set_list_from_set(domain);
+ }
+
+ list = generate_parallel_domains(domain_list, executed, build);
+
+ isl_basic_set_list_free(domain_list);
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+
+ return list;
+error:
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+ return NULL;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, do so for the specified subset of the schedule domsain.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_part(
+ __isl_keep isl_union_map *executed, __isl_take isl_set *domain,
+ __isl_keep isl_ast_build *build, int isolated)
+{
+ isl_union_set *uset;
+ int empty;
+
+ uset = isl_union_set_from_set(domain);
+ executed = isl_union_map_copy(executed);
+ executed = isl_union_map_intersect_domain(executed, uset);
+ empty = isl_union_map_is_empty(executed);
+ if (empty < 0)
+ goto error;
+ if (empty) {
+ isl_ctx *ctx;
+ isl_union_map_free(executed);
+ ctx = isl_ast_build_get_ctx(build);
+ return isl_ast_graft_list_alloc(ctx, 0);
+ }
+
+ build = isl_ast_build_copy(build);
+ return generate_shifted_component_tree_base(executed, build, isolated);
+error:
+ isl_union_map_free(executed);
+ return NULL;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ *
+ * We first check if the user has specified a (non-empty) isolated
+ * schedule domain.
+ * If so, we break up the schedule domain into iterations that
+ * precede the isolated domain, the isolated domain itself,
+ * the iterations that follow the isolated domain and
+ * the remaining iterations (those that are incomparable
+ * to the isolated domain).
+ * We generate an AST for each piece and concatenate the results.
+ * If no isolated set has been specified, then we generate an
+ * AST for the entire inverse schedule.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree(
+ __isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+ int i, depth;
+ int empty, has_isolate;
+ isl_space *space;
+ isl_union_set *schedule_domain;
+ isl_set *domain;
+ isl_basic_set *hull;
+ isl_set *isolated, *before, *after;
+ isl_map *gt, *lt;
+ isl_ast_graft_list *list, *res;
+
+ build = isl_ast_build_extract_isolated(build);
+ has_isolate = isl_ast_build_has_isolated(build);
+ if (has_isolate < 0)
+ executed = isl_union_map_free(executed);
+ else if (!has_isolate)
+ return generate_shifted_component_tree_base(executed, build, 0);
+
+ schedule_domain = isl_union_map_domain(isl_union_map_copy(executed));
+ domain = isl_set_from_union_set(schedule_domain);
+
+ isolated = isl_ast_build_get_isolated(build);
+ isolated = isl_set_intersect(isolated, isl_set_copy(domain));
+ empty = isl_set_is_empty(isolated);
+ if (empty < 0)
+ goto error;
+ if (empty) {
+ isl_set_free(isolated);
+ isl_set_free(domain);
+ return generate_shifted_component_tree_base(executed, build, 0);
+ }
+ isolated = isl_ast_build_eliminate(build, isolated);
+ hull = isl_set_unshifted_simple_hull(isolated);
+ isolated = isl_set_from_basic_set(hull);
+
+ depth = isl_ast_build_get_depth(build);
+ space = isl_space_map_from_set(isl_set_get_space(isolated));
+ gt = isl_map_universe(space);
+ for (i = 0; i < depth; ++i)
+ gt = isl_map_equate(gt, isl_dim_in, i, isl_dim_out, i);
+ gt = isl_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth);
+ lt = isl_map_reverse(isl_map_copy(gt));
+ before = isl_set_apply(isl_set_copy(isolated), gt);
+ after = isl_set_apply(isl_set_copy(isolated), lt);
+
+ domain = isl_set_subtract(domain, isl_set_copy(isolated));
+ domain = isl_set_subtract(domain, isl_set_copy(before));
+ domain = isl_set_subtract(domain, isl_set_copy(after));
+ after = isl_set_subtract(after, isl_set_copy(isolated));
+ after = isl_set_subtract(after, isl_set_copy(before));
+ before = isl_set_subtract(before, isl_set_copy(isolated));
+
+ res = generate_shifted_component_tree_part(executed, before, build, 0);
+ list = generate_shifted_component_tree_part(executed, isolated,
+ build, 1);
+ res = isl_ast_graft_list_concat(res, list);
+ list = generate_shifted_component_tree_part(executed, after, build, 0);
+ res = isl_ast_graft_list_concat(res, list);
+ list = generate_shifted_component_tree_part(executed, domain, build, 0);
+ res = isl_ast_graft_list_concat(res, list);
+
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+
+ return res;
+error:
+ isl_set_free(domain);
+ isl_set_free(isolated);
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+ return NULL;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied.
+ *
+ * Call generate_shifted_component_tree or generate_shifted_component_flat
+ * depending on whether the schedule was specified as a schedule tree.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component(
+ __isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+ if (isl_ast_build_has_schedule_node(build))
+ return generate_shifted_component_tree(executed, build);
+ else
+ return generate_shifted_component_flat(executed, build);
+}
+
struct isl_set_map_pair {
isl_set *set;
isl_map *map;
@@ -3398,6 +3774,21 @@ error:
return NULL;
}
+/* Does any node in the schedule tree rooted at the current schedule node
+ * of "build" depend on outer schedule nodes?
+ */
+static int has_anchored_subtree(__isl_keep isl_ast_build *build)
+{
+ isl_schedule_node *node;
+ int dependent = 0;
+
+ node = isl_ast_build_get_schedule_node(build);
+ dependent = isl_schedule_node_is_subtree_anchored(node);
+ isl_schedule_node_free(node);
+
+ return dependent;
+}
+
/* Generate code for a single component.
*
* The component inverse schedule is specified as the "map" fields
@@ -3429,11 +3820,15 @@ error:
* a fixed value for almost all domains then there is nothing to be done.
* In particular, we need at least two domains where the current schedule
* dimension does not have a fixed value.
- * Finally, if any of the options refer to the current schedule dimension,
+ * Finally, in case of a schedule map input,
+ * if any of the options refer to the current schedule dimension,
* then we bail out as well. It would be possible to reformulate the options
* in terms of the new schedule domain, but that would introduce constraints
* that separate the domains in the options and that is something we would
* like to avoid.
+ * In the case of a schedule tree input, we bail out if any of
+ * the descendants of the current schedule node refer to outer
+ * schedule nodes in any way.
*
*
* To see if there is any shifted stride, we look at the differences
@@ -3485,8 +3880,12 @@ static __isl_give isl_ast_graft_list *generate_component(
skip = n == 1;
if (skip >= 0 && !skip)
skip = at_most_one_non_fixed(domain, order, n, depth);
- if (skip >= 0 && !skip)
- skip = isl_ast_build_options_involve_depth(build);
+ if (skip >= 0 && !skip) {
+ if (isl_ast_build_has_schedule_node(build))
+ skip = has_anchored_subtree(build);
+ else
+ skip = isl_ast_build_options_involve_depth(build);
+ }
if (skip < 0)
goto error;
if (skip)
@@ -3578,8 +3977,339 @@ static int extract_domain(__isl_take isl_map *map, void *user)
return 0;
}
+static int after_in_tree(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node);
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the child of "node"?
+ */
+static int after_in_child(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ isl_schedule_node *child;
+ int after;
+
+ child = isl_schedule_node_get_child(node, 0);
+ after = after_in_tree(umap, child);
+ isl_schedule_node_free(child);
+
+ return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the band node "node"?
+ *
+ * We first check if any domain element is scheduled after any
+ * of the corresponding image elements by the band node itself.
+ * If not, we restrict "map" to those pairs of element that
+ * are scheduled together by the band node and continue with
+ * the child of the band node.
+ * If there are no such pairs then the map passed to after_in_child
+ * will be empty causing it to return 0.
+ */
+static int after_in_band(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ isl_multi_union_pw_aff *mupa;
+ isl_union_map *partial, *test, *gt, *universe, *umap1, *umap2;
+ isl_union_set *domain, *range;
+ isl_space *space;
+ int empty;
+ int after;
+
+ if (isl_schedule_node_band_n_member(node) == 0)
+ return after_in_child(umap, node);
+
+ mupa = isl_schedule_node_band_get_partial_schedule(node);
+ space = isl_multi_union_pw_aff_get_space(mupa);
+ partial = isl_union_map_from_multi_union_pw_aff(mupa);
+ test = isl_union_map_copy(umap);
+ test = isl_union_map_apply_domain(test, isl_union_map_copy(partial));
+ test = isl_union_map_apply_range(test, isl_union_map_copy(partial));
+ gt = isl_union_map_from_map(isl_map_lex_gt(space));
+ test = isl_union_map_intersect(test, gt);
+ empty = isl_union_map_is_empty(test);
+ isl_union_map_free(test);
+
+ if (empty < 0 || !empty) {
+ isl_union_map_free(partial);
+ return empty < 0 ? -1 : 1;
+ }
+
+ universe = isl_union_map_universe(isl_union_map_copy(umap));
+ domain = isl_union_map_domain(isl_union_map_copy(universe));
+ range = isl_union_map_range(universe);
+ umap1 = isl_union_map_copy(partial);
+ umap1 = isl_union_map_intersect_domain(umap1, domain);
+ umap2 = isl_union_map_intersect_domain(partial, range);
+ test = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2));
+ test = isl_union_map_intersect(test, isl_union_map_copy(umap));
+ after = after_in_child(test, node);
+ isl_union_map_free(test);
+ return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the context node "node"?
+ *
+ * The context constraints apply to the schedule domain,
+ * so we cannot apply them directly to "umap", which contains
+ * pairs of statement instances. Instead, we add them
+ * to the range of the prefix schedule for both domain and
+ * range of "umap".
+ */
+static int after_in_context(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ isl_union_map *prefix, *universe, *umap1, *umap2;
+ isl_union_set *domain, *range;
+ isl_set *context;
+ int after;
+
+ umap = isl_union_map_copy(umap);
+ context = isl_schedule_node_context_get_context(node);
+ prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+ universe = isl_union_map_universe(isl_union_map_copy(umap));
+ domain = isl_union_map_domain(isl_union_map_copy(universe));
+ range = isl_union_map_range(universe);
+ umap1 = isl_union_map_copy(prefix);
+ umap1 = isl_union_map_intersect_domain(umap1, domain);
+ umap2 = isl_union_map_intersect_domain(prefix, range);
+ umap1 = isl_union_map_intersect_range(umap1,
+ isl_union_set_from_set(context));
+ umap1 = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2));
+ umap = isl_union_map_intersect(umap, umap1);
+
+ after = after_in_child(umap, node);
+
+ isl_union_map_free(umap);
+
+ return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the filter node "node"?
+ *
+ * We intersect domain and range of "umap" with the filter and
+ * continue with its child.
+ */
+static int after_in_filter(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ isl_union_set *filter;
+ int after;
+
+ umap = isl_union_map_copy(umap);
+ filter = isl_schedule_node_filter_get_filter(node);
+ umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(filter));
+ umap = isl_union_map_intersect_range(umap, filter);
+
+ after = after_in_child(umap, node);
+
+ isl_union_map_free(umap);
+
+ return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the set node "node"?
+ *
+ * This is only the case if this condition holds in any
+ * of the (filter) children of the set node.
+ * In particular, if the domain and the range of "umap"
+ * are contained in different children, then the condition
+ * does not hold.
+ */
+static int after_in_set(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ int i, n;
+
+ n = isl_schedule_node_n_children(node);
+ for (i = 0; i < n; ++i) {
+ isl_schedule_node *child;
+ int after;
+
+ child = isl_schedule_node_get_child(node, i);
+ after = after_in_tree(umap, child);
+ isl_schedule_node_free(child);
+
+ if (after < 0 || after)
+ return after;
+ }
+
+ return 0;
+}
+
+/* Return the filter of child "i" of "node".
+ */
+static __isl_give isl_union_set *child_filter(
+ __isl_keep isl_schedule_node *node, int i)
+{
+ isl_schedule_node *child;
+ isl_union_set *filter;
+
+ child = isl_schedule_node_get_child(node, i);
+ filter = isl_schedule_node_filter_get_filter(child);
+ isl_schedule_node_free(child);
+
+ return filter;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the sequence node "node"?
+ *
+ * This happens in particular if any domain element is
+ * contained in a later child than one containing a range element or
+ * if the condition holds within a given child in the sequence.
+ * The later part of the condition is checked by after_in_set.
+ */
+static int after_in_sequence(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ int i, j, n;
+ isl_union_map *umap_i;
+ int empty, after = 0;
+
+ n = isl_schedule_node_n_children(node);
+ for (i = 1; i < n; ++i) {
+ isl_union_set *filter_i;
+
+ umap_i = isl_union_map_copy(umap);
+ filter_i = child_filter(node, i);
+ umap_i = isl_union_map_intersect_domain(umap_i, filter_i);
+ empty = isl_union_map_is_empty(umap_i);
+ if (empty < 0)
+ goto error;
+ if (empty) {
+ isl_union_map_free(umap_i);
+ continue;
+ }
+
+ for (j = 0; j < i; ++j) {
+ isl_union_set *filter_j;
+ isl_union_map *umap_ij;
+
+ umap_ij = isl_union_map_copy(umap_i);
+ filter_j = child_filter(node, j);
+ umap_ij = isl_union_map_intersect_range(umap_ij,
+ filter_j);
+ empty = isl_union_map_is_empty(umap_ij);
+ isl_union_map_free(umap_ij);
+
+ if (empty < 0)
+ goto error;
+ if (!empty)
+ after = 1;
+ if (after)
+ break;
+ }
+
+ isl_union_map_free(umap_i);
+ if (after)
+ break;
+ }
+
+ if (after < 0 || after)
+ return after;
+
+ return after_in_set(umap, node);
+error:
+ isl_union_map_free(umap_i);
+ return -1;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at "node"?
+ *
+ * If "umap" is empty, then clearly there is no such element.
+ * Otherwise, consider the different types of nodes separately.
+ */
+static int after_in_tree(__isl_keep isl_union_map *umap,
+ __isl_keep isl_schedule_node *node)
+{
+ int empty;
+ enum isl_schedule_node_type type;
+
+ empty = isl_union_map_is_empty(umap);
+ if (empty < 0)
+ return -1;
+ if (empty)
+ return 0;
+ if (!node)
+ return -1;
+
+ type = isl_schedule_node_get_type(node);
+ switch (type) {
+ case isl_schedule_node_error:
+ return -1;
+ case isl_schedule_node_leaf:
+ return 0;
+ case isl_schedule_node_band:
+ return after_in_band(umap, node);
+ case isl_schedule_node_domain:
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+ "unexpected internal domain node", return -1);
+ case isl_schedule_node_context:
+ return after_in_context(umap, node);
+ case isl_schedule_node_filter:
+ return after_in_filter(umap, node);
+ case isl_schedule_node_set:
+ return after_in_set(umap, node);
+ case isl_schedule_node_sequence:
+ return after_in_sequence(umap, node);
+ }
+
+ return 1;
+}
+
+/* Is any domain element of "map1" scheduled after any domain
+ * element of "map2" by the subtree underneath the current band node,
+ * while at the same time being scheduled together by the current
+ * band node, i.e., by "map1" and "map2?
+ *
+ * If the child of the current band node is a leaf, then
+ * no element can be scheduled after any other element.
+ *
+ * Otherwise, we construct a relation between domain elements
+ * of "map1" and domain elements of "map2" that are scheduled
+ * together and then check if the subtree underneath the current
+ * band node determines their relative order.
+ */
+static int after_in_subtree(__isl_keep isl_ast_build *build,
+ __isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ isl_schedule_node *node;
+ isl_map *map;
+ isl_union_map *umap;
+ int after;
+
+ node = isl_ast_build_get_schedule_node(build);
+ if (!node)
+ return -1;
+ node = isl_schedule_node_child(node, 0);
+ if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) {
+ isl_schedule_node_free(node);
+ return 0;
+ }
+ map = isl_map_copy(map2);
+ map = isl_map_apply_domain(map, isl_map_copy(map1));
+ umap = isl_union_map_from_map(map);
+ after = after_in_tree(umap, node);
+ isl_union_map_free(umap);
+ isl_schedule_node_free(node);
+ return after;
+}
+
/* Internal data for any_scheduled_after.
*
+ * "build" is the build in which the AST is constructed.
* "depth" is the number of loops that have already been generated
* "group_coscheduled" is a local copy of options->ast_build_group_coscheduled
* "domain" is an array of set-map pairs corresponding to the different
@@ -3587,6 +4317,7 @@ static int extract_domain(__isl_take isl_map *map, void *user)
* of the inverse schedule, while the map is the inverse schedule itself.
*/
struct isl_any_scheduled_after_data {
+ isl_ast_build *build;
int depth;
int group_coscheduled;
struct isl_set_map_pair *domain;
@@ -3598,6 +4329,11 @@ struct isl_any_scheduled_after_data {
* data->domain[i].set contains the domain of the inverse schedule
* for domain "i", i.e., elements in the schedule domain.
*
+ * If we are inside a band of a schedule tree and there is a pair
+ * of elements in the two domains that is schedule together by
+ * the current band, then we check if any element of "i" may be schedule
+ * after element of "j" by the descendants of the band node.
+ *
* If data->group_coscheduled is set, then we also return 1 if there
* is any pair of elements in the two domains that are scheduled together.
*/
@@ -3621,6 +4357,15 @@ static int any_scheduled_after(int i, int j, void *user)
return 0;
}
+ if (isl_ast_build_has_schedule_node(data->build)) {
+ int after;
+
+ after = after_in_subtree(data->build, data->domain[i].map,
+ data->domain[j].map);
+ if (after < 0 || after)
+ return after;
+ }
+
return data->group_coscheduled;
}
@@ -3667,6 +4412,7 @@ static __isl_give isl_ast_graft_list *generate_components(
if (!build)
goto error;
+ data.build = build;
data.depth = isl_ast_build_get_depth(build);
data.group_coscheduled = isl_options_get_ast_build_group_coscheduled(ctx);
g = isl_tarjan_graph_init(ctx, n, &any_scheduled_after, &data);
@@ -3753,7 +4499,7 @@ error:
return NULL;
}
-/* Internal data structure used by isl_ast_build_ast_from_schedule.
+/* Internal data structure used by isl_ast_build_node_from_schedule_map.
* internal, executed and build are the inputs to generate_code.
* list collects the output.
*/
@@ -3811,7 +4557,8 @@ static __isl_give isl_union_map *internal_executed(
* It is equal to the space of "set" if build->domain is parametric.
* Otherwise, it is equal to the range of the wrapped space of "set".
*
- * If the build space is not parametric and if isl_ast_build_ast_from_schedule
+ * If the build space is not parametric and
+ * if isl_ast_build_node_from_schedule_map
* was called from an outside user (data->internal not set), then
* the (inverse) schedule refers to the external build domain and needs to
* be transformed to refer to the internal build domain.
@@ -4012,7 +4759,7 @@ error:
* the schedule domain in the domain and the elements to be executed
* in the range) called "executed".
*/
-__isl_give isl_ast_node *isl_ast_build_ast_from_schedule(
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule_map(
__isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule)
{
isl_ast_graft_list *list;
@@ -4030,3 +4777,463 @@ __isl_give isl_ast_node *isl_ast_build_ast_from_schedule(
return node;
}
+
+/* The old name for isl_ast_build_node_from_schedule_map.
+ * It is being kept for backward compatibility, but
+ * it will be removed in the future.
+ */
+__isl_give isl_ast_node *isl_ast_build_ast_from_schedule(
+ __isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule)
+{
+ return isl_ast_build_node_from_schedule_map(build, schedule);
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the band node "node" and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * If the band is empty, we continue with its descendants.
+ * Otherwise, we extend the build and the inverse schedule with
+ * the additional space/partial schedule and continue generating
+ * an AST in generate_next_level.
+ * As soon as we have extended the inverse schedule with the additional
+ * partial schedule, we look for equalities that may exists between
+ * the old and the new part.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_band(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ isl_space *space;
+ isl_multi_union_pw_aff *extra;
+ isl_union_map *extra_umap;
+ isl_ast_graft_list *list;
+ unsigned n1, n2;
+
+ if (!build || !node || !executed)
+ goto error;
+
+ if (isl_schedule_node_band_n_member(node) == 0)
+ return build_ast_from_child(build, node, executed);
+
+ extra = isl_schedule_node_band_get_partial_schedule(node);
+ extra = isl_multi_union_pw_aff_align_params(extra,
+ isl_ast_build_get_space(build, 1));
+ space = isl_multi_union_pw_aff_get_space(extra);
+
+ extra_umap = isl_union_map_from_multi_union_pw_aff(extra);
+ extra_umap = isl_union_map_reverse(extra_umap);
+
+ executed = isl_union_map_domain_product(executed, extra_umap);
+ executed = isl_union_map_detect_equalities(executed);
+
+ n1 = isl_ast_build_dim(build, isl_dim_param);
+ build = isl_ast_build_product(build, space);
+ n2 = isl_ast_build_dim(build, isl_dim_param);
+ if (n2 > n1)
+ isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+ "band node is not allowed to introduce new parameters",
+ build = isl_ast_build_free(build));
+ build = isl_ast_build_set_schedule_node(build, node);
+
+ list = generate_next_level(executed, build);
+
+ list = isl_ast_graft_list_unembed(list, 1);
+
+ return list;
+error:
+ isl_schedule_node_free(node);
+ isl_union_map_free(executed);
+ isl_ast_build_free(build);
+ return NULL;
+}
+
+/* Hoist a list of grafts (in practice containing a single graft)
+ * from "sub_build" (which includes extra context information)
+ * to "build".
+ *
+ * In particular, project out all additional parameters introduced
+ * by the context node from the enforced constraints and the guard
+ * of the single graft.
+ */
+static __isl_give isl_ast_graft_list *hoist_out_of_context(
+ __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build,
+ __isl_keep isl_ast_build *sub_build)
+{
+ isl_ast_graft *graft;
+ isl_basic_set *enforced;
+ isl_set *guard;
+ unsigned n_param, extra_param;
+
+ if (!build || !sub_build)
+ return isl_ast_graft_list_free(list);
+
+ n_param = isl_ast_build_dim(build, isl_dim_param);
+ extra_param = isl_ast_build_dim(sub_build, isl_dim_param);
+
+ if (extra_param == n_param)
+ return list;
+
+ extra_param -= n_param;
+ enforced = isl_ast_graft_list_extract_shared_enforced(list, sub_build);
+ enforced = isl_basic_set_project_out(enforced, isl_dim_param,
+ n_param, extra_param);
+ enforced = isl_basic_set_remove_unknown_divs(enforced);
+ guard = isl_ast_graft_list_extract_hoistable_guard(list, sub_build);
+ guard = isl_set_remove_divs_involving_dims(guard, isl_dim_param,
+ n_param, extra_param);
+ guard = isl_set_project_out(guard, isl_dim_param, n_param, extra_param);
+ guard = isl_set_compute_divs(guard);
+ graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
+ build, sub_build);
+ list = isl_ast_graft_list_from_ast_graft(graft);
+
+ return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the context node "node"
+ * and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * The context node may introduce additional parameters as well as
+ * constraints on the outer schedule dimenions or original parameters.
+ *
+ * We add the extra parameters to a new build and the context
+ * constraints to both the build and (as a single disjunct)
+ * to the domain of "executed". Since the context constraints
+ * are specified in terms of the input schedule, we first need
+ * to map them to the internal schedule domain.
+ *
+ * After constructing the AST from the descendants of "node",
+ * we combine the list of grafts into a single graft within
+ * the new build, in order to be able to exploit the additional
+ * context constraints during this combination.
+ *
+ * Additionally, if the current node is the outermost node in
+ * the schedule tree (apart from the root domain node), we generate
+ * all pending guards, again to be able to exploit the additional
+ * context constraints. We currently do not do this for internal
+ * context nodes since we may still want to hoist conditions
+ * to outer AST nodes.
+ *
+ * If the context node introduced any new parameters, then they
+ * are removed from the set of enforced constraints and guard
+ * in hoist_out_of_context.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_context(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ isl_set *context;
+ isl_space *space;
+ isl_multi_aff *internal2input;
+ isl_ast_build *sub_build;
+ isl_ast_graft_list *list;
+ int n, depth;
+
+ depth = isl_schedule_node_get_tree_depth(node);
+ space = isl_ast_build_get_space(build, 1);
+ context = isl_schedule_node_context_get_context(node);
+ context = isl_set_align_params(context, space);
+ sub_build = isl_ast_build_copy(build);
+ space = isl_set_get_space(context);
+ sub_build = isl_ast_build_align_params(sub_build, space);
+ internal2input = isl_ast_build_get_internal2input(sub_build);
+ context = isl_set_preimage_multi_aff(context, internal2input);
+ sub_build = isl_ast_build_restrict_generated(sub_build,
+ isl_set_copy(context));
+ context = isl_set_from_basic_set(isl_set_simple_hull(context));
+ executed = isl_union_map_intersect_domain(executed,
+ isl_union_set_from_set(context));
+
+ list = build_ast_from_child(isl_ast_build_copy(sub_build),
+ node, executed);
+ n = isl_ast_graft_list_n_ast_graft(list);
+ if (n < 0)
+ list = isl_ast_graft_list_free(list);
+
+ list = isl_ast_graft_list_fuse(list, sub_build);
+ if (depth == 1)
+ list = isl_ast_graft_list_insert_pending_guard_nodes(list,
+ sub_build);
+ if (n >= 1)
+ list = hoist_out_of_context(list, build, sub_build);
+
+ isl_ast_build_free(build);
+ isl_ast_build_free(sub_build);
+
+ return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the filter node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * We simply intersect the iteration domain (i.e., the range of "executed")
+ * with the filter and continue with the descendants of the node,
+ * unless the resulting inverse schedule is empty, in which
+ * case we return an empty list.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_filter(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ isl_ctx *ctx;
+ isl_union_set *filter;
+ isl_ast_graft_list *list;
+ int empty;
+ unsigned n1, n2;
+
+ if (!build || !node || !executed)
+ goto error;
+
+ filter = isl_schedule_node_filter_get_filter(node);
+ filter = isl_union_set_align_params(filter,
+ isl_union_map_get_space(executed));
+ n1 = isl_union_map_dim(executed, isl_dim_param);
+ executed = isl_union_map_intersect_range(executed, filter);
+ n2 = isl_union_map_dim(executed, isl_dim_param);
+ if (n2 > n1)
+ isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+ "filter node is not allowed to introduce "
+ "new parameters", goto error);
+
+ empty = isl_union_map_is_empty(executed);
+ if (empty < 0)
+ goto error;
+ if (!empty)
+ return build_ast_from_child(build, node, executed);
+
+ ctx = isl_ast_build_get_ctx(build);
+ list = isl_ast_graft_list_alloc(ctx, 0);
+ isl_ast_build_free(build);
+ isl_schedule_node_free(node);
+ isl_union_map_free(executed);
+ return list;
+error:
+ isl_ast_build_free(build);
+ isl_schedule_node_free(node);
+ isl_union_map_free(executed);
+ return NULL;
+}
+
+static __isl_give isl_ast_graft_list *build_ast_from_schedule_node(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed);
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the sequence (or set) node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * We simply generate an AST for each of the children and concatenate
+ * the results.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_sequence(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ int i, n;
+ isl_ctx *ctx;
+ isl_ast_graft_list *list;
+
+ ctx = isl_ast_build_get_ctx(build);
+ list = isl_ast_graft_list_alloc(ctx, 0);
+
+ n = isl_schedule_node_n_children(node);
+ for (i = 0; i < n; ++i) {
+ isl_schedule_node *child;
+ isl_ast_graft_list *list_i;
+
+ child = isl_schedule_node_get_child(node, i);
+ list_i = build_ast_from_schedule_node(isl_ast_build_copy(build),
+ child, isl_union_map_copy(executed));
+ list = isl_ast_graft_list_concat(list, list_i);
+ }
+ isl_ast_build_free(build);
+ isl_schedule_node_free(node);
+ isl_union_map_free(executed);
+
+ return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the node "node" and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * If the node is a leaf, then we pass control to generate_inner_level.
+ * Note that the current build does not refer to any band node, so
+ * that generate_inner_level will not try to visit the child of
+ * the leaf node.
+ *
+ * The other node types are handled in separate functions.
+ * Set nodes are currently treated in the same way as sequence nodes.
+ * The children of a set node may be executed in any order,
+ * including the order of the children.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_schedule_node(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ enum isl_schedule_node_type type;
+
+ type = isl_schedule_node_get_type(node);
+
+ switch (type) {
+ case isl_schedule_node_error:
+ goto error;
+ case isl_schedule_node_leaf:
+ isl_schedule_node_free(node);
+ return generate_inner_level(executed, build);
+ case isl_schedule_node_band:
+ return build_ast_from_band(build, node, executed);
+ case isl_schedule_node_context:
+ return build_ast_from_context(build, node, executed);
+ case isl_schedule_node_domain:
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+ "unexpected internal domain node", goto error);
+ case isl_schedule_node_filter:
+ return build_ast_from_filter(build, node, executed);
+ case isl_schedule_node_sequence:
+ case isl_schedule_node_set:
+ return build_ast_from_sequence(build, node, executed);
+ }
+
+ isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+ "unhandled type", goto error);
+error:
+ isl_union_map_free(executed);
+ isl_schedule_node_free(node);
+ isl_ast_build_free(build);
+
+ return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the (single) child of "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * This function is never called on a leaf, set or sequence node,
+ * so the node always has exactly one child.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_child(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ node = isl_schedule_node_child(node, 0);
+ return build_ast_from_schedule_node(build, node, executed);
+}
+
+/* Generate an AST that visits the elements in the domain of the domain
+ * node "node" in the relative order specified by its descendants.
+ *
+ * An initial inverse schedule is created that maps a zero-dimensional
+ * schedule space to the node domain.
+ * The input "build" is assumed to have a parametric domain and
+ * is replaced by the same zero-dimensional schedule space.
+ *
+ * We also add some of the parameter constraints in the build domain
+ * to the executed relation. Adding these constraints
+ * allows for an earlier detection of conflicts in some cases.
+ * However, we do not want to divide the executed relation into
+ * more disjuncts than necessary. We therefore approximate
+ * the constraints on the parameters by a single disjunct set.
+ */
+static __isl_give isl_ast_node *build_ast_from_domain(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node)
+{
+ isl_ctx *ctx;
+ isl_union_set *domain, *schedule_domain;
+ isl_union_map *executed;
+ isl_space *space;
+ isl_set *set;
+ isl_ast_graft_list *list;
+ isl_ast_node *ast;
+ int is_params;
+
+ if (!build)
+ goto error;
+
+ ctx = isl_ast_build_get_ctx(build);
+ space = isl_ast_build_get_space(build, 1);
+ is_params = isl_space_is_params(space);
+ isl_space_free(space);
+ if (is_params < 0)
+ goto error;
+ if (!is_params)
+ isl_die(ctx, isl_error_unsupported,
+ "expecting parametric initial context", goto error);
+
+ domain = isl_schedule_node_domain_get_domain(node);
+ domain = isl_union_set_coalesce(domain);
+
+ space = isl_union_set_get_space(domain);
+ space = isl_space_set_from_params(space);
+ build = isl_ast_build_product(build, space);
+
+ set = isl_ast_build_get_domain(build);
+ set = isl_set_from_basic_set(isl_set_simple_hull(set));
+ schedule_domain = isl_union_set_from_set(set);
+
+ executed = isl_union_map_from_domain_and_range(schedule_domain, domain);
+ list = build_ast_from_child(isl_ast_build_copy(build), node, executed);
+ ast = isl_ast_node_from_graft_list(list, build);
+ isl_ast_build_free(build);
+
+ return ast;
+error:
+ isl_schedule_node_free(node);
+ isl_ast_build_free(build);
+ return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "schedule"
+ * in the relative order specified by the schedule tree.
+ *
+ * "build" is an isl_ast_build that has been created using
+ * isl_ast_build_alloc or isl_ast_build_from_context based
+ * on a parametric set.
+ *
+ * The construction starts at the root node of the schedule,
+ * which is assumed to be a domain node.
+ */
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule(
+ __isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule)
+{
+ isl_ctx *ctx;
+ isl_schedule_node *node;
+
+ if (!build || !schedule)
+ goto error;
+
+ ctx = isl_ast_build_get_ctx(build);
+
+ node = isl_schedule_get_root(schedule);
+ isl_schedule_free(schedule);
+
+ build = isl_ast_build_copy(build);
+ build = isl_ast_build_set_single_valued(build, 0);
+ if (isl_schedule_node_get_type(node) != isl_schedule_node_domain)
+ isl_die(ctx, isl_error_unsupported,
+ "expecting root domain node",
+ build = isl_ast_build_free(build));
+ return build_ast_from_domain(build, node);
+error:
+ isl_schedule_free(schedule);
+ return NULL;
+}
OpenPOWER on IntegriCloud