+version: 0.11.2
+date: Tue Apr 9 18:45:10 CEST 2013
+changes:
+ - make code generation output the same on Solaris
+ - fix some hard to trigger bugs
+---
version: 0.11.1
date: Mon Dec 10 11:55:30 CET 2012
changes:
- fix several hard to trigger bugs
- improved argument parsing
- support parametric vertex enumeration for barvinok
----
-version: 0.08
-date: Fri Oct 21 12:36:20 CEST 2011
-changes:
- optionally use Bernstein expansion to compute bounds
doc/mypod2latex \
doc/manual.tex \
doc/user.pod \
+ interface/all.h \
+ interface/isl.py.top \
test_inputs
dist-hook:
-AC_INIT([isl], [0.11.1], [isl-development@googlegroups.com])
+AC_INIT([isl], [0.11.2], [isl-development@googlegroups.com])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
AC_SUBST(versioninfo)
-versioninfo=11:1:1
+versioninfo=11:2:1
if test "x$prefix" != "xNONE"; then
prefix_wd=`cd $prefix && pwd`
* 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>
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);
* specialized to the current depth.
* "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);
res = isl_basic_map_set_rational(res);
if (isl_basic_map_plain_is_empty(bmap)) {
isl_basic_map_free(bmap);
+ free(dim_map);
return isl_basic_map_set_to_empty(res);
}
res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
return schedule ? isl_space_get_ctx(schedule->dim) : NULL;
}
+/* Set max_out to the maximal number of output dimensions over
+ * all maps.
+ */
+static int update_max_out(__isl_take isl_map *map, void *user)
+{
+ int *max_out = user;
+ int n_out = isl_map_dim(map, isl_dim_out);
+
+ if (n_out > *max_out)
+ *max_out = n_out;
+
+ isl_map_free(map);
+ return 0;
+}
+
+/* Internal data structure for map_pad_range.
+ *
+ * "max_out" is the maximal schedule dimension.
+ * "res" collects the results.
+ */
+struct isl_pad_schedule_map_data {
+ int max_out;
+ isl_union_map *res;
+};
+
+/* Pad the range of the given map with zeros to data->max_out and
+ * then add the result to data->res.
+ */
+static int map_pad_range(__isl_take isl_map *map, void *user)
+{
+ struct isl_pad_schedule_map_data *data = user;
+ int i;
+ int n_out = isl_map_dim(map, isl_dim_out);
+
+ map = isl_map_add_dims(map, isl_dim_out, data->max_out - n_out);
+ for (i = n_out; i < data->max_out; ++i)
+ map = isl_map_fix_si(map, isl_dim_out, i, 0);
+
+ data->res = isl_union_map_add_map(data->res, map);
+ if (!data->res)
+ return -1;
+
+ return 0;
+}
+
+/* Pad the ranges of the maps in the union map with zeros such they all have
+ * the same dimension.
+ */
+static __isl_give isl_union_map *pad_schedule_map(
+ __isl_take isl_union_map *umap)
+{
+ struct isl_pad_schedule_map_data data;
+
+ if (!umap)
+ return NULL;
+ if (isl_union_map_n_map(umap) <= 1)
+ return umap;
+
+ data.max_out = 0;
+ if (isl_union_map_foreach_map(umap, &update_max_out, &data.max_out) < 0)
+ return isl_union_map_free(umap);
+
+ data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+ if (isl_union_map_foreach_map(umap, &map_pad_range, &data) < 0)
+ data.res = isl_union_map_free(data.res);
+
+ isl_union_map_free(umap);
+ return data.res;
+}
+
/* Return an isl_union_map of the schedule. If we have already constructed
* a band forest, then this band forest may have been modified so we need
* to extract the isl_union_map from the forest rather than from
- * the originally computed schedule.
+ * the originally computed schedule. This reconstructed schedule map
+ * then needs to be padded with zeros to unify the schedule space
+ * since the result of isl_band_list_get_suffix_schedule may not have
+ * a unified schedule space.
*/
__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
{
if (!sched)
return NULL;
- if (sched->band_forest)
- return isl_band_list_get_suffix_schedule(sched->band_forest);
+ if (sched->band_forest) {
+ umap = isl_band_list_get_suffix_schedule(sched->band_forest);
+ return pad_schedule_map(umap);
+ }
umap = isl_union_map_empty(isl_space_copy(sched->dim));
for (i = 0; i < sched->n; ++i) {
return 0;
}
+/* Check that the schedule map is properly padded, even after being
+ * reconstructed from the band forest.
+ */
+static int test_padded_schedule(isl_ctx *ctx)
+{
+ const char *str;
+ isl_union_set *D;
+ isl_union_map *validity, *proximity;
+ isl_schedule *sched;
+ isl_union_map *map1, *map2;
+ isl_band_list *list;
+ int equal;
+
+ str = "[N] -> { S0[i] : 0 <= i <= N; S1[i, j] : 0 <= i, j <= N }";
+ D = isl_union_set_read_from_str(ctx, str);
+ validity = isl_union_map_empty(isl_union_set_get_space(D));
+ proximity = isl_union_map_copy(validity);
+ sched = isl_union_set_compute_schedule(D, validity, proximity);
+ map1 = isl_schedule_get_map(sched);
+ list = isl_schedule_get_band_forest(sched);
+ isl_band_list_free(list);
+ map2 = isl_schedule_get_map(sched);
+ isl_schedule_free(sched);
+ equal = isl_union_map_is_equal(map1, map2);
+ isl_union_map_free(map1);
+ isl_union_map_free(map2);
+
+ if (equal < 0)
+ return -1;
+ if (!equal)
+ isl_die(ctx, isl_error_unknown,
+ "reconstructed schedule map not the same as original",
+ return -1);
+
+ return 0;
+}
+
int test_schedule(isl_ctx *ctx)
{
const char *D, *W, *R, *V, *P, *S;
if (test_has_schedule(ctx, D, V, P) < 0)
return -1;
+ if (test_padded_schedule(ctx) < 0)
+ return -1;
+
return 0;
}
--- /dev/null
+for (int c0 = ((b0 + 32767) % 32768) + 1; c0 <= 65534; c0 += 32768)
+ A(c0);
--- /dev/null
+# Check that isl properly handles atomic domains that are unions.
+[nn, b0] -> { A[a] -> [a, 0, b0] : exists (e0 = [(b0 - a)/32768]: 32768e0 = b0 - a and a >= 1 and b0 >= 0 and b0 <= 32767 and a <= 65534) }
+[nn, b0] -> { : b0 >= 0 and b0 <= 32767 }
+[nn, b0] -> { [a, b, c] -> atomic[2] : c >= 1; [a, 0, c] -> atomic[2] }
--- /dev/null
+{
+ if (((-t1 + 128) % 128) + nn >= 128 * g + 130 && 128 * g + 127 >= (-t1 + 128) % 128 && nn >= 128 * g + 6)
+ for (int c1 = 393214; c1 < nn - 1; c1 += 393216)
+ A(c1, ((t1 + 127) % 128) + 128 * g + 1, ((t1 + 127) % 128) + 1);
+ if (nn >= t1 + 128 * g + 130 && t1 + 128 * g + 127 >= 0 && t1 <= 2 && t1 >= 1)
+ for (int c1 = 393214; c1 < nn - 1; c1 += 393216)
+ A(c1, t1 + 128 * g + 128, t1 + 128);
+}
--- /dev/null
+# Check that the right lower bound is chosen for unrolling.
+# Older versions of isl would pick a lower bound that resulted
+# in a number of slices that exceeds the maximal value of an integer
+# and then only generated code for a truncated number (zero) of slices.
+[nn, t1, g] -> { A[a, b, c] -> [c] : exists (e0 = [(2 + a)/393216], e1 = [(t1 - c)/128]: 128g = b - c and 393216e0 = 2 + a and 128e1 = t1 - c and c <= 130 and c >= 6 - nn + b and c <= 128 + b and nn >= 137 and t1 >= 0 and c >= 1 and a <= -2 + nn and a >= 1 and nn <= 9223372036854775807 and b >= 1 and b <= -2 + nn and t1 <= 127) }
+[nn, t1, g] -> { : nn <= 9223372036854775807 and nn >= 137 and t1 >= 0 and t1 <= 127 }
+{ [c] -> unroll[x] }