identity = isl_set_identity(isl_map_range(isl_map_copy(executed)));
executed = isl_map_domain_product(executed, identity);
+ build = isl_ast_build_set_single_valued(build, 1);
list = generate_code(isl_union_map_from_map(executed), build, 1);
* the constraints from data->build->domain.
* On the other hand, we only perform the test after having taken the gist
* of the domain as the resulting map is the one from which the call
- * expression is constructed.
+ * expression is constructed. Using this map to construct the call
+ * expression usually yields simpler results.
+ * Because we perform the single-valuedness test on the gisted map,
+ * we may in rare cases fail to recognize that the inverse schedule
+ * is single-valued. This becomes problematic if this happens
+ * from the recursive call through generate_non_single_valued
+ * as we would then end up in an infinite recursion.
+ * We therefore check if we are inside a call to generate_non_single_valued
+ * and revert to the ungisted map if the gisted map turns out not to be
+ * single-valued.
*
* Otherwise, we generate a call expression for the single executed
* domain element and put a guard around it based on the (simplified)
goto error;
if (!sv) {
isl_map_free(map);
- return generate_non_single_valued(executed, data);
+ if (data->build->single_valued)
+ map = isl_map_copy(executed);
+ else
+ return generate_non_single_valued(executed, data);
}
guard = isl_map_domain(isl_map_copy(map));
guard = isl_set_coalesce(guard);
return data.list;
}
+/* Call the before_each_for callback, if requested by the user.
+ */
+static __isl_give isl_ast_node *before_each_for(__isl_take isl_ast_node *node,
+ __isl_keep isl_ast_build *build)
+{
+ isl_id *id;
+
+ if (!node || !build)
+ return isl_ast_node_free(node);
+ if (!build->before_each_for)
+ return node;
+ id = build->before_each_for(build, build->before_each_for_user);
+ node = isl_ast_node_set_annotation(node, id);
+ return node;
+}
+
+/* Call the after_each_for callback, if requested by the user.
+ */
+static __isl_give isl_ast_graft *after_each_for(__isl_keep isl_ast_graft *graft,
+ __isl_keep isl_ast_build *build)
+{
+ if (!graft || !build)
+ return isl_ast_graft_free(graft);
+ if (!build->after_each_for)
+ return graft;
+ graft->node = build->after_each_for(graft->node, build,
+ build->after_each_for_user);
+ if (!graft->node)
+ return isl_ast_graft_free(graft);
+ return graft;
+}
+
/* Eliminate the schedule dimension "pos" from "executed" and return
* the result.
*/
isl_ctx *ctx;
isl_ast_expr *inc;
+ if (!build)
+ return NULL;
ctx = isl_ast_build_get_ctx(build);
depth = isl_ast_build_get_depth(build);
* we performed separation with explicit bounds.
* The very first step is then to copy these constraints to "bounds".
*
+ * Since we may be calling before_each_for and after_each_for
+ * callbacks, we record the current inverse schedule in the build.
+ *
* We consider three builds,
* "build" is the one in which the current level is created,
* "body_build" is the build in which the next level is created,
domain = isl_set_detect_equalities(domain);
hull = isl_set_unshifted_simple_hull(isl_set_copy(domain));
bounds = isl_basic_set_intersect(bounds, hull);
+ build = isl_ast_build_set_executed(build, isl_union_map_copy(executed));
depth = isl_ast_build_get_depth(build);
sub_build = isl_ast_build_copy(build);
body_build = isl_ast_build_copy(sub_build);
body_build = isl_ast_build_increase_depth(body_build);
+ if (!eliminated)
+ node = before_each_for(node, body_build);
children = generate_next_level(executed,
isl_ast_build_copy(body_build));
graft = refine_degenerate(graft, bounds, build, sub_build);
else
graft = refine_generic(graft, bounds, domain, build);
+ if (!eliminated)
+ graft = after_each_for(graft, body_build);
isl_ast_build_free(body_build);
isl_ast_build_free(sub_build);
if (isl_aff_get_denominator(offset, &data.d) < 0)
executed = isl_union_map_free(executed);
- if (isl_int_is_divisible_by(data.m, data.d))
+ if (executed && isl_int_is_divisible_by(data.m, data.d))
isl_int_divexact(data.m, data.m, data.d);
else
isl_int_set_si(data.m, 1);
data.depth = isl_ast_build_get_depth(build);
data.piece = domain_list->p;
g = isl_tarjan_graph_init(ctx, n, &domain_follows_at_depth, &data);
+ if (!g)
+ goto error;
i = 0;
while (list && n) {
class_set = isl_set_from_point(pnt);
domain = isl_map_domain(isl_map_intersect_range(
isl_map_copy(domains->sep_class), class_set));
+ domain = isl_ast_build_compute_gist(domains->build, domain);
domain = isl_ast_build_eliminate(domains->build, domain);
disjoint = isl_set_plain_is_disjoint(domain, domains->schedule_domain);
enum isl_ast_build_domain_type type;
int empty;
+ if (!executed)
+ return NULL;
+
ctx = isl_union_map_get_ctx(executed);
domains.list = isl_basic_set_list_alloc(ctx, 0);
isl_ast_node *node;
isl_union_map *executed;
+ build = isl_ast_build_copy(build);
+ build = isl_ast_build_set_single_valued(build, 0);
executed = isl_union_map_reverse(schedule);
list = generate_code(executed, isl_ast_build_copy(build), 0);
node = isl_ast_node_from_graft_list(list, build);
+ isl_ast_build_free(build);
return node;
}