* Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
*/
+#include <limits.h>
#include <isl/aff.h>
#include <isl/set.h>
#include <isl/ilp.h>
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);
children = generate_next_level(executed,
isl_ast_build_copy(body_build));
- graft = isl_ast_graft_alloc_level(children, sub_build);
+ graft = isl_ast_graft_alloc_level(children, build, sub_build);
if (!eliminated)
graft = isl_ast_graft_insert_for(graft, node);
if (eliminated)
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) {
* of domains that share some values of the outer dimensions.
* That is, domains in different components do not share any values
* of the outer dimensions. This means that these components
- * can be freely reorderd.
+ * can be freely reordered.
* Within each of the components, we sort the domains according
* to the execution order at the current depth.
*
if (n > 0)
list = isl_ast_graft_list_free(list);
- list = isl_ast_graft_list_sort(list);
+ list = isl_ast_graft_list_sort_guard(list);
isl_tarjan_graph_free(g);
return 0;
}
- if (!data->lower || isl_int_cmp_si(data->tmp, *data->n) < 0) {
+ if (isl_int_cmp_si(data->tmp, INT_MAX) <= 0 &&
+ (!data->lower || isl_int_cmp_si(data->tmp, *data->n) < 0)) {
isl_aff_free(data->lower);
data->lower = lower;
*data->n = isl_int_get_si(data->tmp);
return isl_aff_free(data.lower);
}
-/* Intersect "set" with the constraint
+/* Return the constraint
*
* i_"depth" = aff + offset
*/
-static __isl_give isl_set *at_offset(__isl_take isl_set *set, int depth,
- __isl_keep isl_aff *aff, int offset)
+static __isl_give isl_constraint *at_offset(int depth, __isl_keep isl_aff *aff,
+ int offset)
{
- isl_constraint *eq;
-
aff = isl_aff_copy(aff);
aff = isl_aff_add_coefficient_si(aff, isl_dim_in, depth, -1);
aff = isl_aff_add_constant_si(aff, offset);
- eq = isl_equality_from_aff(aff);
- set = isl_set_add_constraint(set, eq);
-
- return set;
+ return isl_equality_from_aff(aff);
}
/* Return a list of basic sets, one for each value of the current dimension
*
* We compute the unshifted simple hull of each slice to ensure that
* we have a single basic set per offset. The slicing constraint
- * is preserved by taking the unshifted simple hull, so these basic sets
+ * may get simplified away before the unshifted simple hull is taken
+ * and may therefore in some rare cases disappear from the result.
+ * We therefore explicitly add the constraint back after computing
+ * the unshifted simple hull to ensure that the basic sets
* remain disjoint. The constraints that are dropped by taking the hull
* will be taken into account at the next level, as in the case of the
* atomic option.
for (i = 0; list && i < n; ++i) {
isl_set *set;
isl_basic_set *bset;
+ isl_constraint *slice;
- set = at_offset(isl_set_copy(domain), depth, lower, i);
+ slice = at_offset(depth, lower, i);
+ set = isl_set_copy(domain);
+ set = isl_set_add_constraint(set, isl_constraint_copy(slice));
bset = isl_set_unshifted_simple_hull(set);
+ bset = isl_basic_set_add_constraint(bset, slice);
bset = isl_basic_set_apply(bset, isl_basic_map_copy(bmap));
list = isl_basic_set_list_add(list, bset);
}
*
* "sep_class" contains the user-specified split into separation classes
* specialized to the current depth.
- * "done" contains the union of th separation domains that have already
+ * "done" contains the union of the separation domains that have already
* been handled.
+ * "atomic" contains the domain that has effectively been made atomic.
+ * This domain may be larger than the intersection of option[atomic]
+ * and the schedule domain.
*/
struct isl_codegen_domains {
isl_basic_set_list *list;
isl_map *sep_class;
isl_set *done;
+ isl_set *atomic;
};
/* Add domains to domains->list for each individual value of the current
/* Construct a single basic set that includes the intersection of
* the schedule domain, the atomic option domain and the class domain.
- * Add the resulting basic set to domains->list.
+ * Add the resulting basic set to domains->list and save a copy
+ * in domains->atomic for use in compute_partial_domains.
*
* We construct a single domain rather than trying to combine
* the schedule domains of individual domains because we are working
atomic_domain = isl_set_intersect(atomic_domain, isl_set_copy(domain));
empty = isl_set_is_empty(atomic_domain);
if (empty < 0 || empty) {
- isl_set_free(atomic_domain);
+ domains->atomic = atomic_domain;
return empty < 0 ? -1 : 0;
}
atomic_domain = isl_set_coalesce(atomic_domain);
bset = isl_set_unshifted_simple_hull(atomic_domain);
+ domains->atomic = isl_set_from_basic_set(isl_basic_set_copy(bset));
domains->list = isl_basic_set_list_add(domains->list, bset);
return 0;
* the result with the current "class_domain" to ensure that the domains
* are disjoint from those generated from other class domains.
*
+ * The domain that has been made atomic may be larger than specified
+ * by the user since it needs to be representable as a single basic set.
+ * This possibly larger domain is stored in domains->atomic by
+ * compute_atomic_domain.
+ *
* If anything is left after handling separate, unroll and atomic,
* we split it up into basic sets and append the basic sets to domains->list.
*/
domain = isl_set_intersect(domain, isl_set_copy(class_domain));
if (compute_atomic_domain(domains, domain) < 0)
- goto error;
- domain = isl_set_subtract(domain,
- isl_set_copy(domains->option[atomic]));
+ domain = isl_set_free(domain);
+ domain = isl_set_subtract(domain, domains->atomic);
domain = isl_set_coalesce(domain);
domain = isl_set_make_disjoint(domain);
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;
}