From 978192140aa4be7176c3bded39cbbb77a0f5b316 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Fri, 27 Sep 2013 10:15:20 +0200 Subject: [PATCH] isl_ast_build_node_from_schedule: handle basic AST build options That is, handle the atomic/separate/unroll choice for each schedule dimension in a band node. These options are much simpler than their schedule map representation counterparts. When using a schedule map representation, the options had to describe which part of the schedule tree encoded in the schedule map was affected. Since the new options are attached directly to a band node, they only need to describe which of the schedule dimensions within the band is/are affected. In theory, the new options are less expressive, but in practice, the extra expressiveness is not used or even usable. In particular, the new options are much easier to use by the user and much easier to handle by isl with a seriously reduced risk for inconsistencies. We provide two interfaces for setting these options, one through a function call and one through an options string. The first is easier to use programmatically, while the second is easier to use when loading a schedule tree from a file. Signed-off-by: Sven Verdoolaege --- codegen.c | 42 +++++ doc/user.pod | 136 ++++++++++++++- include/isl/ast_type.h | 8 + include/isl/schedule_node.h | 10 ++ isl_ast_build.c | 109 +++++++++++- isl_ast_build_private.h | 17 +- isl_ast_codegen.c | 147 +++++++++++++++- isl_schedule_band.c | 376 +++++++++++++++++++++++++++++++++++++++- isl_schedule_band.h | 18 ++ isl_schedule_node.c | 59 +++++++ isl_schedule_read.c | 18 ++ isl_schedule_tree.c | 95 ++++++++++ isl_schedule_tree.h | 9 + test_inputs/codegen/atomic.st | 4 + test_inputs/codegen/separate.st | 4 + test_inputs/codegen/unroll8.c | 6 + test_inputs/codegen/unroll8.st | 5 + test_inputs/codegen/unroll9.c | 7 + test_inputs/codegen/unroll9.st | 7 + 19 files changed, 1046 insertions(+), 31 deletions(-) create mode 100644 test_inputs/codegen/atomic.st create mode 100644 test_inputs/codegen/separate.st create mode 100644 test_inputs/codegen/unroll8.c create mode 100644 test_inputs/codegen/unroll8.st create mode 100644 test_inputs/codegen/unroll9.c create mode 100644 test_inputs/codegen/unroll9.st diff --git a/codegen.c b/codegen.c index 1b16b4dc..78483f7e 100644 --- a/codegen.c +++ b/codegen.c @@ -25,6 +25,7 @@ #include #include #include +#include struct options { struct isl_options *isl; @@ -131,6 +132,43 @@ static __isl_give isl_ast_node *construct_ast_from_union_map( return tree; } +/* If "node" is a band node, then replace the AST build options + * by "options". + */ +static __isl_give isl_schedule_node *node_set_options( + __isl_take isl_schedule_node *node, void *user) +{ + enum isl_ast_loop_type *type = user; + int i, n; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_band) + return node; + + n = isl_schedule_node_band_n_member(node); + for (i = 0; i < n; ++i) + node = isl_schedule_node_band_member_set_ast_loop_type(node, + i, *type); + return node; +} + +/* Replace the AST build options on all band nodes if requested + * by the user. + */ +static __isl_give isl_schedule *schedule_set_options( + __isl_take isl_schedule *schedule, struct options *options) +{ + enum isl_ast_loop_type type; + + if (!options->separate && !options->atomic) + return schedule; + + type = options->separate ? isl_ast_loop_separate : isl_ast_loop_atomic; + schedule = isl_schedule_map_schedule_node(schedule, + &node_set_options, &type); + + return schedule; +} + /* Construct an AST in case the schedule is specified by a schedule tree. */ static __isl_give isl_ast_node *construct_ast_from_schedule( @@ -138,8 +176,12 @@ static __isl_give isl_ast_node *construct_ast_from_schedule( { isl_ast_build *build; isl_ast_node *tree; + struct options *options; + + options = isl_ctx_peek_cg_options(isl_schedule_get_ctx(schedule)); build = isl_ast_build_alloc(isl_schedule_get_ctx(schedule)); + schedule = schedule_set_options(schedule, options); tree = isl_ast_build_node_from_schedule(build, schedule); isl_ast_build_free(build); diff --git a/doc/user.pod b/doc/user.pod index e149faea..61cd56e3 100644 --- a/doc/user.pod +++ b/doc/user.pod @@ -7639,6 +7639,20 @@ Several node types have their own functions for querying __isl_give isl_schedule_node * isl_schedule_node_band_set_permutable( __isl_take isl_schedule_node *node, int permutable); + enum isl_ast_loop_type + isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); + __isl_give isl_union_set * + isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *options); The function C returns the space of the partial schedule of the band. @@ -7656,6 +7670,15 @@ iterations of outer bands). A band is marked permutable if it was produced using the Pluto-like scheduler. Note that the scheduler may have to resort to a Feautrier style scheduling step even if the default scheduler is used. +An C is one of C, +C, C or C. +For the meaning of these loop AST generation types, see +L. +The function C +may return C if an error occurs. +The AST build options govern how an AST is generated for +the individual schedule dimensions during AST generation. +See L. #include __isl_give isl_union_set * @@ -8997,15 +9020,102 @@ to construct if conditions with disjunctions. =back -=head3 Fine-grained Control over AST Generation +=head3 AST Generation Options (Schedule Tree) + +In case of AST construction from a schedule tree, the options +that control how an AST is created from the individual schedule +dimensions are stored in the band nodes of the tree +(see L). + +In particular, a schedule dimension can be handled in four +different ways, atomic, separate, unroll or the default. +This loop AST generation type can be set using +C. +Alternatively, +the first three can be selected by including a one-dimensional +element with as value the position of the schedule dimension +within the band and as name one of C, C +or C in the options +set by C. +Only one of these three may be specified for +any given schedule dimension within a band node. +If none of these is specified, then the default +is used. The meaning of the options is as follows. -Besides specifying the constraints on the parameters, -an C object can be used to control -various aspects of the AST generation process. -The most prominent way of control is through ``options'', -which only have an effect on the construction of an AST -using C and -which can be set using the following function. +=over + +=item C + +When this option is specified, the AST generator will make +sure that a given domains space only appears in a single +loop at the specified level. + +For example, for the schedule tree + + domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" + child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ atomic[x] }" + +the following AST will be generated + + for (int c0 = 0; c0 <= 10; c0 += 1) { + if (c0 >= 1) + b(c0 - 1); + if (c0 <= 9) + a(c0); + } + +On the other hand, for the schedule tree + + domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" + child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ separate[x] }" + +the following AST will be generated + + { + a(0); + for (int c0 = 1; c0 <= 9; c0 += 1) { + b(c0 - 1); + a(c0); + } + b(9); + } + +If neither C nor C is specified, then the AST generator +may produce either of these two results or some intermediate form. + +=item C + +When this option is specified, the AST generator will +split the domain of the specified schedule dimension +into pieces with a fixed set of statements for which +instances need to be executed by the iterations in +the schedule domain part. This option tends to avoid +the generation of guards inside the corresponding loops. +See also the C option. + +=item C + +When this option is specified, the AST generator will +I unroll the corresponding schedule dimension. +It is the responsibility of the user to ensure that such +unrolling is possible. +To obtain a partial unrolling, the user should apply an additional +strip-mining to the schedule and fully unroll the inner schedule +dimension. + +=back + +=head3 AST Generation Options (Schedule Map) + +In case of AST construction using +C, the options +that control how an AST is created from the individual schedule +dimensions are stored in the C. +They can be set using the following function. #include __isl_give isl_ast_build * @@ -9182,6 +9292,16 @@ strip-mining to the schedule and fully unroll the inner loop. =back +=head3 Fine-grained Control over AST Generation + +Besides specifying the constraints on the parameters, +an C object can be used to control +various aspects of the AST generation process. +In case of AST construction using +C, +the most prominent way of control is through ``options'', +as explained above. + Additional control is available through the following functions. #include diff --git a/include/isl/ast_type.h b/include/isl/ast_type.h index 19b14b3b..f5a23742 100644 --- a/include/isl/ast_type.h +++ b/include/isl/ast_type.h @@ -58,6 +58,14 @@ enum isl_ast_node_type { isl_ast_node_user }; +enum isl_ast_loop_type { + isl_ast_loop_error = -1, + isl_ast_loop_default = 0, + isl_ast_loop_atomic, + isl_ast_loop_unroll, + isl_ast_loop_separate +}; + struct isl_ast_print_options; typedef struct isl_ast_print_options isl_ast_print_options; diff --git a/include/isl/schedule_node.h b/include/isl/schedule_node.h index f9f82a36..c04f1dba 100644 --- a/include/isl/schedule_node.h +++ b/include/isl/schedule_node.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,15 @@ __isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule( __isl_keep isl_schedule_node *node); __isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( __isl_keep isl_schedule_node *node); +enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *options); unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node); int isl_schedule_node_band_member_get_coincident( __isl_keep isl_schedule_node *node, int pos); diff --git a/isl_ast_build.c b/isl_ast_build.c index 1c5c9372..d86ceedb 100644 --- a/isl_ast_build.c +++ b/isl_ast_build.c @@ -204,6 +204,17 @@ __isl_give isl_ast_build *isl_ast_build_dup(__isl_keep isl_ast_build *build) dup->create_leaf = build->create_leaf; dup->create_leaf_user = build->create_leaf_user; dup->node = isl_schedule_node_copy(build->node); + if (build->loop_type) { + int i; + + dup->n = build->n; + dup->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, dup->n); + if (dup->n && !dup->loop_type) + return isl_ast_build_free(dup); + for (i = 0; i < dup->n; ++i) + dup->loop_type[i] = build->loop_type[i]; + } if (!dup->iterators || !dup->domain || !dup->generated || !dup->pending || !dup->values || @@ -282,6 +293,7 @@ __isl_null isl_ast_build *isl_ast_build_free( isl_union_map_free(build->executed); isl_union_map_free(build->options); isl_schedule_node_free(build->node); + free(build->loop_type); free(build); @@ -955,7 +967,39 @@ __isl_give isl_schedule_node *isl_ast_build_get_schedule_node( return isl_schedule_node_copy(build->node); } -/* Replace the band node that "build" refers to by "node". +/* Extract the loop AST generation types for the members of build->node + * and store them in build->loop_type. + */ +static __isl_give isl_ast_build *extract_loop_types( + __isl_take isl_ast_build *build) +{ + int i; + isl_ctx *ctx; + isl_schedule_node *node; + + if (!build) + return NULL; + ctx = isl_ast_build_get_ctx(build); + if (!build->node) + isl_die(ctx, isl_error_internal, "missing AST node", + return isl_ast_build_free(build)); + + free(build->loop_type); + build->n = isl_schedule_node_band_n_member(build->node); + build->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, build->n); + if (build->n && !build->loop_type) + return isl_ast_build_free(build); + node = build->node; + for (i = 0; i < build->n; ++i) + build->loop_type[i] = + isl_schedule_node_band_member_get_ast_loop_type(node, i); + + return build; +} + +/* Replace the band node that "build" refers to by "node" and + * extract the corresponding loop AST generation types. */ __isl_give isl_ast_build *isl_ast_build_set_schedule_node( __isl_take isl_ast_build *build, @@ -968,6 +1012,8 @@ __isl_give isl_ast_build *isl_ast_build_set_schedule_node( isl_schedule_node_free(build->node); build->node = node; + build = extract_loop_types(build); + return build; error: isl_ast_build_free(build); @@ -1565,6 +1611,40 @@ static __isl_give isl_union_map *options_insert_dim( return options; } +/* If we are generating an AST from a schedule tree (build->node is set), + * then update the loop AST generation types + * to reflect the insertion of a dimension at (global) position "pos" + * in the schedule domain space. + */ +static __isl_give isl_ast_build *node_insert_dim( + __isl_take isl_ast_build *build, int pos) +{ + int i; + int local_pos; + enum isl_ast_loop_type *loop_type; + isl_ctx *ctx; + + build = isl_ast_build_cow(build); + if (!build) + return NULL; + if (!build->node) + return build; + + ctx = isl_ast_build_get_ctx(build); + local_pos = pos - build->outer_pos; + loop_type = isl_realloc_array(ctx, build->loop_type, + enum isl_ast_loop_type, build->n + 1); + if (!loop_type) + return isl_ast_build_free(build); + build->loop_type = loop_type; + for (i = build->n - 1; i >= local_pos; --i) + loop_type[i + 1] = loop_type[i]; + loop_type[local_pos] = isl_ast_loop_default; + build->n++; + + return build; +} + /* Insert a single dimension in the schedule domain at position "pos". * The new dimension is given an isl_id with the empty string as name. * @@ -1618,6 +1698,8 @@ __isl_give isl_ast_build *isl_ast_build_insert_dim( !build->strides || !build->offsets || !build->options) return isl_ast_build_free(build); + build = node_insert_dim(build, pos); + return build; } @@ -2122,6 +2204,31 @@ __isl_give isl_set *isl_ast_build_get_option_domain( return domain; } +/* How does the user want the current schedule dimension to be generated? + * These choices have been extracted from the schedule node + * in extract_loop_types and stored in build->loop_type. + * They have been updated to reflect any dimension insertion in + * node_insert_dim. + * Return isl_ast_domain_error on error. + */ +enum isl_ast_loop_type isl_ast_build_get_loop_type( + __isl_keep isl_ast_build *build) +{ + int local_pos; + isl_ctx *ctx; + + if (!build) + return isl_ast_loop_error; + ctx = isl_ast_build_get_ctx(build); + if (!build->node) + isl_die(ctx, isl_error_internal, + "only works for schedule tree based AST generation", + return isl_ast_loop_error); + + local_pos = build->depth - build->outer_pos; + return build->loop_type[local_pos]; +} + /* Extract the separation class mapping at the current depth. * * In particular, find and return the subset of build->options that is of diff --git a/isl_ast_build_private.h b/isl_ast_build_private.h index 4ab4bedb..51108c83 100644 --- a/isl_ast_build_private.h +++ b/isl_ast_build_private.h @@ -8,13 +8,6 @@ #include #include -enum isl_ast_loop_type { - isl_ast_loop_default = 0, - isl_ast_loop_atomic, - isl_ast_loop_unroll, - isl_ast_loop_separate -}; - /* An isl_ast_build represents the context in which AST is being * generated. That is, it (mostly) contains information about outer * loops that can be used to simplify inner loops. @@ -126,6 +119,11 @@ enum isl_ast_loop_type { * "node" points to the current band node in case we are generating * an AST from a schedule tree. It may be NULL if we are not generating * an AST from a schedule tree or if we are not inside a band node. + * + * "loop_type" originally constains loop AST generation types for + * the "n" members of "node" and it is updated (along with "n") when + * a schedule dimension is inserted. + * It is NULL if "node" is NULL. */ struct isl_ast_build { int ref; @@ -170,6 +168,8 @@ struct isl_ast_build { int single_valued; isl_schedule_node *node; + int n; + enum isl_ast_loop_type *loop_type; }; __isl_give isl_ast_build *isl_ast_build_clear_local_info( @@ -279,6 +279,9 @@ __isl_give isl_set *isl_ast_build_eliminate_inner( __isl_give isl_set *isl_ast_build_eliminate_divs( __isl_keep isl_ast_build *build, __isl_take isl_set *set); +enum isl_ast_loop_type isl_ast_build_get_loop_type( + __isl_keep isl_ast_build *build); + __isl_give isl_map *isl_ast_build_map_to_iterator( __isl_keep isl_ast_build *build, __isl_take isl_set *set); diff --git a/isl_ast_codegen.c b/isl_ast_codegen.c index 0156b0a6..5110d4cc 100644 --- a/isl_ast_codegen.c +++ b/isl_ast_codegen.c @@ -10,6 +10,7 @@ * B.P. 105 - 78153 Le Chesnay, France */ +#include #include #include #include @@ -2513,6 +2514,8 @@ error: } /* 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, @@ -2544,7 +2547,7 @@ error: * Finally, we map i' back to i and call "fn". */ static int foreach_iteration(__isl_take isl_set *domain, - __isl_keep isl_ast_build *build, + __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; @@ -2574,6 +2577,8 @@ static int foreach_iteration(__isl_take isl_set *domain, if (!lower) domain = isl_set_free(domain); + if (init && init(n, user) < 0) + domain = isl_set_free(domain); for (i = 0; i < n; ++i) { isl_set *set; isl_basic_set *bset; @@ -2690,7 +2695,7 @@ static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains, data.class_domain = class_domain; data.unroll_domain = isl_set_empty(isl_set_get_space(domain)); - if (foreach_iteration(domain, domains->build, + if (foreach_iteration(domain, domains->build, NULL, &do_unroll_iteration, &data) < 0) data.unroll_domain = isl_set_free(data.unroll_domain); @@ -3091,11 +3096,116 @@ static __isl_give isl_ast_graft_list *generate_shifted_component_flat( } /* 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. * - * We currently simply split the schedule domain into disjoint - * basic sets and then generate code for each of them, - * concatenating the results. + * 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( __isl_take isl_union_map *executed, __isl_take isl_ast_build *build) @@ -3104,15 +3214,34 @@ static __isl_give isl_ast_graft_list *generate_shifted_component_tree( 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); + 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); - domain = isl_set_make_disjoint(domain); - domain_list = isl_basic_set_list_from_set(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); @@ -3121,6 +3250,10 @@ static __isl_give isl_ast_graft_list *generate_shifted_component_tree( 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) diff --git a/isl_schedule_band.c b/isl_schedule_band.c index 6c0b391e..6efb6c58 100644 --- a/isl_schedule_band.c +++ b/isl_schedule_band.c @@ -10,6 +10,7 @@ * B.P. 105 - 78153 Le Chesnay, France */ +#include #include #include #include @@ -37,14 +38,15 @@ static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx) /* Return a new isl_schedule_band with partial schedule "mupa". * First replace "mupa" by its greatest integer part to ensure * that the schedule is always integral. - * The band is not marked permutable and the dimensions are not - * marked coincident. + * The band is not marked permutable, the dimensions are not + * marked coincident and the AST build options are empty. */ __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( __isl_take isl_multi_union_pw_aff *mupa) { isl_ctx *ctx; isl_schedule_band *band; + isl_space *space; mupa = isl_multi_union_pw_aff_floor(mupa); if (!mupa) @@ -57,8 +59,10 @@ __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); band->coincident = isl_calloc_array(ctx, int, band->n); band->mupa = mupa; + space = isl_space_params_alloc(ctx, 0); + band->ast_build_options = isl_union_set_empty(space); - if (band->n && !band->coincident) + if ((band->n && !band->coincident) || !band->ast_build_options) return isl_schedule_band_free(band); return band; @@ -94,9 +98,19 @@ __isl_give isl_schedule_band *isl_schedule_band_dup( dup->permutable = band->permutable; dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); - if (!dup->mupa) + dup->ast_build_options = isl_union_set_copy(band->ast_build_options); + if (!dup->mupa || !dup->ast_build_options) return isl_schedule_band_free(dup); + if (band->loop_type) { + dup->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !dup->loop_type) + return isl_schedule_band_free(dup); + for (i = 0; i < band->n; ++i) + dup->loop_type[i] = band->loop_type[i]; + } + return dup; } @@ -139,6 +153,8 @@ __isl_null isl_schedule_band *isl_schedule_band_free( return NULL; isl_multi_union_pw_aff_free(band->mupa); + isl_union_set_free(band->ast_build_options); + free(band->loop_type); free(band->coincident); free(band); @@ -151,6 +167,7 @@ int isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, __isl_keep isl_schedule_band *band2) { int i; + int equal; if (!band1 || !band2) return -1; @@ -165,7 +182,19 @@ int isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, if (band1->permutable != band2->permutable) return 0; - return isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa); + equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa); + if (equal < 0 || !equal) + return equal; + + if (!band1->loop_type != !band2->loop_type) + return 0; + if (band1->loop_type) + for (i = 0; i < band1->n; ++i) + if (band1->loop_type[i] != band2->loop_type[i]) + return 0; + + return isl_union_set_is_equal(band1->ast_build_options, + band2->ast_build_options); } /* Return the number of scheduling dimensions in the band. @@ -260,6 +289,329 @@ __isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL; } +/* Return the loop AST generation type for the band member of "band" + * at position "pos". + */ +enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos) +{ + if (!band) + return isl_ast_loop_error; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", return -1); + + if (!band->loop_type) + return isl_ast_loop_default; + + return band->loop_type[pos]; +} + +/* Set the loop AST generation type for the band member of "band" + * at position "pos" to "type". + */ +__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type) +{ + if (!band) + return NULL; + if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type) + return band; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", + isl_schedule_band_free(band)); + + band = isl_schedule_band_cow(band); + if (!band) + return isl_schedule_band_free(band); + + if (!band->loop_type) { + isl_ctx *ctx; + + ctx = isl_schedule_band_get_ctx(band); + band->loop_type = isl_calloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->loop_type) + return isl_schedule_band_free(band); + } + + band->loop_type[pos] = type; + + return band; +} + +static const char *option_str[] = { + [isl_ast_loop_atomic] = "atomic", + [isl_ast_loop_unroll] = "unroll", + [isl_ast_loop_separate] = "separate" +}; + +/* Given a parameter space "space", extend it to a set space + * + * { type[x] } + * + * which can be used to encode loop AST generation options of the given type. + */ +static __isl_give isl_space *loop_type_space(__isl_take isl_space *space, + enum isl_ast_loop_type type) +{ + const char *name; + + name = option_str[type]; + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); + space = isl_space_set_tuple_name(space, isl_dim_set, name); + + return space; +} + +/* Add encodings of the "n" loop AST generation options "type" to "options". + * + * In particular, for each sequence of consecutive identical types "t", + * different from the default, add an option + * + * { t[x] : first <= x <= last } + */ +static __isl_give isl_union_set *add_loop_types( + __isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type) +{ + int i; + isl_ctx *ctx; + + if (!type) + return options; + if (!options) + return NULL; + + ctx = isl_union_set_get_ctx(options); + for (i = 0; i < n; ++i) { + int first; + isl_space *space; + isl_set *option; + + if (type[i] == isl_ast_loop_default) + continue; + + first = i; + while (i + 1 < n && type[i + 1] == type[i]) + ++i; + + space = isl_union_set_get_space(options); + space = loop_type_space(space, type[i]); + option = isl_set_universe(space); + option = isl_set_lower_bound_si(option, isl_dim_set, 0, first); + option = isl_set_upper_bound_si(option, isl_dim_set, 0, i); + options = isl_union_set_add_set(options, option); + } + + return options; +} + +/* Return the AST build options associated to "band". + */ +__isl_give isl_union_set *isl_schedule_band_get_ast_build_options( + __isl_keep isl_schedule_band *band) +{ + isl_union_set *options; + + if (!band) + return NULL; + + options = isl_union_set_copy(band->ast_build_options); + options = add_loop_types(options, band->n, band->loop_type); + + return options; +} + +/* Does "uset" contain any set that satisfies "is"? + * "is" is assumed to set its integer argument to 1 if it is satisfied. + */ +static int has_any(__isl_keep isl_union_set *uset, + int (*is)(__isl_take isl_set *set, void *user)) +{ + int found = 0; + + if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found) + return -1; + + return found; +} + +/* Does "set" encode a loop AST generation option? + */ +static int is_loop_type_option(__isl_take isl_set *set, void *user) +{ + int *found = user; + + if (isl_set_dim(set, isl_dim_set) == 1 && + isl_set_has_tuple_name(set)) { + const char *name; + enum isl_ast_loop_type type; + name = isl_set_get_tuple_name(set); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + if (strcmp(name, option_str[type])) + continue; + *found = 1; + break; + } + } + isl_set_free(set); + + return *found ? -1 : 0; +} + +/* Does "options" encode any loop AST generation options? + */ +static int has_loop_type_options(__isl_keep isl_union_set *options) +{ + return has_any(options, &is_loop_type_option); +} + +/* Extract the loop AST generation type for the band member + * at position "pos" from "options". + */ +static enum isl_ast_loop_type extract_loop_type( + __isl_keep isl_union_set *options, int pos) +{ + isl_ctx *ctx; + enum isl_ast_loop_type type, res = isl_ast_loop_default; + + ctx = isl_union_set_get_ctx(options); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + isl_space *space; + isl_set *option; + int empty; + + space = isl_union_set_get_space(options); + space = loop_type_space(space, type); + option = isl_union_set_extract_set(options, space); + option = isl_set_fix_si(option, isl_dim_set, 0, pos); + empty = isl_set_is_empty(option); + isl_set_free(option); + + if (empty < 0) + return isl_ast_loop_error; + if (empty) + continue; + if (res != isl_ast_loop_default) + isl_die(ctx, isl_error_invalid, + "conflicting loop type options", + return isl_ast_loop_error); + res = type; + } + + return res; +} + +/* Extract the loop AST generation types for the members of "band" + * from "options" and store them in band->loop_type. + * Return -1 on error. + */ +static int extract_loop_types(__isl_keep isl_schedule_band *band, + __isl_keep isl_union_set *options) +{ + int i; + + if (!band->loop_type) { + isl_ctx *ctx = isl_schedule_band_get_ctx(band); + band->loop_type = isl_alloc_array(ctx, + enum isl_ast_loop_type, band->n); + if (band->n && !band->loop_type) + return -1; + } + for (i = 0; i < band->n; ++i) { + band->loop_type[i] = extract_loop_type(options, i); + if (band->loop_type[i] == isl_ast_loop_error) + return -1; + } + + return 0; +} + +/* Construct universe sets of the spaces that encode loop AST generation + * types. That is, construct + * + * { atomic[x]; separate[x]; unroll[x] } + */ +static __isl_give isl_union_set *loop_types(__isl_take isl_space *space) +{ + enum isl_ast_loop_type type; + isl_union_set *types; + + types = isl_union_set_empty(space); + for (type = isl_ast_loop_atomic; + type <= isl_ast_loop_separate; ++type) { + isl_set *set; + + space = isl_union_set_get_space(types); + space = loop_type_space(space, type); + set = isl_set_universe(space); + types = isl_union_set_add_set(types, set); + } + + return types; +} + +/* Remove all elements from spaces that encode loop AST generation types + * from "options". + */ +static __isl_give isl_union_set *clear_loop_types( + __isl_take isl_union_set *options) +{ + isl_union_set *types; + + types = loop_types(isl_union_set_get_space(options)); + options = isl_union_set_subtract(options, types); + + return options; +} + +/* Replace the AST build options associated to "band" by "options". + * If there are any loop AST generation type options, then they + * are extracted and stored in band->loop_type. Otherwise, + * band->loop_type is removed to indicate that the default applies + * to all members. + * The remaining options are stored in band->ast_build_options. + */ +__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *options) +{ + int has_loop_type; + + band = isl_schedule_band_cow(band); + if (!band || !options) + goto error; + has_loop_type = has_loop_type_options(options); + if (has_loop_type < 0) + goto error; + + if (!has_loop_type) { + free(band->loop_type); + band->loop_type = NULL; + } else { + if (extract_loop_types(band, options) < 0) + goto error; + options = clear_loop_types(options); + if (!options) + goto error; + } + + isl_union_set_free(band->ast_build_options); + band->ast_build_options = options; + + return band; +error: + isl_schedule_band_free(band); + isl_union_set_free(options); + return NULL; +} + /* Multiply the partial schedule of "band" with the factors in "mv". * Replace the result by its greatest integer part to ensure * that the schedule is always integral. @@ -436,6 +788,9 @@ __isl_give isl_schedule_band *isl_schedule_band_drop( for (i = pos + n; i < band->n; ++i) band->coincident[i - n] = band->coincident[i]; + if (band->loop_type) + for (i = pos + n; i < band->n; ++i) + band->loop_type[i - n] = band->loop_type[i]; band->n -= n; @@ -453,7 +808,9 @@ __isl_give isl_schedule_band *isl_schedule_band_reset_user( return NULL; band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa); - if (!band->mupa) + band->ast_build_options = + isl_union_set_reset_user(band->ast_build_options); + if (!band->mupa || !band->ast_build_options) return isl_schedule_band_free(band); return band; @@ -468,8 +825,11 @@ __isl_give isl_schedule_band *isl_schedule_band_align_params( if (!band || !space) goto error; - band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, space); - if (!band->mupa) + band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, + isl_space_copy(space)); + band->ast_build_options = + isl_union_set_align_params(band->ast_build_options, space); + if (!band->mupa || !band->ast_build_options) return isl_schedule_band_free(band); return band; diff --git a/isl_schedule_band.h b/isl_schedule_band.h index 5cf30d41..a3d8fd42 100644 --- a/isl_schedule_band.h +++ b/isl_schedule_band.h @@ -2,6 +2,7 @@ #define ISL_SCHEDULE_BAND_H #include +#include #include /* Information about a band within a schedule. @@ -13,6 +14,11 @@ * permutable is set if the band is permutable. * mupa is the partial schedule corresponding to this band. The dimension * of mupa is equal to n. + * loop_type contains the loop AST generation types for the members + * in the band. It may be NULL, if all members are + * of type isl_ast_loop_default. + * ast_build_options are the remaining AST build options associated + * to the band. */ struct isl_schedule_band { int ref; @@ -22,6 +28,9 @@ struct isl_schedule_band { int permutable; isl_multi_union_pw_aff *mupa; + + isl_union_set *ast_build_options; + enum isl_ast_loop_type *loop_type; }; typedef struct isl_schedule_band isl_schedule_band; @@ -41,6 +50,15 @@ __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_keep isl_schedule_band *band); +enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( + __isl_keep isl_schedule_band *band, int pos); +__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( + __isl_take isl_schedule_band *band, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_band_get_ast_build_options( + __isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( + __isl_take isl_schedule_band *band, __isl_take isl_union_set *options); int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band); int isl_schedule_band_member_get_coincident( diff --git a/isl_schedule_node.c b/isl_schedule_node.c index 38f65be6..12b3bb6c 100644 --- a/isl_schedule_node.c +++ b/isl_schedule_node.c @@ -1224,6 +1224,65 @@ __isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( return isl_union_map_from_multi_union_pw_aff(mupa); } +/* Return the loop AST generation type for the band member of band node "node" + * at position "pos". + */ +enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type( + __isl_keep isl_schedule_node *node, int pos) +{ + if (!node) + return isl_ast_loop_error; + + return isl_schedule_tree_band_member_get_ast_loop_type(node->tree, pos); +} + +/* Set the loop AST generation type for the band member of band node "node" + * at position "pos" to "type". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type( + __isl_take isl_schedule_node *node, int pos, + enum isl_ast_loop_type type) +{ + isl_schedule_tree *tree; + + if (!node) + return NULL; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_member_set_ast_loop_type(tree, pos, type); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Return the AST build options associated to band node "node". + */ +__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_ast_build_options(node->tree); +} + +/* Replace the AST build options associated to band node "node" by "options". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *options) +{ + isl_schedule_tree *tree; + + if (!node || !options) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_set_ast_build_options(tree, options); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_set_free(options); + return NULL; +} + /* Make sure that that spaces of "node" and "mv" are the same. * Return -1 on error, reporting the error to the user. */ diff --git a/isl_schedule_read.c b/isl_schedule_read.c index 95000aec..aa9d41b1 100644 --- a/isl_schedule_read.c +++ b/isl_schedule_read.c @@ -15,6 +15,7 @@ enum isl_schedule_key { isl_schedule_key_domain, isl_schedule_key_filter, isl_schedule_key_leaf, + isl_schedule_key_options, isl_schedule_key_permutable, isl_schedule_key_schedule, isl_schedule_key_sequence, @@ -50,6 +51,8 @@ static enum isl_schedule_key extract_key(__isl_keep isl_stream *s, key = isl_schedule_key_filter; else if (!strcmp(name, "leaf")) key = isl_schedule_key_leaf; + else if (!strcmp(name, "options")) + key = isl_schedule_key_options; else if (!strcmp(name, "schedule")) key = isl_schedule_key_schedule; else if (!strcmp(name, "sequence")) @@ -247,6 +250,7 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) isl_multi_union_pw_aff *schedule = NULL; isl_schedule_tree *tree = NULL; isl_val_list *coincident = NULL; + isl_union_set *options = NULL; isl_ctx *ctx; isl_schedule_band *band; int permutable = 0; @@ -290,6 +294,16 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) permutable = !isl_val_is_zero(v); isl_val_free(v); break; + case isl_schedule_key_options: + isl_union_set_free(options); + tok = isl_stream_next_token(s); + str = isl_token_get_str(ctx, tok); + options = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + if (!options) + goto error; + break; case isl_schedule_key_child: isl_schedule_tree_free(tree); tree = isl_stream_read_schedule_tree(s); @@ -312,6 +326,8 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) band = isl_schedule_band_set_permutable(band, permutable); if (coincident) band = set_coincident(band, coincident); + if (options) + band = isl_schedule_band_set_ast_build_options(band, options); if (tree) tree = isl_schedule_tree_insert_band(tree, band); else @@ -320,6 +336,7 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) return tree; error: isl_val_list_free(coincident); + isl_union_set_free(options); isl_schedule_tree_free(tree); isl_multi_union_pw_aff_free(schedule); return NULL; @@ -421,6 +438,7 @@ static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( break; case isl_schedule_key_schedule: case isl_schedule_key_coincident: + case isl_schedule_key_options: case isl_schedule_key_permutable: tree = read_band(s); break; diff --git a/isl_schedule_tree.c b/isl_schedule_tree.c index f675f64b..95be2f67 100644 --- a/isl_schedule_tree.c +++ b/isl_schedule_tree.c @@ -752,6 +752,85 @@ __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( return isl_schedule_band_get_partial_schedule(tree->band); } +/* Return the loop AST generation type for the band member + * of the band tree root at position "pos". + */ +enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return isl_ast_loop_error; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_ast_loop_error); + + return isl_schedule_band_member_get_ast_loop_type(tree->band, pos); +} + +/* Set the loop AST generation type for the band member of the band tree root + * at position "pos" to "type". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type) +{ + tree = isl_schedule_tree_cow(tree); + 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", return isl_schedule_tree_free(tree)); + + tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band, + pos, type); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +} + +/* Return the AST build options associated to the band tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options( + __isl_keep isl_schedule_tree *tree) +{ + 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", return NULL); + + return isl_schedule_band_get_ast_build_options(tree->band); +} + +/* Replace the AST build options associated to band tree root by "options". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !options) + goto error; + + 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->band = isl_schedule_band_set_ast_build_options(tree->band, + options); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(options); + return NULL; +} + /* Return the domain of the domain tree root. */ __isl_give isl_union_set *isl_schedule_tree_domain_get_domain( @@ -1609,6 +1688,9 @@ static int any_coincident(__isl_keep isl_schedule_band *band) static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p, __isl_keep isl_schedule_band *band) { + isl_union_set *options; + int empty; + p = isl_printer_print_str(p, "schedule"); p = isl_printer_yaml_next(p); p = isl_printer_print_str(p, "\""); @@ -1639,6 +1721,19 @@ static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p, p = isl_printer_yaml_end_sequence(p); p = isl_printer_set_yaml_style(p, style); } + options = isl_schedule_band_get_ast_build_options(band); + empty = isl_union_set_is_empty(options); + if (empty < 0) + p = isl_printer_free(p); + if (!empty) { + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "options"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, options); + p = isl_printer_print_str(p, "\""); + } + isl_union_set_free(options); return p; } diff --git a/isl_schedule_tree.h b/isl_schedule_tree.h index a5c5486c..2ec5e7a8 100644 --- a/isl_schedule_tree.h +++ b/isl_schedule_tree.h @@ -74,6 +74,15 @@ __isl_give isl_space *isl_schedule_tree_band_get_space( __isl_keep isl_schedule_tree *tree); __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( __isl_keep isl_schedule_tree *tree); +enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type( + __isl_keep isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type( + __isl_take isl_schedule_tree *tree, int pos, + enum isl_ast_loop_type type); +__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options); __isl_give isl_union_set *isl_schedule_tree_domain_get_domain( __isl_keep isl_schedule_tree *tree); __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( diff --git a/test_inputs/codegen/atomic.st b/test_inputs/codegen/atomic.st new file mode 100644 index 00000000..ca46e0ea --- /dev/null +++ b/test_inputs/codegen/atomic.st @@ -0,0 +1,4 @@ +domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" +child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ atomic[x] }" diff --git a/test_inputs/codegen/separate.st b/test_inputs/codegen/separate.st new file mode 100644 index 00000000..408c7d91 --- /dev/null +++ b/test_inputs/codegen/separate.st @@ -0,0 +1,4 @@ +domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }" +child: + schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]" + options: "{ separate[x] }" diff --git a/test_inputs/codegen/unroll8.c b/test_inputs/codegen/unroll8.c new file mode 100644 index 00000000..b3ca142d --- /dev/null +++ b/test_inputs/codegen/unroll8.c @@ -0,0 +1,6 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) { + A(c0, 0); + A(c0, 1); + B(c0, 0); + B(c0, 1); +} diff --git a/test_inputs/codegen/unroll8.st b/test_inputs/codegen/unroll8.st new file mode 100644 index 00000000..94fb49ea --- /dev/null +++ b/test_inputs/codegen/unroll8.st @@ -0,0 +1,5 @@ +# Check that options are adjusted by shifted stride detection +domain: "{ A[i,j] : 0 <= i < 100 and 0 <= j < 2; B[i,j] : 0 <= i < 100 and 0 <= j < 2 }" +child: + schedule: "[{ A[i,j] -> [2i]; B[i,j] -> [2i+1] }, { A[i,j] -> [j]; B[i,j] -> [j]}]" + options: "{ unroll[1] }" diff --git a/test_inputs/codegen/unroll9.c b/test_inputs/codegen/unroll9.c new file mode 100644 index 00000000..b00ea41d --- /dev/null +++ b/test_inputs/codegen/unroll9.c @@ -0,0 +1,7 @@ +for (int c0 = 0; c0 <= 99; c0 += 1) + for (int c1 = 0; c1 <= 99; c1 += 1) { + A(c1, 0, c0); + A(c1, 1, c0); + B(c1, 0, c0); + B(c1, 1, c0); + } diff --git a/test_inputs/codegen/unroll9.st b/test_inputs/codegen/unroll9.st new file mode 100644 index 00000000..653da415 --- /dev/null +++ b/test_inputs/codegen/unroll9.st @@ -0,0 +1,7 @@ +# Check that options are interpreted locally +domain: "{ A[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2; B[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2 }" +child: + schedule: "[{ A[i,j,k] -> [k]; B[i,j,k] -> [k] }]" + child: + schedule: "[{ A[i,j,k] -> [2i]; B[i,j,k] -> [2i+1] }, { A[i,j,k] -> [j]; B[i,j,k] -> [j]}]" + options: "{ unroll[1] }" -- 2.11.4.GIT