#include <isl/options.h>
#include <isl/set.h>
#include <isl/stream.h>
+#include <isl/schedule_node.h>
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);
@@ -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<isl_schedule_node_band_get_space> 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<isl_ast_loop_type> is one of C<isl_ast_loop_default>,
+C<isl_ast_loop_atomic>, C<isl_ast_loop_unroll> or C<isl_ast_loop_separate>.
+For the meaning of these loop AST generation types, see
+L</"AST Generation Options (Schedule Tree)">.
+The function C<isl_schedule_node_band_member_get_ast_loop_type>
+may return C<isl_ast_loop_error> if an error occurs.
+The AST build options govern how an AST is generated for
+the individual schedule dimensions during AST generation.
+See L</"AST Generation Options (Schedule Tree)">.
#include <isl/schedule_node.h>
__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</"Schedule Trees">).
+
+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<isl_schedule_node_band_member_set_ast_loop_type>.
+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<atomic>, C<separate>
+or C<unroll> in the options
+set by C<isl_schedule_node_band_set_ast_build_options>.
+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<isl_ast_build> 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<isl_ast_build_node_from_schedule_map> and
-which can be set using the following function.
+=over
+
+=item C<atomic>
+
+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<atomic> nor C<separate> is specified, then the AST generator
+may produce either of these two results or some intermediate form.
+
+=item C<separate>
+
+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<atomic> option.
+
+=item C<unroll>
+
+When this option is specified, the AST generator will
+I<completely> 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<isl_ast_build_node_from_schedule_map>, the options
+that control how an AST is created from the individual schedule
+dimensions are stored in the C<isl_ast_build>.
+They can be set using the following function.
#include <isl/ast_build.h>
__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<isl_ast_build> object can be used to control
+various aspects of the AST generation process.
+In case of AST construction using
+C<isl_ast_build_node_from_schedule_map>,
+the most prominent way of control is through ``options'',
+as explained above.
+
Additional control is available through the following functions.
#include <isl/ast_build.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;
#include <isl/schedule_type.h>
#include <isl/union_set_type.h>
#include <isl/aff_type.h>
+#include <isl/ast_type.h>
#include <isl/val.h>
#include <isl/space.h>
@@ -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);
@@ -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
#include <isl/list.h>
#include <isl/schedule_node.h>
-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);
* B.P. 105 - 78153 Le Chesnay, France
*/
+#include <string.h>
#include <limits.h>
#include <isl/aff.h>
#include <isl/set.h>
@@ -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)
* B.P. 105 - 78153 Le Chesnay, France
*/
+#include <string.h>
#include <isl/schedule_node.h>
#include <isl_schedule_band.h>
#include <isl_schedule_private.h>
@@ -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;
#define ISL_SCHEDULE_BAND_H
#include <isl/aff.h>
+#include <isl/ast_type.h>
#include <isl/union_map.h>
/* Information about a band within a schedule.
* 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(
@@ -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.
*/
@@ -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;
@@ -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;
}
@@ -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(
--- /dev/null
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+ schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+ options: "{ atomic[x] }"
--- /dev/null
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+ schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+ options: "{ separate[x] }"
--- /dev/null
+for (int c0 = 0; c0 <= 99; c0 += 1) {
+ A(c0, 0);
+ A(c0, 1);
+ B(c0, 0);
+ B(c0, 1);
+}
--- /dev/null
+# 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] }"
--- /dev/null
+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);
+ }
--- /dev/null
+# 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] }"