@@ -7294,7 +7294,7 @@ is therefore also immaterial.
=back
-The following node type is only supported by the AST generator.
+The following node types are only supported by the AST generator.
=over
@@ -7310,6 +7310,18 @@ this space is the unnamed zero-dimensional space.
Since a context node references the outer band nodes, any tree
containing a context node is considered to be anchored.
+=item C<isl_schedule_node_guard>
+
+The guard describes constraints on the parameters and
+the schedule dimensions of outer
+bands that need to be enforced by the outer nodes
+in the generated AST.
+The space of the guard is that of the flat product of the outer
+band nodes. In particular, if there are no outer band nodes, then
+this space is the unnamed zero-dimensional space.
+Since a guard node references the outer band nodes, any tree
+containing a guard node is considered to be anchored.
+
=back
Except for the C<isl_schedule_node_context> nodes,
@@ -7773,6 +7785,10 @@ See L</"AST Generation Options (Schedule Tree)">.
__isl_keep isl_schedule_node *node);
#include <isl/schedule_node.h>
+ __isl_give isl_set *isl_schedule_node_guard_get_guard(
+ __isl_keep isl_schedule_node *node);
+
+ #include <isl/schedule_node.h>
__isl_give isl_id *isl_schedule_node_mark_get_id(
__isl_keep isl_schedule_node *node);
@@ -7880,6 +7896,14 @@ two filter nodes are merged into one.
#include <isl/schedule_node.h>
__isl_give isl_schedule_node *
+ isl_schedule_node_insert_guard(
+ __isl_take isl_schedule_node *node,
+ __isl_take isl_set *guard);
+
+This function inserts a new guard node with the given guard constraints.
+
+ #include <isl/schedule_node.h>
+ __isl_give isl_schedule_node *
isl_schedule_node_insert_mark(
__isl_take isl_schedule_node *node,
__isl_take isl_id *mark);
@@ -132,6 +132,8 @@ __isl_give isl_union_pw_multi_aff *isl_schedule_node_expansion_get_contraction(
__isl_keep isl_schedule_node *node);
__isl_give isl_union_set *isl_schedule_node_filter_get_filter(
__isl_keep isl_schedule_node *node);
+__isl_give isl_set *isl_schedule_node_guard_get_guard(
+ __isl_keep isl_schedule_node *node);
__isl_give isl_id *isl_schedule_node_mark_get_id(
__isl_keep isl_schedule_node *node);
@@ -164,6 +166,8 @@ __isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule(
__isl_take isl_multi_union_pw_aff *schedule);
__isl_give isl_schedule_node *isl_schedule_node_insert_filter(
__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_node *isl_schedule_node_insert_guard(
+ __isl_take isl_schedule_node *node, __isl_take isl_set *context);
__isl_give isl_schedule_node *isl_schedule_node_insert_mark(
__isl_take isl_schedule_node *node, __isl_take isl_id *mark);
__isl_give isl_schedule_node *isl_schedule_node_insert_sequence(
@@ -13,6 +13,7 @@ enum isl_schedule_node_type {
isl_schedule_node_expansion,
isl_schedule_node_filter,
isl_schedule_node_leaf,
+ isl_schedule_node_guard,
isl_schedule_node_mark,
isl_schedule_node_sequence,
isl_schedule_node_set
@@ -4287,6 +4287,7 @@ static int after_in_tree(__isl_keep isl_union_map *umap,
return after_in_expansion(umap, node);
case isl_schedule_node_filter:
return after_in_filter(umap, node);
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
return after_in_child(umap, node);
case isl_schedule_node_set:
return NULL;
}
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the guard node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * Ensure that the associated guard is enforced by the outer AST
+ * constructs by adding it to the guard of the graft.
+ * Since we know that we will enforce the guard, we can also include it
+ * in the generated constraints used to construct an AST for
+ * the descendant nodes.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_guard(
+ __isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+ __isl_take isl_union_map *executed)
+{
+ isl_space *space;
+ isl_set *guard, *hoisted;
+ isl_basic_set *enforced;
+ isl_ast_build *sub_build;
+ isl_ast_graft *graft;
+ isl_ast_graft_list *list;
+ unsigned n1, n2;
+
+ space = isl_ast_build_get_space(build, 1);
+ guard = isl_schedule_node_guard_get_guard(node);
+ n1 = isl_space_dim(space, isl_dim_param);
+ guard = isl_set_align_params(guard, space);
+ n2 = isl_set_dim(guard, isl_dim_param);
+ if (n2 > n1)
+ isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+ "guard node is not allowed to introduce "
+ "new parameters", guard = isl_set_free(guard));
+ guard = isl_set_preimage_multi_aff(guard,
+ isl_multi_aff_copy(build->internal2input));
+ guard = isl_ast_build_specialize(build, guard);
+ guard = isl_set_gist(guard, isl_set_copy(build->generated));
+
+ sub_build = isl_ast_build_copy(build);
+ sub_build = isl_ast_build_restrict_generated(sub_build,
+ isl_set_copy(guard));
+
+ list = build_ast_from_child(isl_ast_build_copy(sub_build),
+ node, executed);
+
+ hoisted = isl_ast_graft_list_extract_hoistable_guard(list, sub_build);
+ if (isl_set_n_basic_set(hoisted) > 1)
+ list = isl_ast_graft_list_gist_guards(list,
+ isl_set_copy(hoisted));
+ guard = isl_set_intersect(guard, hoisted);
+ enforced = extract_shared_enforced(list, build);
+ graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
+ build, sub_build);
+
+ isl_ast_build_free(sub_build);
+ isl_ast_build_free(build);
+ return isl_ast_graft_list_from_ast_graft(graft);
+}
+
/* Call the before_each_mark callback, if requested by the user.
*
* Return 0 on success and -1 on error.
@@ -5261,6 +5322,8 @@ static __isl_give isl_ast_graft_list *build_ast_from_schedule_node(
return build_ast_from_expansion(build, node, executed);
case isl_schedule_node_filter:
return build_ast_from_filter(build, node, executed);
+ case isl_schedule_node_guard:
+ return build_ast_from_guard(build, node, executed);
case isl_schedule_node_mark:
return build_ast_from_mark(build, node, executed);
case isl_schedule_node_sequence:
@@ -744,6 +744,9 @@ static __isl_give isl_band_list *construct_band_list(
domain = isl_union_set_intersect(domain, filter);
node = isl_schedule_node_child(node, 0);
return construct_band_list(node, domain, parent);
+ case isl_schedule_node_guard:
+ isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+ "guard nodes not supported", goto error);
case isl_schedule_node_mark:
isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
"mark nodes not supported", goto error);
@@ -396,6 +396,7 @@ static int collect_filter_prefix_init(__isl_keep isl_schedule_tree *tree,
"should be handled by caller", return -1);
case isl_schedule_node_context:
case isl_schedule_node_leaf:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
@@ -464,6 +465,7 @@ static int collect_filter_prefix_update(__isl_keep isl_schedule_tree *tree,
"should be handled by caller", return -1);
case isl_schedule_node_context:
case isl_schedule_node_leaf:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
return NULL;
}
+/* Return the guard of the guard node "node".
+ */
+__isl_give isl_set *isl_schedule_node_guard_get_guard(
+ __isl_keep isl_schedule_node *node)
+{
+ if (!node)
+ return NULL;
+
+ return isl_schedule_tree_guard_get_guard(node->tree);
+}
+
/* Return the mark identifier of the mark node "node".
*/
__isl_give isl_id *isl_schedule_node_mark_get_id(
@@ -2089,6 +2102,24 @@ __isl_give isl_schedule_node *isl_schedule_node_insert_filter(
return node;
}
+/* Insert a guard node with guard "guard" between "node" and its parent.
+ * Return a pointer to the new guard node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_guard(
+ __isl_take isl_schedule_node *node, __isl_take isl_set *guard)
+{
+ isl_schedule_tree *tree;
+
+ if (check_insert(node) < 0)
+ node = isl_schedule_node_free(node);
+
+ tree = isl_schedule_node_get_tree(node);
+ tree = isl_schedule_tree_insert_guard(tree, guard);
+ node = isl_schedule_node_graft_tree(node, tree);
+
+ return node;
+}
+
/* Insert a mark node with mark identifier "mark" between "node" and
* its parent.
* Return a pointer to the new mark node.
@@ -2614,6 +2645,7 @@ static __isl_give isl_schedule_tree *group_ancestor(
data->finished = 1;
break;
case isl_schedule_node_leaf:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
@@ -2868,6 +2900,7 @@ static __isl_give isl_schedule_node *gist_enter(
case isl_schedule_node_band:
case isl_schedule_node_context:
case isl_schedule_node_domain:
+ case isl_schedule_node_guard:
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
@@ -2993,6 +3026,7 @@ static __isl_give isl_schedule_node *gist_leave(
break;
case isl_schedule_node_context:
case isl_schedule_node_domain:
+ case isl_schedule_node_guard:
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
break;
@@ -3138,6 +3172,7 @@ static __isl_give isl_schedule_node *subtree_expansion_enter(
case isl_schedule_node_band:
case isl_schedule_node_context:
case isl_schedule_node_domain:
+ case isl_schedule_node_guard:
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
@@ -3190,6 +3225,7 @@ static __isl_give isl_schedule_node *subtree_expansion_leave(
case isl_schedule_node_context:
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
@@ -3313,6 +3349,7 @@ static __isl_give isl_schedule_node *subtree_contraction_enter(
case isl_schedule_node_band:
case isl_schedule_node_context:
case isl_schedule_node_domain:
+ case isl_schedule_node_guard:
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
@@ -3368,6 +3405,7 @@ static __isl_give isl_schedule_node *subtree_contraction_leave(
case isl_schedule_node_context:
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
@@ -17,6 +17,7 @@ enum isl_schedule_key {
isl_schedule_key_domain,
isl_schedule_key_expansion,
isl_schedule_key_filter,
+ isl_schedule_key_guard,
isl_schedule_key_leaf,
isl_schedule_key_mark,
isl_schedule_key_options,
@@ -59,6 +60,8 @@ static enum isl_schedule_key extract_key(__isl_keep isl_stream *s,
key = isl_schedule_key_expansion;
else if (!strcmp(name, "filter"))
key = isl_schedule_key_filter;
+ else if (!strcmp(name, "guard"))
+ key = isl_schedule_key_guard;
else if (!strcmp(name, "leaf"))
key = isl_schedule_key_leaf;
else if (!strcmp(name, "mark"))
@@ -327,6 +330,57 @@ error:
return NULL;
}
+/* Read a subtree with guard root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_guard(isl_stream *s)
+{
+ isl_set *guard = NULL;
+ isl_schedule_tree *tree;
+ isl_ctx *ctx;
+ struct isl_token *tok;
+ enum isl_schedule_key key;
+ char *str;
+ int more;
+
+ ctx = isl_stream_get_ctx(s);
+
+ key = get_key(s);
+
+ if (isl_stream_yaml_next(s) < 0)
+ return NULL;
+
+ tok = isl_stream_next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ return NULL;
+ }
+ str = isl_token_get_str(ctx, tok);
+ guard = isl_set_read_from_str(ctx, str);
+ free(str);
+ isl_token_free(tok);
+
+ more = isl_stream_yaml_next(s);
+ if (more < 0)
+ goto error;
+ if (!more) {
+ tree = isl_schedule_tree_from_guard(guard);
+ } else {
+ key = get_key(s);
+ if (key != isl_schedule_key_child)
+ isl_die(ctx, isl_error_invalid, "expecting child",
+ goto error);
+ if (isl_stream_yaml_next(s) < 0)
+ goto error;
+ tree = isl_stream_read_schedule_tree(s);
+ tree = isl_schedule_tree_insert_guard(tree, guard);
+ }
+
+ return tree;
+error:
+ isl_set_free(guard);
+ return NULL;
+}
+
/* Read a subtree with mark root node from "s".
*/
static __isl_give isl_schedule_tree *read_mark(isl_stream *s)
@@ -623,6 +677,9 @@ static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
case isl_schedule_key_filter:
tree = read_filter(s);
break;
+ case isl_schedule_key_guard:
+ tree = read_guard(s);
+ break;
case isl_schedule_key_leaf:
isl_token_free(isl_stream_next_token(s));
tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s));
@@ -107,6 +107,11 @@ __isl_take isl_schedule_tree *isl_schedule_tree_dup(
if (!dup->filter)
return isl_schedule_tree_free(dup);
break;
+ case isl_schedule_node_guard:
+ dup->guard = isl_set_copy(tree->guard);
+ if (!dup->guard)
+ return isl_schedule_tree_free(dup);
+ break;
case isl_schedule_node_mark:
dup->mark = isl_id_copy(tree->mark);
if (!dup->mark)
@@ -199,6 +204,9 @@ __isl_null isl_schedule_tree *isl_schedule_tree_free(
case isl_schedule_node_filter:
isl_union_set_free(tree->filter);
break;
+ case isl_schedule_node_guard:
+ isl_set_free(tree->guard);
+ break;
case isl_schedule_node_mark:
isl_id_free(tree->mark);
break;
@@ -351,6 +359,33 @@ error:
return NULL;
}
+/* Create a new guard schedule tree with the given guard and no children.
+ * Since the guard references the outer schedule dimension,
+ * the tree is anchored.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
+ __isl_take isl_set *guard)
+{
+ isl_ctx *ctx;
+ isl_schedule_tree *tree;
+
+ if (!guard)
+ return NULL;
+
+ ctx = isl_set_get_ctx(guard);
+ tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
+ if (!tree)
+ goto error;
+
+ tree->guard = guard;
+ tree->anchored = 1;
+
+ return tree;
+error:
+ isl_set_free(guard);
+ return NULL;
+}
+
/* Create a new mark schedule tree with the given mark identifier and
* no children.
*/
@@ -387,7 +422,7 @@ int isl_schedule_tree_is_subtree_anchored(__isl_keep isl_schedule_tree *tree)
/* Does the root node of "tree" depend on its position in the complete
* schedule tree?
* Band nodes may be anchored depending on the associated AST build options.
- * Context nodes are always anchored.
+ * Context and guard nodes are always anchored.
*/
int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
{
@@ -400,6 +435,7 @@ int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
case isl_schedule_node_band:
return isl_schedule_band_is_anchored(tree->band);
case isl_schedule_node_context:
+ case isl_schedule_node_guard:
return 1;
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
@@ -570,6 +606,9 @@ int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
case isl_schedule_node_filter:
equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
break;
+ case isl_schedule_node_guard:
+ equal = isl_set_is_equal(tree1->guard, tree2->guard);
+ break;
case isl_schedule_node_mark:
equal = tree1->mark == tree2->mark;
break;
@@ -860,6 +899,18 @@ error:
return NULL;
}
+/* Create a new guard schedule tree with the given guard and
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
+{
+ isl_schedule_tree *res;
+
+ res = isl_schedule_tree_from_guard(guard);
+ return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
/* Create a new mark schedule tree with the given mark identifier and
* single child.
*/
return NULL;
}
+/* Return the guard of the guard tree root.
+ */
+__isl_give isl_set *isl_schedule_tree_guard_get_guard(
+ __isl_take isl_schedule_tree *tree)
+{
+ if (!tree)
+ return NULL;
+
+ if (tree->type != isl_schedule_node_guard)
+ isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+ "not a guard node", return NULL);
+
+ return isl_set_copy(tree->guard);
+}
+
/* Return the mark identifier of the mark tree root "tree".
*/
__isl_give isl_id *isl_schedule_tree_mark_get_id(
@@ -1410,6 +1476,7 @@ static int domain_less(__isl_keep isl_schedule_tree *tree)
case isl_schedule_node_band:
return isl_schedule_tree_band_n_member(tree) == 0;
case isl_schedule_node_context:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
return 1;
case isl_schedule_node_leaf:
@@ -1621,6 +1688,7 @@ static __isl_give isl_union_map *subtree_schedule_extend(
case isl_schedule_node_error:
return isl_union_map_free(outer);
case isl_schedule_node_context:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
return subtree_schedule_extend_child(tree, outer);
case isl_schedule_node_band:
@@ -1720,6 +1788,10 @@ static __isl_give isl_union_set *initial_domain(
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"context node should be handled by caller",
return NULL);
+ case isl_schedule_node_guard:
+ isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+ "guard node should be handled by caller",
+ return NULL);
case isl_schedule_node_mark:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"mark node should be handled by caller",
@@ -1999,6 +2071,11 @@ __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
if (!tree->filter)
return isl_schedule_tree_free(tree);
break;
+ case isl_schedule_node_guard:
+ tree->guard = isl_set_reset_user(tree->guard);
+ if (!tree->guard)
+ return isl_schedule_tree_free(tree);
+ break;
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
@@ -2058,6 +2135,11 @@ __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
if (!tree->filter)
return isl_schedule_tree_free(tree);
break;
+ case isl_schedule_node_guard:
+ tree->guard = isl_set_align_params(tree->guard, space);
+ if (!tree->guard)
+ return isl_schedule_tree_free(tree);
+ break;
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
@@ -2092,6 +2174,7 @@ static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
return 1;
case isl_schedule_node_context:
case isl_schedule_node_leaf:
+ case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
@@ -2331,6 +2414,13 @@ __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
p = isl_printer_print_union_set(p, tree->filter);
p = isl_printer_print_str(p, "\"");
break;
+ case isl_schedule_node_guard:
+ p = isl_printer_print_str(p, "guard");
+ p = isl_printer_yaml_next(p);
+ p = isl_printer_print_str(p, "\"");
+ p = isl_printer_print_set(p, tree->guard);
+ p = isl_printer_print_str(p, "\"");
+ break;
case isl_schedule_node_mark:
p = isl_printer_print_str(p, "mark");
p = isl_printer_yaml_next(p);
@@ -37,6 +37,10 @@ ISL_DECLARE_LIST(schedule_tree)
* The "filter" field is valid when type is isl_schedule_node_filter
* and represents the statement instances selected by the node.
*
+ * The "guard" field is valid when type is isl_schedule_node_guard
+ * and represents constraints on the flat product of the outer band nodes
+ * that need to be enforced by the outer nodes in the generated AST.
+ *
* The "mark" field is valid when type is isl_schedule_node_mark and
* identifies the mark.
*
@@ -61,6 +65,7 @@ struct isl_schedule_tree {
isl_union_map *expansion;
};
isl_union_set *filter;
+ isl_set *guard;
isl_id *mark;
};
isl_schedule_tree_list *children;
@@ -92,6 +97,8 @@ __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
__isl_take isl_union_map *expansion);
__isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
__isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
+ __isl_take isl_set *guard);
__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
enum isl_schedule_node_type type,
__isl_take isl_schedule_tree_list *list);
@@ -144,6 +151,8 @@ __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
__isl_keep isl_schedule_tree *tree);
__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_set *isl_schedule_tree_guard_get_guard(
+ __isl_keep isl_schedule_tree *tree);
__isl_give isl_id *isl_schedule_tree_mark_get_id(
__isl_keep isl_schedule_tree *tree);
@@ -181,6 +190,8 @@ __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
+ __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard);
__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
__isl_take isl_schedule_tree *tree, __isl_take isl_id *mark);