Merge branch 'maint'
authorSven Verdoolaege <skimo@kotnet.org>
Wed, 22 May 2013 10:28:26 +0000 (12:28 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Wed, 22 May 2013 10:28:26 +0000 (12:28 +0200)
80 files changed:
Makefile.am
bound.c
codegen_test.sh.in
configure.ac
doc/user.pod
include/isl/aff.h
include/isl/aff_type.h
include/isl/ast_build.h
include/isl/band.h
include/isl/constraint.h
include/isl/ctx.h
include/isl/id.h
include/isl/int.h
include/isl/list.h
include/isl/map.h
include/isl/map_type.h
include/isl/mat.h
include/isl/multi.h
include/isl/set.h
include/isl/union_map.h
isl_aff.c
isl_aff_private.h
isl_affine_hull.c
isl_arg.c
isl_ast.c
isl_ast_build.c
isl_ast_build_expr.c
isl_ast_build_private.h
isl_ast_codegen.c
isl_ast_graft.c
isl_ast_graft_private.h
isl_band.c
isl_band_private.h
isl_coalesce.c
isl_constraint.c
isl_constraint_private.h
isl_ctx.c
isl_equalities.c
isl_equalities.h
isl_fold.c
isl_id.c
isl_id_private.h
isl_input.c
isl_list.c [deleted file]
isl_list_private.h [deleted file]
isl_list_templ.c
isl_list_templ.h
isl_local_space.c
isl_map.c
isl_map_lexopt_templ.c
isl_map_private.h
isl_map_simplify.c
isl_mat.c
isl_morph.c
isl_multi_templ.c
isl_multi_templ.h
isl_options.c
isl_options_private.h
isl_polynomial.c
isl_schedule.c
isl_set_list.c [new file with mode: 0644]
isl_space.c
isl_space_private.h
isl_tab.c
isl_tab.h
isl_tab_pip.c
isl_test.c
isl_union_map.c
isl_union_templ.c
m4/ax_create_pkgconfig_info.m4
test_inputs/codegen/cloog/thomasset.c
test_inputs/codegen/hoist2.c
test_inputs/codegen/omega/floor_bound-6.c
test_inputs/codegen/omega/lefur04-0.c
test_inputs/codegen/omega/p.delft2-0.c
test_inputs/codegen/separation_class2.c
test_inputs/codegen/single_valued.c
test_inputs/codegen/stride6.c [new file with mode: 0644]
test_inputs/codegen/stride6.in [new file with mode: 0644]
test_inputs/codegen/unroll4.c

index 7218498..055cbc5 100644 (file)
@@ -83,8 +83,6 @@ libisl_la_SOURCES = \
        isl_hmap_map_basic_set.h \
        isl_ilp.c \
        isl_input.c \
-       isl_list.c \
-       isl_list_private.h \
        isl_local_space_private.h \
        isl_local_space.c \
        isl_lp.c \
@@ -122,6 +120,7 @@ libisl_la_SOURCES = \
        isl_scan.h \
        isl_schedule.c \
        isl_schedule_private.h \
+       isl_set_list.c \
        isl_sort.c \
        isl_sort.h \
        isl_space.c \
diff --git a/bound.c b/bound.c
index a0772b7..9a0ee8d 100644 (file)
--- a/bound.c
+++ b/bound.c
@@ -62,10 +62,12 @@ static int verify_point(__isl_take isl_point *pnt, void *user)
        unsigned nparam;
        struct verify_point_bound *vpb = (struct verify_point_bound *) user;
        isl_int t;
+       isl_ctx *ctx;
        isl_pw_qpolynomial_fold *pwf;
        isl_qpolynomial *bound = NULL;
        isl_qpolynomial *opt = NULL;
        isl_set *dom = NULL;
+       isl_printer *p;
        const char *minmax;
        int bounded;
        int sign;
@@ -82,6 +84,9 @@ static int verify_point(__isl_take isl_point *pnt, void *user)
                sign = -1;
        }
 
+       ctx = isl_point_get_ctx(pnt);
+       p = isl_printer_to_file(ctx, out);
+
        isl_int_init(t);
 
        pwf = isl_pw_qpolynomial_fold_copy(vpb->pwf);
@@ -123,24 +128,28 @@ static int verify_point(__isl_take isl_point *pnt, void *user)
                goto error;
 
        if (vpb->options->print_all || !ok) {
-               fprintf(out, "%s(", minmax);
+               p = isl_printer_print_str(p, minmax);
+               p = isl_printer_print_str(p, "(");
                for (i = 0; i < nparam; ++i) {
                        if (i)
-                               fprintf(out, ", ");
+                               p = isl_printer_print_str(p, ", ");
                        isl_point_get_coordinate(pnt, isl_dim_param, i, &t);
-                       isl_int_print(out, t, 0);
+                       p = isl_printer_print_isl_int(p, t);
                }
-               fprintf(out, ") = ");
-               isl_qpolynomial_print(bound, out, ISL_FORMAT_ISL);
-               fprintf(out, ", %s = ", bounded ? "opt" : "sample");
-               isl_qpolynomial_print(opt, out, ISL_FORMAT_ISL);
+               p = isl_printer_print_str(p, ") = ");
+               p = isl_printer_print_qpolynomial(p, bound);
+               p = isl_printer_print_str(p, ", ");
+               p = isl_printer_print_str(p, bounded ? "opt" : "sample");
+               p = isl_printer_print_str(p, " = ");
+               p = isl_printer_print_qpolynomial(p, opt);
                if (ok)
-                       fprintf(out, ". OK\n");
+                       p = isl_printer_print_str(p, ". OK");
                else
-                       fprintf(out, ". NOT OK\n");
+                       p = isl_printer_print_str(p, ". NOT OK");
+               p = isl_printer_end_line(p);
        } else if ((vpb->n % vpb->stride) == 0) {
-               printf("o");
-               fflush(stdout);
+               p = isl_printer_print_str(p, "o");
+               p = isl_printer_flush(p);
        }
 
        if (0) {
@@ -156,6 +165,8 @@ error:
 
        isl_int_clear(t);
 
+       isl_printer_free(p);
+
        if (!ok)
                vpb->error = 1;
 
index dd0c488..36a1815 100644 (file)
@@ -3,6 +3,8 @@
 EXEEXT=@EXEEXT@
 srcdir=@srcdir@
 
+failed=0
+
 for i in $srcdir/test_inputs/codegen/*.in \
                $srcdir/test_inputs/codegen/cloog/*.in \
                $srcdir/test_inputs/codegen/omega/*.in \
@@ -13,5 +15,7 @@ for i in $srcdir/test_inputs/codegen/*.in \
        dir=`dirname $i`
        ref=$dir/$base.c
        (./isl_codegen$EXEEXT < $i > $test &&
-        diff -uw $ref $test && rm $test) || exit
+        diff -uw $ref $test && rm $test) || failed=1
 done
+
+test $failed -eq 0 || exit
index 3213de0..bb19dde 100644 (file)
@@ -48,6 +48,22 @@ system)
                GMP_LDFLAGS="-L$with_gmp_prefix/lib"
        fi
        GMP_LIBS=-lgmp
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+       SAVE_LIBS="$LIBS"
+       CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
+       LDFLAGS="$GMP_LDFLAGS $LDFLAGS"
+       LIBS="$GMP_LIBS $LIBS"
+       AC_CHECK_HEADER([gmp.h], [], [AC_ERROR([gmp.h header not found])])
+       AC_CHECK_LIB([gmp], [main], [], [AC_ERROR([gmp library not found])])
+       AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gmp.h>]], [[
+               mpz_t n, d;
+               if (mpz_divisible_p(n, d))
+                       mpz_divexact_ui(n, n, 4);
+       ]])], [], [AC_ERROR([gmp library too old])])
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
+       LIBS="$SAVE_LIBS"
        ;;
 build)
        GMP_CPPFLAGS="-I$gmp_srcdir -I$with_gmp_builddir"
index 950f93c..2278000 100644 (file)
@@ -950,6 +950,9 @@ They can be inspected, modified, copied and freed using the following functions.
                __isl_keep isl_local_space *ls);
        void *isl_local_space_free(__isl_take isl_local_space *ls);
 
+Note that C<isl_local_space_get_div> can only be used on local spaces
+of sets.
+
 Two local spaces can be compared using
 
        int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
@@ -2162,6 +2165,10 @@ dimensions have opposite values.
        __isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
                enum isl_dim_type type1, int pos1,
                enum isl_dim_type type2, int pos2);
+       __isl_give isl_basic_map *isl_basic_map_order_gt(
+               __isl_take isl_basic_map *bmap,
+               enum isl_dim_type type1, int pos1,
+               enum isl_dim_type type2, int pos2);
        __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
                enum isl_dim_type type1, int pos1,
                enum isl_dim_type type2, int pos2);
@@ -2332,6 +2339,11 @@ per space.
                __isl_take isl_basic_set *bset,
                enum isl_dim_type type,
                unsigned first, unsigned n);
+       __isl_give isl_basic_map *
+       isl_basic_map_drop_constraints_involving_dims(
+               __isl_take isl_basic_map *bmap,
+               enum isl_dim_type type,
+               unsigned first, unsigned n);
        __isl_give isl_basic_set *
        isl_basic_set_drop_constraints_not_involving_dims(
                __isl_take isl_basic_set *bset,
@@ -2809,10 +2821,17 @@ a parametric set as well.
        __isl_give isl_set *isl_set_preimage_pw_multi_aff(
                __isl_take isl_set *set,
                __isl_take isl_pw_multi_aff *pma);
+       __isl_give isl_map *isl_map_preimage_domain_multi_aff(
+               __isl_take isl_map *map,
+               __isl_take isl_multi_aff *ma);
+       __isl_give isl_union_map *
+       isl_union_map_preimage_domain_multi_aff(
+               __isl_take isl_union_map *umap,
+               __isl_take isl_multi_aff *ma);
 
-These functions compute the preimage of the given set under
+These functions compute the preimage of the given set or map domain under
 the given function.  In other words, the expression is plugged
-into the set description.
+into the set description or into the domain of the map.
 Objects of types C<isl_multi_aff> and C<isl_pw_multi_aff> are described in
 L</"Piecewise Multiple Quasi Affine Expressions">.
 
@@ -3058,6 +3077,10 @@ returning a basic set or relation.
                __isl_take isl_basic_map *bmap,
                __isl_take isl_basic_set *dom,
                __isl_give isl_set **empty);
+       __isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff(
+               __isl_take isl_set *set);
+       __isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff(
+               __isl_take isl_set *set);
        __isl_give isl_pw_multi_aff *isl_map_lexmin_pw_multi_aff(
                __isl_take isl_map *map);
        __isl_give isl_pw_multi_aff *isl_map_lexmax_pw_multi_aff(
@@ -3093,6 +3116,11 @@ Lists can be created, copied, modified and freed using the following functions.
        __isl_give isl_set_list *isl_set_list_concat(
                __isl_take isl_set_list *list1,
                __isl_take isl_set_list *list2);
+       __isl_give isl_set_list *isl_set_list_sort(
+               __isl_take isl_set_list *list,
+               int (*cmp)(__isl_keep isl_set *a,
+                       __isl_keep isl_set *b, void *user),
+               void *user);
        void *isl_set_list_free(__isl_take isl_set_list *list);
 
 C<isl_set_list_alloc> creates an empty list with a capacity for
@@ -3109,6 +3137,18 @@ Lists can be inspected using the following functions.
        int isl_set_list_foreach(__isl_keep isl_set_list *list,
                int (*fn)(__isl_take isl_set *el, void *user),
                void *user);
+       int isl_set_list_foreach_scc(__isl_keep isl_set_list *list,
+               int (*follows)(__isl_keep isl_set *a,
+                       __isl_keep isl_set *b, void *user),
+               void *follows_user
+               int (*fn)(__isl_take isl_set *el, void *user),
+               void *fn_user);
+
+The function C<isl_set_list_foreach_scc> calls C<fn> on each of the
+strongly connected components of the graph with as vertices the elements
+of C<list> and a directed edge from vertex C<b> to vertex C<a>
+iff C<follows(a, b)> returns C<1>.  The callbacks C<follows> and C<fn>
+should return C<-1> on error.
 
 Lists can be printed using
 
@@ -3161,7 +3201,7 @@ Matrices can be created, copied and freed using the following functions.
        __isl_give isl_mat *isl_mat_alloc(isl_ctx *ctx,
                unsigned n_row, unsigned n_col);
        __isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat);
-       void isl_mat_free(__isl_take isl_mat *mat);
+       void *isl_mat_free(__isl_take isl_mat *mat);
 
 Note that the elements of a newly created matrix may have arbitrary values.
 The elements can be changed and inspected using the following functions.
@@ -3704,12 +3744,21 @@ can be created using the following functions.
 A piecewise multiple quasi affine expression can also be initialized
 from an C<isl_set> or C<isl_map>, provided the C<isl_set> is a singleton
 and the C<isl_map> is single-valued.
+In case of a conversion from an C<isl_union_set> or an C<isl_union_map>
+to an C<isl_union_pw_multi_aff>, these properties need to hold in each space.
 
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(
                __isl_take isl_set *set);
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(
                __isl_take isl_map *map);
 
+       __isl_give isl_union_pw_multi_aff *
+       isl_union_pw_multi_aff_from_union_set(
+               __isl_take isl_union_set *uset);
+       __isl_give isl_union_pw_multi_aff *
+       isl_union_pw_multi_aff_from_union_map(
+               __isl_take isl_union_map *umap);
+
 Multiple quasi affine expressions can be copied and freed using
 
        #include <isl/aff.h>
@@ -3872,15 +3921,44 @@ Operations include
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
                __isl_take isl_pw_multi_aff *pma1,
                __isl_take isl_pw_multi_aff *pma2);
+       __isl_give isl_multi_aff *isl_multi_aff_sub(
+               __isl_take isl_multi_aff *ma1,
+               __isl_take isl_multi_aff *ma2);
+       __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+               __isl_take isl_pw_multi_aff *pma1,
+               __isl_take isl_pw_multi_aff *pma2);
+       __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub(
+               __isl_take isl_union_pw_multi_aff *upma1,
+               __isl_take isl_union_pw_multi_aff *upma2);
+
+C<isl_multi_aff_sub> subtracts the second argument from the first.
+
        __isl_give isl_multi_aff *isl_multi_aff_scale(
                __isl_take isl_multi_aff *maff,
                isl_int f);
+       __isl_give isl_multi_aff *isl_multi_aff_scale_vec(
+               __isl_take isl_multi_aff *ma,
+               __isl_take isl_vec *v);
+       __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_vec(
+               __isl_take isl_pw_multi_aff *pma,
+               __isl_take isl_vec *v);
+       __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_vec(
+               __isl_take isl_union_pw_multi_aff *upma,
+               __isl_take isl_vec *v);
+
+C<isl_multi_aff_scale_vec> scales the first elements of C<ma>
+by the corresponding elements of C<v>.
+
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_params(
                __isl_take isl_pw_multi_aff *pma,
                __isl_take isl_set *set);
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_domain(
                __isl_take isl_pw_multi_aff *pma,
                __isl_take isl_set *set);
+       __isl_give isl_union_pw_multi_aff *
+       isl_union_pw_multi_aff_intersect_domain(
+               __isl_take isl_union_pw_multi_aff *upma,
+               __isl_take isl_union_set *uset);
        __isl_give isl_multi_aff *isl_multi_aff_lift(
                __isl_take isl_multi_aff *maff,
                __isl_give isl_local_space **ls);
@@ -3999,6 +4077,9 @@ An expression can be read from input using
                isl_ctx *ctx, const char *str);
        __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(
                isl_ctx *ctx, const char *str);
+       __isl_give isl_union_pw_multi_aff *
+       isl_union_pw_multi_aff_read_from_str(
+               isl_ctx *ctx, const char *str);
 
 An expression can be printed using
 
@@ -5071,6 +5152,9 @@ A band can be tiled using the following function.
        int isl_options_set_tile_scale_tile_loops(isl_ctx *ctx,
                int val);
        int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
+       int isl_options_set_tile_shift_point_loops(isl_ctx *ctx,
+               int val);
+       int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
 
 The C<isl_band_tile> function tiles the band using the given tile sizes
 inside its schedule.
@@ -5078,6 +5162,15 @@ A new child band is created to represent the point loops and it is
 inserted between the modified band and its children.
 The C<tile_scale_tile_loops> option specifies whether the tile
 loops iterators should be scaled by the tile sizes.
+If the C<tile_shift_point_loops> option is set, then the point loops
+are shifted to start at zero.
+
+A band can be split into two nested bands using the following function.
+
+       int isl_band_split(__isl_keep isl_band *band, int pos);
+
+The resulting outer band contains the first C<pos> dimensions of C<band>
+while the inner band contains the remaining dimensions.
 
 A representation of the band can be printed using
 
@@ -5642,6 +5735,9 @@ while printing the AST.
        int isl_options_set_ast_build_allow_else(isl_ctx *ctx,
                int val);
        int isl_options_get_ast_build_allow_else(isl_ctx *ctx);
+       int isl_options_set_ast_build_allow_or(isl_ctx *ctx,
+               int val);
+       int isl_options_get_ast_build_allow_or(isl_ctx *ctx);
 
 =over
 
@@ -5740,6 +5836,11 @@ to scale down iterators of strided loops.
 This option specifies whether the AST generator is allowed
 to construct if statements with else branches.
 
+=item * ast_build_allow_or
+
+This option specifies whether the AST generator is allowed
+to construct if conditions with disjunctions.
+
 =back
 
 =head3 Fine-grained Control over AST Generation
index a8e16c8..b86b304 100644 (file)
@@ -8,6 +8,7 @@
 #include <isl/list.h>
 #include <isl/multi.h>
 #include <isl/union_set_type.h>
+#include <isl/vec.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -270,60 +271,24 @@ __isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1,
 __isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1,
        __isl_take isl_pw_aff_list *list2);
 
+ISL_DECLARE_MULTI(aff)
+
 __isl_give isl_multi_aff *isl_multi_aff_from_aff(__isl_take isl_aff *aff);
-__isl_give isl_multi_aff *isl_multi_aff_zero(__isl_take isl_space *space);
 __isl_give isl_multi_aff *isl_multi_aff_identity(__isl_take isl_space *space);
 
-isl_ctx *isl_multi_aff_get_ctx(__isl_keep isl_multi_aff *maff);
-__isl_give isl_space *isl_multi_aff_get_space(__isl_keep isl_multi_aff *maff);
-__isl_give isl_space *isl_multi_aff_get_domain_space(
-       __isl_keep isl_multi_aff *maff);
-__isl_give isl_multi_aff *isl_multi_aff_set_tuple_name(
-       __isl_take isl_multi_aff *maff,
-       enum isl_dim_type type, const char *s);
-__isl_give isl_multi_aff *isl_multi_aff_set_tuple_id(
-       __isl_take isl_multi_aff *maff,
-       enum isl_dim_type type, __isl_take isl_id *id);
-__isl_give isl_multi_aff *isl_multi_aff_copy(__isl_keep isl_multi_aff *maff);
-void *isl_multi_aff_free(__isl_take isl_multi_aff *maff);
-
-unsigned isl_multi_aff_dim(__isl_keep isl_multi_aff *maff,
-       enum isl_dim_type type);
-__isl_give isl_aff *isl_multi_aff_get_aff(__isl_keep isl_multi_aff *multi,
-       int pos);
-
-__isl_give isl_multi_aff *isl_multi_aff_insert_dims(
-       __isl_take isl_multi_aff *ma,
-       enum isl_dim_type type, unsigned first, unsigned n);
-__isl_give isl_multi_aff *isl_multi_aff_add_dims(__isl_take isl_multi_aff *ma,
-       enum isl_dim_type type, unsigned n);
-__isl_give isl_multi_aff *isl_multi_aff_drop_dims(
-       __isl_take isl_multi_aff *maff,
-       enum isl_dim_type type, unsigned first, unsigned n);
-
-__isl_give isl_multi_aff *isl_multi_aff_set_dim_name(
-       __isl_take isl_multi_aff *maff,
-       enum isl_dim_type type, unsigned pos, const char *s);
-
 int isl_multi_aff_plain_is_equal(__isl_keep isl_multi_aff *maff1,
        __isl_keep isl_multi_aff *maff2);
 
 __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *maff1,
        __isl_take isl_multi_aff *maff2);
+__isl_give isl_multi_aff *isl_multi_aff_sub(__isl_take isl_multi_aff *ma1,
+       __isl_take isl_multi_aff *ma2);
 
 __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff,
        isl_int f);
+__isl_give isl_multi_aff *isl_multi_aff_scale_vec(__isl_take isl_multi_aff *ma,
+       __isl_take isl_vec *v);
 
-__isl_give isl_multi_aff *isl_multi_aff_range_splice(
-       __isl_take isl_multi_aff *ma1, unsigned pos,
-       __isl_take isl_multi_aff *ma2);
-__isl_give isl_multi_aff *isl_multi_aff_splice(
-       __isl_take isl_multi_aff *ma1, unsigned in_pos, unsigned out_pos,
-       __isl_take isl_multi_aff *ma2);
-__isl_give isl_multi_aff *isl_multi_aff_range_product(
-       __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2);
-__isl_give isl_multi_aff *isl_multi_aff_flat_range_product(
-       __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2);
 __isl_give isl_multi_aff *isl_multi_aff_product(
        __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2);
 
@@ -353,6 +318,8 @@ __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
                const char *str);
 void isl_multi_aff_dump(__isl_keep isl_multi_aff *maff);
 
+ISL_DECLARE_MULTI(pw_aff)
+
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
        __isl_take isl_space *space);
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
@@ -415,6 +382,11 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
 
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
        __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_vec(
+       __isl_take isl_pw_multi_aff *pma, __isl_take isl_vec *v);
 
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
        __isl_take isl_pw_multi_aff *pma1,
@@ -498,61 +470,43 @@ __isl_give isl_union_set *isl_union_pw_multi_aff_domain(
 __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add(
        __isl_take isl_union_pw_multi_aff *upma1,
        __isl_take isl_union_pw_multi_aff *upma2);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub(
+       __isl_take isl_union_pw_multi_aff *upma1,
+       __isl_take isl_union_pw_multi_aff *upma2);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_vec(
+       __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_vec *v);
 
 __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(
        __isl_take isl_union_pw_multi_aff *upma1,
        __isl_take isl_union_pw_multi_aff *upma2);
 
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_domain(
+       __isl_take isl_union_pw_multi_aff *upma,
+       __isl_take isl_union_set *uset);
+
 __isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff(
        __isl_take isl_union_pw_multi_aff *upma);
 
 __isl_give isl_printer *isl_printer_print_union_pw_multi_aff(
        __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma);
 
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_zero(__isl_take isl_space *space);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
+       __isl_take isl_union_set *uset);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
+       __isl_take isl_union_map *umap);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+       isl_ctx *ctx, const char *str);
+void isl_union_pw_multi_aff_dump(__isl_keep isl_union_pw_multi_aff *upma);
+__isl_give char *isl_union_pw_multi_aff_to_str(
+       __isl_keep isl_union_pw_multi_aff *upma);
+
 __isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity(
        __isl_take isl_space *space);
 __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff(
        __isl_take isl_pw_aff *pa);
 
-isl_ctx *isl_multi_pw_aff_get_ctx(__isl_keep isl_multi_pw_aff *mpa);
-__isl_give isl_space *isl_multi_pw_aff_get_space(
-       __isl_keep isl_multi_pw_aff *mpa);
-__isl_give isl_space *isl_multi_pw_aff_get_domain_space(
-       __isl_keep isl_multi_pw_aff *mpa);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_set_tuple_name(
-       __isl_take isl_multi_pw_aff *mpa,
-       enum isl_dim_type type, const char *s);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_copy(
-       __isl_keep isl_multi_pw_aff *mpa);
-void *isl_multi_pw_aff_free(__isl_take isl_multi_pw_aff *mpa);
-
-unsigned isl_multi_pw_aff_dim(__isl_keep isl_multi_pw_aff *mpa,
-       enum isl_dim_type type);
-__isl_give isl_pw_aff *isl_multi_pw_aff_get_pw_aff(
-       __isl_keep isl_multi_pw_aff *mpa, int pos);
-
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_insert_dims(
-       __isl_take isl_multi_pw_aff *mpa,
-       enum isl_dim_type type, unsigned first, unsigned n);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_add_dims(
-       __isl_take isl_multi_pw_aff *mpa, enum isl_dim_type type, unsigned n);
-
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_set_dim_name(
-       __isl_take isl_multi_pw_aff *mpa,
-       enum isl_dim_type type, unsigned pos, const char *s);
-
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_range_splice(
-       __isl_take isl_multi_pw_aff *mpa1, unsigned pos,
-       __isl_take isl_multi_pw_aff *mpa2);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_splice(
-       __isl_take isl_multi_pw_aff *mpa1, unsigned in_pos, unsigned out_pos,
-       __isl_take isl_multi_pw_aff *mpa2);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_flat_range_product(
-       __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2);
-__isl_give isl_multi_pw_aff *isl_multi_pw_aff_range_product(
-       __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2);
-
 __isl_give isl_printer *isl_printer_print_multi_pw_aff(
        __isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa);
 void isl_multi_pw_aff_dump(__isl_keep isl_multi_pw_aff *mpa);
index e5308c7..ce19f1d 100644 (file)
@@ -1,12 +1,22 @@
 #ifndef ISL_AFF_TYPE_H
 #define ISL_AFF_TYPE_H
 
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct isl_aff;
 typedef struct isl_aff isl_aff;
 
+ISL_DECLARE_LIST(aff)
+
 struct isl_pw_aff;
 typedef struct isl_pw_aff isl_pw_aff;
 
+ISL_DECLARE_LIST(pw_aff)
+
 struct isl_multi_aff;
 typedef struct isl_multi_aff isl_multi_aff;
 
@@ -19,4 +29,8 @@ typedef struct isl_union_pw_multi_aff isl_union_pw_multi_aff;
 struct isl_multi_pw_aff;
 typedef struct isl_multi_pw_aff isl_multi_pw_aff;
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
index 7294ed7..79b4e24 100644 (file)
@@ -36,6 +36,9 @@ int isl_options_get_ast_build_scale_strides(isl_ctx *ctx);
 int isl_options_set_ast_build_allow_else(isl_ctx *ctx, int val);
 int isl_options_get_ast_build_allow_else(isl_ctx *ctx);
 
+int isl_options_set_ast_build_allow_or(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_allow_or(isl_ctx *ctx);
+
 isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build);
 
 __isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set);
index e7bf51c..882393e 100644 (file)
@@ -13,6 +13,8 @@ extern "C" {
 struct isl_band;
 typedef struct isl_band isl_band;
 
+ISL_DECLARE_LIST(band)
+
 __isl_give isl_band *isl_band_copy(__isl_keep isl_band *band);
 void *isl_band_free(__isl_take isl_band *band);
 
@@ -31,8 +33,11 @@ __isl_give isl_union_map *isl_band_get_suffix_schedule(
 
 int isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, int val);
 int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
+int isl_options_set_tile_shift_point_loops(isl_ctx *ctx, int val);
+int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
 
 int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes);
+int isl_band_split(__isl_keep isl_band *band, int pos);
 
 int isl_band_n_member(__isl_keep isl_band *band);
 int isl_band_member_is_zero_distance(__isl_keep isl_band *band, int pos);
index 224e44d..131db2f 100644 (file)
@@ -14,6 +14,7 @@
 #include <isl/space.h>
 #include <isl/aff_type.h>
 #include <isl/set_type.h>
+#include <isl/list.h>
 #include <isl/printer.h>
 
 #if defined(__cplusplus)
@@ -23,6 +24,8 @@ extern "C" {
 struct isl_constraint;
 typedef struct isl_constraint isl_constraint;
 
+ISL_DECLARE_LIST(constraint)
+
 isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c);
 
 __isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls);
index 3d88697..811798e 100644 (file)
@@ -102,7 +102,7 @@ typedef struct isl_ctx isl_ctx;
  * returns the value of 'expr'. It is used to ensure, that always an isl_ctx is
  * passed to the following macros, even if they currently do not use it.
  */
-#define isl_check_ctx(ctx, expr)       ((ctx != (isl_ctx *) 0) ? expr : expr)
+#define isl_check_ctx(ctx, expr)       ((ctx != (isl_ctx *) 0) ? expr : NULL)
 
 #define isl_alloc(ctx,type,size)       ((type *)isl_check_ctx(ctx,\
                                                        malloc(size)))
index d237b23..4c457fb 100644 (file)
@@ -2,6 +2,7 @@
 #define ISL_ID_H
 
 #include <isl/ctx.h>
+#include <isl/list.h>
 #include <isl/printer.h>
 
 #if defined(__cplusplus)
@@ -11,6 +12,8 @@ extern "C" {
 struct isl_id;
 typedef struct isl_id isl_id;
 
+ISL_DECLARE_LIST(id)
+
 isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id);
 
 __isl_give isl_id *isl_id_alloc(isl_ctx *ctx,
index 9391df9..4f890f3 100644 (file)
@@ -70,6 +70,7 @@ typedef void (*isl_int_print_gmp_free_t)(void *, size_t);
 #define isl_int_submul(r,i,j)  mpz_submul(r,i,j)
 
 #define isl_int_gcd(r,i,j)     mpz_gcd(r,i,j)
+#define isl_int_gcdext(g,x,y,i,j)      mpz_gcdext(g,x,y,i,j)
 #define isl_int_lcm(r,i,j)     mpz_lcm(r,i,j)
 #define isl_int_divexact(r,i,j)        mpz_divexact(r,i,j)
 #define isl_int_divexact_ui(r,i,j)     mpz_divexact_ui(r,i,j)
index 0de7d1c..0a77241 100644 (file)
 extern "C" {
 #endif
 
-#define ISL_DECLARE_LIST(EL)                                           \
+#define ISL_DECLARE_LIST_TYPE(EL)                                      \
 struct isl_##EL;                                                       \
 struct isl_##EL##_list;                                                        \
-typedef struct isl_##EL##_list isl_##EL##_list;                                \
+typedef struct isl_##EL##_list isl_##EL##_list;
+#define ISL_DECLARE_LIST_FN(EL)                                                \
 isl_ctx *isl_##EL##_list_get_ctx(__isl_keep isl_##EL##_list *list);    \
 __isl_give isl_##EL##_list *isl_##EL##_list_from_##EL(                 \
        __isl_take struct isl_##EL *el);                                \
@@ -48,17 +49,24 @@ __isl_give struct isl_##EL##_list *isl_##EL##_list_set_##EL(                \
 int isl_##EL##_list_foreach(__isl_keep isl_##EL##_list *list,          \
        int (*fn)(__isl_take struct isl_##EL *el, void *user),          \
        void *user);                                                    \
+__isl_give isl_##EL##_list *isl_##EL##_list_sort(                      \
+       __isl_take isl_##EL##_list *list,                               \
+       int (*cmp)(__isl_keep struct isl_##EL *a,                       \
+               __isl_keep struct isl_##EL *b,                          \
+               void *user), void *user);                               \
+int isl_##EL##_list_foreach_scc(__isl_keep isl_##EL##_list *list,      \
+       int (*follows)(__isl_keep struct isl_##EL *a,                   \
+                       __isl_keep struct isl_##EL *b, void *user),     \
+       void *follows_user,                                             \
+       int (*fn)(__isl_take isl_##EL##_list *scc, void *user),         \
+       void *fn_user);                                                 \
 __isl_give isl_printer *isl_printer_print_##EL##_list(                 \
        __isl_take isl_printer *p, __isl_keep isl_##EL##_list *list);   \
 void isl_##EL##_list_dump(__isl_keep isl_##EL##_list *list);
 
-ISL_DECLARE_LIST(id)
-ISL_DECLARE_LIST(constraint)
-ISL_DECLARE_LIST(basic_set)
-ISL_DECLARE_LIST(set)
-ISL_DECLARE_LIST(aff)
-ISL_DECLARE_LIST(pw_aff)
-ISL_DECLARE_LIST(band)
+#define ISL_DECLARE_LIST(EL)                                           \
+       ISL_DECLARE_LIST_TYPE(EL)                                       \
+       ISL_DECLARE_LIST_FN(EL)
 
 #if defined(__cplusplus)
 }
index 1386e34..1667a34 100644 (file)
@@ -341,6 +341,8 @@ __isl_export
 __isl_give isl_map *isl_map_apply_range(
                __isl_take isl_map *map1,
                __isl_take isl_map *map2);
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+       __isl_take isl_multi_aff *ma);
 __isl_give isl_basic_map *isl_basic_map_product(
        __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
 __isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
@@ -450,6 +452,8 @@ __isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
 __isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
 __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
 
@@ -551,6 +555,9 @@ __isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap);
 __isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map);
 __isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map);
 
+__isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims(
+       __isl_take isl_basic_map *bmap,
+       enum isl_dim_type type, unsigned first, unsigned n);
 __isl_give isl_map *isl_map_drop_constraints_involving_dims(
        __isl_take isl_map *map,
        enum isl_dim_type type, unsigned first, unsigned n);
index 67057e7..148dc0d 100644 (file)
@@ -2,6 +2,7 @@
 #define ISL_MAP_TYPE_H
 
 #include <isl/ctx.h>
+#include <isl/list.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -15,12 +16,18 @@ typedef struct isl_map isl_map;
 #ifndef isl_basic_set
 struct __isl_subclass(isl_set) isl_basic_set;
 typedef struct isl_basic_set isl_basic_set;
+ISL_DECLARE_LIST_TYPE(basic_set)
 #endif
+
 #ifndef isl_set
 struct __isl_subclass(isl_union_set) isl_set;
 typedef struct isl_set isl_set;
+ISL_DECLARE_LIST_TYPE(set)
 #endif
 
+ISL_DECLARE_LIST_FN(basic_set)
+ISL_DECLARE_LIST_FN(set)
+
 #if defined(__cplusplus)
 }
 #endif
index 997b07e..13db7e2 100644 (file)
@@ -34,7 +34,7 @@ struct isl_mat *isl_mat_extend(struct isl_mat *mat,
 struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row);
 __isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat);
 struct isl_mat *isl_mat_cow(struct isl_mat *mat);
-void isl_mat_free(__isl_take isl_mat *mat);
+void *isl_mat_free(__isl_take isl_mat *mat);
 
 int isl_mat_rows(__isl_keep isl_mat *mat);
 int isl_mat_cols(__isl_keep isl_mat *mat);
@@ -60,7 +60,8 @@ struct isl_mat *isl_mat_left_hermite(struct isl_mat *M,
 struct isl_mat *isl_mat_lin_to_aff(struct isl_mat *mat);
 struct isl_mat *isl_mat_inverse_product(struct isl_mat *left,
        struct isl_mat *right);
-struct isl_mat *isl_mat_product(struct isl_mat *left, struct isl_mat *right);
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+       __isl_take isl_mat *right);
 struct isl_mat *isl_mat_transpose(struct isl_mat *mat);
 __isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat);
 __isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat);
index 31b7aca..2cfbced 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef ISL_MULTI_H
 #define ISL_MULTI_H
 
+#include <isl/space.h>
 #include <isl/list.h>
 
 #if defined(__cplusplus)
@@ -8,16 +9,58 @@ extern "C" {
 #endif
 
 #define ISL_DECLARE_MULTI(BASE)                                                \
+unsigned isl_multi_##BASE##_dim(__isl_keep isl_multi_##BASE *multi,    \
+       enum isl_dim_type type);                                        \
+isl_ctx *isl_multi_##BASE##_get_ctx(                                   \
+       __isl_keep isl_multi_##BASE *multi);                            \
+__isl_give isl_space *isl_multi_##BASE##_get_space(                    \
+       __isl_keep isl_multi_##BASE *multi);                            \
+__isl_give isl_space *isl_multi_##BASE##_get_domain_space(             \
+       __isl_keep isl_multi_##BASE *multi);                            \
 __isl_give isl_multi_##BASE *isl_multi_##BASE##_from_##BASE##_list(    \
        __isl_take isl_space *space, __isl_take isl_##BASE##_list *list); \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_zero(                  \
+       __isl_take isl_space *space);                                   \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_copy(                  \
+       __isl_keep isl_multi_##BASE *multi);                            \
+void *isl_multi_##BASE##_free(__isl_take isl_multi_##BASE *multi);     \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_dim_name(          \
+       __isl_take isl_multi_##BASE *multi,                             \
+       enum isl_dim_type type, unsigned pos, const char *s);           \
 const char *isl_multi_##BASE##_get_tuple_name(                         \
        __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type);    \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_name(                \
+       __isl_take isl_multi_##BASE *multi,                             \
+       enum isl_dim_type type, const char *s);                         \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_id(          \
+       __isl_take isl_multi_##BASE *multi,                             \
+       enum isl_dim_type type, __isl_take isl_id *id);                 \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_insert_dims(           \
+       __isl_take isl_multi_##BASE *multi, enum isl_dim_type type,     \
+       unsigned first, unsigned n);                                    \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_add_dims(              \
+       __isl_take isl_multi_##BASE *multi, enum isl_dim_type type,     \
+       unsigned n);                                                    \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_drop_dims(             \
+       __isl_take isl_multi_##BASE *multi, enum isl_dim_type type,     \
+       unsigned first, unsigned n);                                    \
+__isl_give isl_##BASE *isl_multi_##BASE##_get_##BASE(                  \
+       __isl_keep isl_multi_##BASE *multi, int pos);                   \
 __isl_give isl_multi_##BASE *isl_multi_##BASE##_set_##BASE(            \
        __isl_take isl_multi_##BASE *multi, int pos,                    \
-       __isl_take isl_##BASE *el);
-
-ISL_DECLARE_MULTI(aff)
-ISL_DECLARE_MULTI(pw_aff)
+       __isl_take isl_##BASE *el);                                     \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_splice(          \
+       __isl_take isl_multi_##BASE *multi1, unsigned pos,              \
+       __isl_take isl_multi_##BASE *multi2);                           \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_splice(                        \
+       __isl_take isl_multi_##BASE *multi1, unsigned in_pos,           \
+       unsigned out_pos, __isl_take isl_multi_##BASE *multi2);         \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product(    \
+       __isl_take isl_multi_##BASE *multi1,                            \
+       __isl_take isl_multi_##BASE *multi2);                           \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_product(         \
+       __isl_take isl_multi_##BASE *multi1,                            \
+       __isl_take isl_multi_##BASE *multi2);
 
 #if defined(__cplusplus)
 }
index 3f65fea..863f5ce 100644 (file)
@@ -212,6 +212,10 @@ __isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff(
 __isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff(
        __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
        __isl_give isl_set **empty);
+__isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff(
+       __isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff(
+       __isl_take isl_set *set);
 
 __isl_export
 __isl_give isl_set *isl_basic_set_union(
index 8eb7b2f..2ea5876 100644 (file)
@@ -109,6 +109,8 @@ __isl_give isl_union_map *isl_union_map_apply_domain(
 __isl_export
 __isl_give isl_union_map *isl_union_map_apply_range(
        __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff(
+       __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma);
 __isl_export
 __isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap);
 __isl_give isl_union_map *isl_union_map_from_domain_and_range(
index e9d7286..de1a0ca 100644 (file)
--- a/isl_aff.c
+++ b/isl_aff.c
@@ -1,7 +1,7 @@
 /*
  * Copyright 2011      INRIA Saclay
  * Copyright 2011      Sven Verdoolaege
- * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
 #include <isl_space_private.h>
 #include <isl_local_space_private.h>
 #include <isl_mat_private.h>
-#include <isl_list_private.h>
 #include <isl/constraint.h>
 #include <isl/seq.h>
 #include <isl/set.h>
 #include <isl_config.h>
 
+#undef BASE
+#define BASE aff
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE pw_aff
+
+#include <isl_list_templ.c>
+
 __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
        __isl_take isl_vec *v)
 {
@@ -1214,6 +1223,11 @@ __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
        if (!aff->v)
                return isl_aff_free(aff);
 
+       if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) {
+               isl_int_divexact(aff->v->el[0], aff->v->el[0], f);
+               return aff;
+       }
+
        isl_int_init(gcd);
        isl_int_gcd(gcd, aff->v->el[0], f);
        isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);
@@ -2672,31 +2686,15 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
 __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *maff1,
        __isl_take isl_multi_aff *maff2)
 {
-       int i;
-       isl_ctx *ctx;
-
-       maff1 = isl_multi_aff_cow(maff1);
-       if (!maff1 || !maff2)
-               goto error;
-
-       ctx = isl_multi_aff_get_ctx(maff1);
-       if (!isl_space_is_equal(maff1->space, maff2->space))
-               isl_die(ctx, isl_error_invalid,
-                       "spaces don't match", goto error);
-
-       for (i = 0; i < maff1->n; ++i) {
-               maff1->p[i] = isl_aff_add(maff1->p[i],
-                                           isl_aff_copy(maff2->p[i]));
-               if (!maff1->p[i])
-                       goto error;
-       }
+       return isl_multi_aff_bin_op(maff1, maff2, &isl_aff_add);
+}
 
-       isl_multi_aff_free(maff2);
-       return maff1;
-error:
-       isl_multi_aff_free(maff1);
-       isl_multi_aff_free(maff2);
-       return NULL;
+/* Subtract "ma2" from "ma1" and return the result.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_sub(__isl_take isl_multi_aff *ma1,
+       __isl_take isl_multi_aff *ma2)
+{
+       return isl_multi_aff_bin_op(ma1, ma2, &isl_aff_sub);
 }
 
 /* Given two multi-affine expressions A -> B and C -> D,
@@ -3057,6 +3055,22 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
                                                &pw_multi_aff_add);
 }
 
+static __isl_give isl_pw_multi_aff *pw_multi_aff_sub(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
+                                               &isl_multi_aff_sub);
+}
+
+/* Subtract "pma2" from "pma1" and return the result.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+                                               &pw_multi_aff_sub);
+}
+
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
        __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
 {
@@ -3761,6 +3775,51 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)
        return isl_pw_multi_aff_from_map(set);
 }
 
+/* Convert "map" into an isl_pw_multi_aff (if possible) and
+ * add it to *user.
+ */
+static int pw_multi_aff_from_map(__isl_take isl_map *map, void *user)
+{
+       isl_union_pw_multi_aff **upma = user;
+       isl_pw_multi_aff *pma;
+
+       pma = isl_pw_multi_aff_from_map(map);
+       *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+       return *upma ? 0 : -1;
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_map.
+ * The isl_union_map is required to be single-valued in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
+       __isl_take isl_union_map *umap)
+{
+       isl_space *space;
+       isl_union_pw_multi_aff *upma;
+
+       space = isl_union_map_get_space(umap);
+       upma = isl_union_pw_multi_aff_empty(space);
+       if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0)
+               upma = isl_union_pw_multi_aff_free(upma);
+       isl_union_map_free(umap);
+
+       return upma;
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_set.
+ * The isl_union_set is required to be a singleton in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
+       __isl_take isl_union_set *uset)
+{
+       return isl_union_pw_multi_aff_from_union_map(uset);
+}
+
 /* Return the piecewise affine expression "set ? 1 : 0".
  */
 __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
@@ -3923,8 +3982,12 @@ error:
        return NULL;
 }
 
-/* Compute the preimage of the affine expression "src" under "ma"
- * and put the result in "dst".  If "has_denom" is set (to one),
+/* Compute the preimage of a range of dimensions in the affine expression "src"
+ * under "ma" and put the result in "dst".  The number of dimensions in "src"
+ * that precede the range is given by "n_before".  The number of dimensions
+ * in the range is given by the number of output dimensions of "ma".
+ * The number of dimensions that follow the range is given by "n_after".
+ * If "has_denom" is set (to one),
  * then "src" and "dst" have an extra initial denominator.
  * "n_div_ma" is the number of existentials in "ma"
  * "n_div_bset" is the number of existentials in "src"
@@ -3936,17 +3999,18 @@ error:
  *
  * Let src represent the expression
  *
- *     (a(p) + b x + c(divs))/d
+ *     (a(p) + f_u u + b v + f_w w + c(divs))/d
  *
  * and let ma represent the expressions
  *
- *     x_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i
+ *     v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i
  *
  * We start out with the following expression for dst:
  *
- *     (a(p) + 0 y + 0 divs' + f \sum_i b_i x_i + c(divs))/d
+ *     (a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d
  *
- * with the multiplication factor f initially equal to 1.
+ * with the multiplication factor f initially equal to 1
+ * and f \sum_i b_i v_i kept separately.
  * For each x_i that we substitute, we multiply the numerator
  * (and denominator) of dst by c_1 = m_i and add the numerator
  * of the x_i expression multiplied by c_2 = f b_i,
@@ -3955,40 +4019,63 @@ error:
  * for the next x_j, j > i.
  */
 void isl_seq_preimage(isl_int *dst, isl_int *src,
-       __isl_keep isl_multi_aff *ma, int n_div_ma, int n_div_bset,
+       __isl_keep isl_multi_aff *ma, int n_before, int n_after,
+       int n_div_ma, int n_div_bmap,
        isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom)
 {
        int i;
        int n_param, n_in, n_out;
-       int o_div_bset;
+       int o_dst, o_src;
 
        n_param = isl_multi_aff_dim(ma, isl_dim_param);
        n_in = isl_multi_aff_dim(ma, isl_dim_in);
        n_out = isl_multi_aff_dim(ma, isl_dim_out);
 
-       o_div_bset = has_denom + 1 + n_param + n_in + n_div_ma;
-
-       isl_seq_cpy(dst, src, has_denom + 1 + n_param);
-       isl_seq_clr(dst + has_denom + 1 + n_param, n_in + n_div_ma);
-       isl_seq_cpy(dst + o_div_bset,
-                   src + has_denom + 1 + n_param + n_out, n_div_bset);
+       isl_seq_cpy(dst, src, has_denom + 1 + n_param + n_before);
+       o_dst = o_src = has_denom + 1 + n_param + n_before;
+       isl_seq_clr(dst + o_dst, n_in);
+       o_dst += n_in;
+       o_src += n_out;
+       isl_seq_cpy(dst + o_dst, src + o_src, n_after);
+       o_dst += n_after;
+       o_src += n_after;
+       isl_seq_clr(dst + o_dst, n_div_ma);
+       o_dst += n_div_ma;
+       isl_seq_cpy(dst + o_dst, src + o_src, n_div_bmap);
 
        isl_int_set_si(f, 1);
 
        for (i = 0; i < n_out; ++i) {
-               if (isl_int_is_zero(src[has_denom + 1 + n_param + i]))
+               int offset = has_denom + 1 + n_param + n_before + i;
+
+               if (isl_int_is_zero(src[offset]))
                        continue;
                isl_int_set(c1, ma->p[i]->v->el[0]);
-               isl_int_mul(c2, f, src[has_denom + 1 + n_param + i]);
+               isl_int_mul(c2, f, src[offset]);
                isl_int_gcd(g, c1, c2);
                isl_int_divexact(c1, c1, g);
                isl_int_divexact(c2, c2, g);
 
                isl_int_mul(f, f, c1);
-               isl_seq_combine(dst + has_denom, c1, dst + has_denom,
-                               c2, ma->p[i]->v->el + 1, ma->p[i]->v->size - 1);
-               isl_seq_scale(dst + o_div_bset,
-                               dst + o_div_bset, c1, n_div_bset);
+               o_dst = has_denom;
+               o_src = 1;
+               isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+                               c2, ma->p[i]->v->el + o_src, 1 + n_param);
+               o_dst += 1 + n_param;
+               o_src += 1 + n_param;
+               isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_before);
+               o_dst += n_before;
+               isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+                               c2, ma->p[i]->v->el + o_src, n_in);
+               o_dst += n_in;
+               o_src += n_in;
+               isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_after);
+               o_dst += n_after;
+               isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+                               c2, ma->p[i]->v->el + o_src, n_div_ma);
+               o_dst += n_div_ma;
+               o_src += n_div_ma;
+               isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_div_bmap);
                if (has_denom)
                        isl_int_mul(dst[0], dst[0], c1);
        }
@@ -4039,7 +4126,7 @@ __isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff,
        isl_int_init(c2);
        isl_int_init(g);
 
-       isl_seq_preimage(res->v->el, aff->v->el, ma, n_div_ma, n_div_aff,
+       isl_seq_preimage(res->v->el, aff->v->el, ma, 0, 0, n_div_ma, n_div_aff,
                        f, c1, c2, g, 1);
 
        isl_int_clear(f);
@@ -4595,3 +4682,101 @@ error:
 #define BASE pw_aff
 
 #include <isl_multi_templ.c>
+
+/* Scale the first elements of "ma" by the corresponding elements of "vec".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_scale_vec(__isl_take isl_multi_aff *ma,
+       __isl_take isl_vec *vec)
+{
+       int i, n;
+       isl_int v;
+
+       if (!ma || !vec)
+               goto error;
+
+       n = isl_multi_aff_dim(ma, isl_dim_out);
+       if (isl_vec_size(vec) < n)
+               n = isl_vec_size(vec);
+
+       isl_int_init(v);
+       for (i = 0; i < n; ++i) {
+               isl_aff *aff;
+
+               isl_vec_get_element(vec, i, &v);
+
+               aff = isl_multi_aff_get_aff(ma, i);
+               aff = isl_aff_scale(aff, v);
+               ma = isl_multi_aff_set_aff(ma, i, aff);
+       }
+       isl_int_clear(v);
+
+       isl_vec_free(vec);
+       return ma;
+error:
+       isl_vec_free(vec);
+       isl_multi_aff_free(ma);
+       return NULL;
+}
+
+/* Scale the first elements of "pma" by the corresponding elements of "vec".
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_vec(
+       __isl_take isl_pw_multi_aff *pma, __isl_take isl_vec *v)
+{
+       int i;
+
+       pma = isl_pw_multi_aff_cow(pma);
+       if (!pma || !v)
+               goto error;
+
+       for (i = 0; i < pma->n; ++i) {
+               pma->p[i].maff = isl_multi_aff_scale_vec(pma->p[i].maff,
+                                                       isl_vec_copy(v));
+               if (!pma->p[i].maff)
+                       goto error;
+       }
+
+       isl_vec_free(v);
+       return pma;
+error:
+       isl_vec_free(v);
+       isl_pw_multi_aff_free(pma);
+       return NULL;
+}
+
+/* This function is called for each entry of an isl_union_pw_multi_aff.
+ * Replace the entry by the result of applying isl_pw_multi_aff_scale_vec
+ * to the original entry with the isl_vec in "user" as extra argument.
+ */
+static int union_pw_multi_aff_scale_vec_entry(void **entry, void *user)
+{
+       isl_pw_multi_aff **pma = (isl_pw_multi_aff **) entry;
+       isl_vec *v = user;
+
+       *pma = isl_pw_multi_aff_scale_vec(*pma, isl_vec_copy(v));
+       if (!*pma)
+               return -1;
+
+       return 0;
+}
+
+/* Scale the first elements of "upma" by the corresponding elements of "vec".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_vec(
+       __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_vec *v)
+{
+       upma = isl_union_pw_multi_aff_cow(upma);
+       if (!upma || !v)
+               goto error;
+
+       if (isl_hash_table_foreach(upma->dim->ctx, &upma->table,
+                                  &union_pw_multi_aff_scale_vec_entry, v) < 0)
+               goto error;
+
+       isl_vec_free(v);
+       return upma;
+error:
+       isl_vec_free(v);
+       isl_union_pw_multi_aff_free(upma);
+       return NULL;
+}
index dc031c4..2fb245a 100644 (file)
@@ -16,6 +16,11 @@ struct isl_aff {
        isl_vec         *v;
 };
 
+#undef EL
+#define EL isl_aff
+
+#include <isl_list_templ.h>
+
 struct isl_pw_aff_piece {
        struct isl_set *set;
        struct isl_aff *aff;
@@ -32,6 +37,11 @@ struct isl_pw_aff {
        struct isl_pw_aff_piece p[1];
 };
 
+#undef EL
+#define EL isl_pw_aff
+
+#include <isl_list_templ.h>
+
 struct isl_pw_multi_aff_piece {
        isl_set *set;
        isl_multi_aff *maff;
@@ -102,7 +112,8 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out(
 void isl_seq_substitute(isl_int *p, int pos, isl_int *subs,
        int p_len, int subs_len, isl_int v);
 void isl_seq_preimage(isl_int *dst, isl_int *src,
-       __isl_keep isl_multi_aff *ma, int n_div_ma, int n_div_bset,
+       __isl_keep isl_multi_aff *ma, int n_before, int n_after,
+       int n_div_ma, int n_div_bmap,
        isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom);
 
 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute(
index e71bc10..0d66081 100644 (file)
@@ -1,10 +1,15 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
  * Written by Sven Verdoolaege, K.U.Leuven, Departement
  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
  */
 
 #include <isl_ctx_private.h>
@@ -1126,30 +1131,6 @@ __isl_give isl_basic_set *isl_basic_set_detect_equalities(
                isl_basic_map_detect_equalities((isl_basic_map *)bset);
 }
 
-__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
-       __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap))
-{
-       struct isl_basic_map *bmap;
-       int i;
-
-       if (!map)
-               return NULL;
-
-       for (i = 0; i < map->n; ++i) {
-               bmap = isl_basic_map_copy(map->p[i]);
-               bmap = fn(bmap);
-               if (!bmap)
-                       goto error;
-               isl_basic_map_free(map->p[i]);
-               map->p[i] = bmap;
-       }
-
-       return map;
-error:
-       isl_map_free(map);
-       return NULL;
-}
-
 __isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map)
 {
        return isl_map_inline_foreach_basic_map(map,
@@ -1181,14 +1162,205 @@ struct isl_basic_set *isl_basic_set_affine_hull(struct isl_basic_set *bset)
                isl_basic_map_affine_hull((struct isl_basic_map *)bset);
 }
 
-struct isl_basic_map *isl_map_affine_hull(struct isl_map *map)
+/* Given a rational affine matrix "M", add stride constraints to "bmap"
+ * that ensure that
+ *
+ *             M(x)
+ *
+ * is an integer vector.  The variables x include all the variables
+ * of "bmap" except the unknown divs.
+ *
+ * If d is the common denominator of M, then we need to impose that
+ *
+ *             d M(x) = 0      mod d
+ *
+ * or
+ *
+ *             exists alpha : d M(x) = d alpha
+ *
+ * This function is similar to add_strides in isl_morph.c
+ */
+static __isl_give isl_basic_map *add_strides(__isl_take isl_basic_map *bmap,
+       __isl_keep isl_mat *M, int n_known)
+{
+       int i, div, k;
+       isl_int gcd;
+
+       if (isl_int_is_one(M->row[0][0]))
+               return bmap;
+
+       bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+                                       M->n_row - 1, M->n_row - 1, 0);
+
+       isl_int_init(gcd);
+       for (i = 1; i < M->n_row; ++i) {
+               isl_seq_gcd(M->row[i], M->n_col, &gcd);
+               if (isl_int_is_divisible_by(gcd, M->row[0][0]))
+                       continue;
+               div = isl_basic_map_alloc_div(bmap);
+               if (div < 0)
+                       goto error;
+               isl_int_set_si(bmap->div[div][0], 0);
+               k = isl_basic_map_alloc_equality(bmap);
+               if (k < 0)
+                       goto error;
+               isl_seq_cpy(bmap->eq[k], M->row[i], M->n_col);
+               isl_seq_clr(bmap->eq[k] + M->n_col, bmap->n_div - n_known);
+               isl_int_set(bmap->eq[k][M->n_col - n_known + div],
+                           M->row[0][0]);
+       }
+       isl_int_clear(gcd);
+
+       return bmap;
+error:
+       isl_int_clear(gcd);
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+/* If there are any equalities that involve (multiple) unknown divs,
+ * then extract the stride information encoded by those equalities
+ * and make it explicitly available in "bmap".
+ *
+ * We first sort the divs so that the unknown divs appear last and
+ * then we count how many equalities involve these divs.
+ *
+ * Let these equalities be of the form
+ *
+ *             A(x) + B y = 0
+ *
+ * where y represents the unknown divs and x the remaining variables.
+ * Let [H 0] be the Hermite Normal Form of B, i.e.,
+ *
+ *             B = [H 0] Q
+ *
+ * Then x is a solution of the equalities iff
+ *
+ *             H^-1 A(x) (= - [I 0] Q y)
+ *
+ * is an integer vector.  Let d be the common denominator of H^-1.
+ * We impose
+ *
+ *             d H^-1 A(x) = d alpha
+ *
+ * in add_strides, with alpha fresh existentially quantified variables.
+ */
+static __isl_give isl_basic_map *isl_basic_map_make_strides_explicit(
+       __isl_take isl_basic_map *bmap)
+{
+       int known;
+       int n_known;
+       int n, n_col;
+       int total;
+       isl_ctx *ctx;
+       isl_mat *A, *B, *M;
+
+       known = isl_basic_map_divs_known(bmap);
+       if (known < 0)
+               return isl_basic_map_free(bmap);
+       if (known)
+               return bmap;
+       bmap = isl_basic_map_sort_divs(bmap);
+       bmap = isl_basic_map_gauss(bmap, NULL);
+       if (!bmap)
+               return NULL;
+
+       for (n_known = 0; n_known < bmap->n_div; ++n_known)
+               if (isl_int_is_zero(bmap->div[n_known][0]))
+                       break;
+       ctx = isl_basic_map_get_ctx(bmap);
+       total = isl_space_dim(bmap->dim, isl_dim_all);
+       for (n = 0; n < bmap->n_eq; ++n)
+               if (isl_seq_first_non_zero(bmap->eq[n] + 1 + total + n_known,
+                                           bmap->n_div - n_known) == -1)
+                       break;
+       if (n == 0)
+               return bmap;
+       B = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 0, 1 + total + n_known);
+       n_col = bmap->n_div - n_known;
+       A = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 1 + total + n_known, n_col);
+       A = isl_mat_left_hermite(A, 0, NULL, NULL);
+       A = isl_mat_drop_cols(A, n, n_col - n);
+       A = isl_mat_lin_to_aff(A);
+       A = isl_mat_right_inverse(A);
+       B = isl_mat_insert_zero_rows(B, 0, 1);
+       B = isl_mat_set_element_si(B, 0, 0, 1);
+       M = isl_mat_product(A, B);
+       if (!M)
+               return isl_basic_map_free(bmap);
+       bmap = add_strides(bmap, M, n_known);
+       bmap = isl_basic_map_gauss(bmap, NULL);
+       isl_mat_free(M);
+
+       return bmap;
+}
+
+/* Compute the affine hull of each basic map in "map" separately
+ * and make all stride information explicit so that we can remove
+ * all unknown divs without losing this information.
+ * The result is also guaranteed to be gaussed.
+ *
+ * In simple cases where a div is determined by an equality,
+ * calling isl_basic_map_gauss is enough to make the stride information
+ * explicit, as it will derive an explicit representation for the div
+ * from the equality.  If, however, the stride information
+ * is encoded through multiple unknown divs then we need to make
+ * some extra effort in isl_basic_map_make_strides_explicit.
+ */
+static __isl_give isl_map *isl_map_local_affine_hull(__isl_take isl_map *map)
 {
        int i;
+
+       map = isl_map_cow(map);
+       if (!map)
+               return NULL;
+
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = isl_basic_map_affine_hull(map->p[i]);
+               map->p[i] = isl_basic_map_gauss(map->p[i], NULL);
+               map->p[i] = isl_basic_map_make_strides_explicit(map->p[i]);
+               if (!map->p[i])
+                       return isl_map_free(map);
+       }
+
+       return map;
+}
+
+static __isl_give isl_set *isl_set_local_affine_hull(__isl_take isl_set *set)
+{
+       return isl_map_local_affine_hull(set);
+}
+
+/* Compute the affine hull of "map".
+ *
+ * We first compute the affine hull of each basic map separately.
+ * Then we align the divs and recompute the affine hulls of the basic
+ * maps since some of them may now have extra divs.
+ * In order to avoid performing parametric integer programming to
+ * compute explicit expressions for the divs, possible leading to
+ * an explosion in the number of basic maps, we first drop all unknown
+ * divs before aligning the divs.  Note that isl_map_local_affine_hull tries
+ * to make sure that all stride information is explicitly available
+ * in terms of known divs.  This involves calling isl_basic_set_gauss,
+ * which is also needed because affine_hull assumes its input has been gaussed,
+ * while isl_map_affine_hull may be called on input that has not been gaussed,
+ * in particular from initial_facet_constraint.
+ * Similarly, align_divs may reorder some divs so that we need to
+ * gauss the result again.
+ * Finally, we combine the individual affine hulls into a single
+ * affine hull.
+ */
+__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map)
+{
        struct isl_basic_map *model = NULL;
        struct isl_basic_map *hull = NULL;
        struct isl_set *set;
+       isl_basic_set *bset;
 
        map = isl_map_detect_equalities(map);
+       map = isl_map_local_affine_hull(map);
+       map = isl_map_remove_empty_parts(map);
+       map = isl_map_remove_unknown_divs(map);
        map = isl_map_align_divs(map);
 
        if (!map)
@@ -1203,30 +1375,15 @@ struct isl_basic_map *isl_map_affine_hull(struct isl_map *map)
        model = isl_basic_map_copy(map->p[0]);
        set = isl_map_underlying_set(map);
        set = isl_set_cow(set);
+       set = isl_set_local_affine_hull(set);
        if (!set)
                goto error;
 
-       for (i = 0; i < set->n; ++i) {
-               set->p[i] = isl_basic_set_cow(set->p[i]);
-               set->p[i] = isl_basic_set_affine_hull(set->p[i]);
-               set->p[i] = isl_basic_set_gauss(set->p[i], NULL);
-               if (!set->p[i])
-                       goto error;
-       }
-       set = isl_set_remove_empty_parts(set);
-       if (set->n == 0) {
-               hull = isl_basic_map_empty_like(model);
-               isl_basic_map_free(model);
-       } else {
-               struct isl_basic_set *bset;
-               while (set->n > 1) {
-                       set->p[0] = affine_hull(set->p[0], set->p[--set->n]);
-                       if (!set->p[0])
-                               goto error;
-               }
-               bset = isl_basic_set_copy(set->p[0]);
-               hull = isl_basic_map_overlying_set(bset, model);
-       }
+       while (set->n > 1)
+               set->p[0] = affine_hull(set->p[0], set->p[--set->n]);
+
+       bset = isl_basic_set_copy(set->p[0]);
+       hull = isl_basic_map_overlying_set(bset, model);
        isl_set_free(set);
        hull = isl_basic_map_simplify(hull);
        return isl_basic_map_finalize(hull);
index 3e2188b..0963aa1 100644 (file)
--- a/isl_arg.c
+++ b/isl_arg.c
@@ -130,6 +130,17 @@ void isl_args_set_defaults(struct isl_args *args, void *opt)
        }
 }
 
+static void free_args(struct isl_arg *arg, void *opt);
+
+static void free_child(struct isl_arg *arg, void *opt)
+{
+       if (arg->offset == (size_t) -1)
+               free_args(arg->u.child.child->args, opt);
+       else
+               isl_args_free(arg->u.child.child,
+                           *(void **)(((char *)opt) + arg->offset));
+}
+
 static void free_str_list(struct isl_arg *arg, void *opt)
 {
        int i;
@@ -141,6 +152,12 @@ static void free_str_list(struct isl_arg *arg, void *opt)
        free(list);
 }
 
+static void free_user(struct isl_arg *arg, void *opt)
+{
+       if (arg->u.user.clear)
+               arg->u.user.clear(((char *)opt) + arg->offset);
+}
+
 static void free_args(struct isl_arg *arg, void *opt)
 {
        int i;
@@ -148,11 +165,7 @@ static void free_args(struct isl_arg *arg, void *opt)
        for (i = 0; arg[i].type != isl_arg_end; ++i) {
                switch (arg[i].type) {
                case isl_arg_child:
-                       if (arg[i].offset == (size_t) -1)
-                               free_args(arg[i].u.child.child->args, opt);
-                       else
-                               isl_args_free(arg[i].u.child.child,
-                                   *(void **)(((char *)opt) + arg[i].offset));
+                       free_child(&arg[i], opt);
                        break;
                case isl_arg_arg:
                case isl_arg_str:
@@ -162,8 +175,7 @@ static void free_args(struct isl_arg *arg, void *opt)
                        free_str_list(&arg[i], opt);
                        break;
                case isl_arg_user:
-                       if (arg[i].u.user.clear)
-                               arg[i].u.user.clear(((char *)opt) + arg[i].offset);
+                       free_user(&arg[i], opt);
                        break;
                case isl_arg_alias:
                case isl_arg_bool:
@@ -714,10 +726,9 @@ static int parse_choice_option(struct isl_arg *decl, char **arg,
 
        if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
                unsigned u = decl->u.choice.default_selected;
+               *(unsigned *)(((char *)opt) + decl->offset) = u;
                if (decl->u.choice.set)
                        decl->u.choice.set(opt, u);
-               else
-                       *(unsigned *)(((char *)opt) + decl->offset) = u;
 
                return 1;
        }
@@ -732,10 +743,9 @@ static int parse_choice_option(struct isl_arg *decl, char **arg,
                        continue;
 
                u = decl->u.choice.choice[i].value;
+               *(unsigned *)(((char *)opt) + decl->offset) = u;
                if (decl->u.choice.set)
                        decl->u.choice.set(opt, u);
-               else
-                       *(unsigned *)(((char *)opt) + decl->offset) = u;
 
                return has_argument ? 1 : 2;
        }
@@ -805,17 +815,17 @@ static int parse_bool_option(struct isl_arg *decl, char **arg,
                        char *endptr;
                        int val = strtol(arg[1], &endptr, 0);
                        if (*endptr == '\0' && (val == 0 || val == 1)) {
+                               if (decl->offset != (size_t) -1)
+                                       *p = val;
                                if (decl->u.b.set)
                                        decl->u.b.set(opt, val);
-                               else if (decl->offset != (size_t) -1)
-                                       *p = val;
                                return 2;
                        }
                }
+               if (decl->offset != (size_t) -1)
+                       *p = 1;
                if (decl->u.b.set)
                        decl->u.b.set(opt, 1);
-               else if (decl->offset != (size_t) -1)
-                       *p = 1;
 
                return 1;
        }
@@ -848,10 +858,10 @@ static int parse_bool_option(struct isl_arg *decl, char **arg,
        }
 
        if (match_long_name(decl, name, name + strlen(name))) {
+               if (decl->offset != (size_t) -1)
+                       *p = 0;
                if (decl->u.b.set)
                        decl->u.b.set(opt, 0);
-               else if (decl->offset != (size_t) -1)
-                       *p = 0;
 
                return 1;
        }
@@ -965,29 +975,26 @@ static int parse_long_option(struct isl_arg *decl, char **arg,
 
        if (has_argument) {
                long l = strtol(val, NULL, 0);
+               *p = l;
                if (decl->u.l.set)
                        decl->u.l.set(opt, l);
-               else
-                       *p = l;
                return 1;
        }
 
        if (arg[1]) {
                long l = strtol(arg[1], &endptr, 0);
                if (*endptr == '\0') {
+                       *p = l;
                        if (decl->u.l.set)
                                decl->u.l.set(opt, l);
-                       else
-                               *p = l;
                        return 2;
                }
        }
 
        if (decl->u.l.default_value != decl->u.l.default_selected) {
+               *p = decl->u.l.default_selected;
                if (decl->u.l.set)
                        decl->u.l.set(opt, decl->u.l.default_selected);
-               else
-                       *p = decl->u.l.default_selected;
                return 1;
        }
 
@@ -1144,21 +1151,17 @@ static int next_arg(struct isl_arg *arg, int a)
        return -1;
 }
 
-/* Unless ISL_ARG_SKIP_HELP is set, check if any of the arguments is
+/* Unless ISL_ARG_SKIP_HELP is set, check if "arg" is
  * equal to "--help" and if so call print_help_and_exit.
  */
-static void check_help(struct isl_args *args, int argc, char **argv, void *opt,
+static void check_help(struct isl_args *args, char *arg, char *prog, void *opt,
        unsigned flags)
 {
-       int i;
-
        if (ISL_FL_ISSET(flags, ISL_ARG_SKIP_HELP))
                return;
 
-       for (i = 1; i < argc; ++i) {
-               if (strcmp(argv[i], "--help") == 0)
-                       print_help_and_exit(args->args, argv[0], opt);
-       }
+       if (strcmp(arg, "--help") == 0)
+               print_help_and_exit(args->args, prog, opt);
 }
 
 int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
@@ -1171,8 +1174,6 @@ int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
 
        n = n_arg(args->args);
 
-       check_help(args, argc, argv, opt, flags);
-
        for (i = 1; i < argc; ++i) {
                if ((strcmp(argv[i], "--version") == 0 ||
                     strcmp(argv[i], "-V") == 0) && any_version(args->args))
@@ -1198,6 +1199,7 @@ int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
                                ++skip;
                        continue;
                }
+               check_help(args, argv[1 + skip], argv[0], opt, flags);
                parsed = parse_option(args->args, &argv[1 + skip], NULL, opt);
                if (parsed)
                        argc = drop_argument(argc, argv, 1 + skip, parsed);
index 05a79a4..6859e7f 100644 (file)
--- a/isl_ast.c
+++ b/isl_ast.c
@@ -1,5 +1,4 @@
 #include <isl_ast_private.h>
-#include <isl_list_private.h>
 
 #undef BASE
 #define BASE ast_expr
index 95b4692..fe14b50 100644 (file)
@@ -1017,6 +1017,30 @@ __isl_give isl_id *isl_ast_build_get_iterator_id(
 
 /* Set the stride and offset of the current dimension to the given
  * value and expression.
+ *
+ * If we had already found a stride before, then the two strides
+ * are combined into a single stride.
+ *
+ * In particular, if the new stride information is of the form
+ *
+ *     i = f + s (...)
+ *
+ * and the old stride information is of the form
+ *
+ *     i = f2 + s2 (...)
+ *
+ * then we compute the extended gcd of s and s2
+ *
+ *     a s + b s2 = g,
+ *
+ * with g = gcd(s,s2), multiply the first equation with t1 = b s2/g
+ * and the second with t2 = a s1/g.
+ * This results in
+ *
+ *     i = (b s2 + a s1)/g i = t1 f + t2 f2 + (s s2)/g (...)
+ *
+ * so that t1 f + t2 f2 is the combined offset and (s s2)/g = lcm(s,s2)
+ * is the combined stride.
  */
 static __isl_give isl_ast_build *set_stride(__isl_take isl_ast_build *build,
        isl_int stride, __isl_take isl_aff *offset)
@@ -1028,6 +1052,35 @@ static __isl_give isl_ast_build *set_stride(__isl_take isl_ast_build *build,
                goto error;
 
        pos = build->depth;
+
+       if (isl_ast_build_has_stride(build, pos)) {
+               isl_int stride2, a, b, g;
+               isl_aff *offset2;
+
+               isl_int_init(stride2);
+               isl_int_init(a);
+               isl_int_init(b);
+               isl_int_init(g);
+
+               isl_vec_get_element(build->strides, pos, &stride2);
+               isl_int_gcdext(g, a, b, stride, stride2);
+               isl_int_mul(a, a, stride);
+               isl_int_divexact(a, a, g);
+               isl_int_divexact(stride2, stride2, g);
+               isl_int_mul(b, b, stride2);
+               isl_int_mul(stride, stride, stride2);
+
+               offset2 = isl_multi_aff_get_aff(build->offsets, pos);
+               offset2 = isl_aff_scale(offset2, a);
+               offset = isl_aff_scale(offset, b);
+               offset = isl_aff_add(offset, offset2);
+
+               isl_int_clear(stride2);
+               isl_int_clear(a);
+               isl_int_clear(b);
+               isl_int_clear(g);
+       }
+
        build->strides = isl_vec_set_element(build->strides, pos, stride);
        build->offsets = isl_multi_aff_set_aff(build->offsets, pos, offset);
        if (!build->strides || !build->offsets)
@@ -1148,51 +1201,6 @@ __isl_give isl_ast_build *isl_ast_build_include_stride(
        return build;
 }
 
-/* Compute x, y and g such that g = gcd(a,b) and a*x+b*y = g */
-static void euclid(isl_int a, isl_int b, isl_int *x, isl_int *y, isl_int *g)
-{
-       isl_int c, d, e, f, tmp;
-
-       isl_int_init(c);
-       isl_int_init(d);
-       isl_int_init(e);
-       isl_int_init(f);
-       isl_int_init(tmp);
-       isl_int_abs(c, a);
-       isl_int_abs(d, b);
-       isl_int_set_si(e, 1);
-       isl_int_set_si(f, 0);
-       while (isl_int_is_pos(d)) {
-               isl_int_tdiv_q(tmp, c, d);
-               isl_int_mul(tmp, tmp, f);
-               isl_int_sub(e, e, tmp);
-               isl_int_tdiv_q(tmp, c, d);
-               isl_int_mul(tmp, tmp, d);
-               isl_int_sub(c, c, tmp);
-               isl_int_swap(c, d);
-               isl_int_swap(e, f);
-       }
-       isl_int_set(*g, c);
-       if (isl_int_is_zero(a))
-               isl_int_set_si(*x, 0);
-       else if (isl_int_is_pos(a))
-               isl_int_set(*x, e);
-       else
-               isl_int_neg(*x, e);
-       if (isl_int_is_zero(b))
-               isl_int_set_si(*y, 0);
-       else {
-               isl_int_mul(tmp, a, *x);
-               isl_int_sub(tmp, c, tmp);
-               isl_int_divexact(*y, tmp, b);
-       }
-       isl_int_clear(c);
-       isl_int_clear(d);
-       isl_int_clear(e);
-       isl_int_clear(f);
-       isl_int_clear(tmp);
-}
-
 /* Information used inside detect_stride.
  *
  * "build" may be updated by detect_stride to include stride information.
@@ -1272,7 +1280,7 @@ static int detect_stride(__isl_take isl_constraint *c, void *user)
        if (!isl_int_is_zero(stride) && !isl_int_is_one(stride)) {
                isl_aff *aff;
 
-               euclid(v, stride, &a, &b, &gcd);
+               isl_int_gcdext(gcd, a, b, v, stride);
 
                aff = isl_constraint_get_aff(c);
                for (i = 0; i < n_div; ++i)
@@ -1806,6 +1814,26 @@ int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build,
        return !involves;
 }
 
+/* Plug in the known values (fixed affine expressions in terms of
+ * parameters and outer loop iterators) of all loop iterators
+ * in the domain of "umap".
+ *
+ * We simply precompose "umap" with build->values.
+ */
+__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain(
+       __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap)
+{
+       isl_multi_aff *values;
+
+       if (!build)
+               return isl_union_map_free(umap);
+
+       values = isl_multi_aff_copy(build->values);
+       umap = isl_union_map_preimage_domain_multi_aff(umap, values);
+
+       return umap;
+}
+
 /* Is the current dimension known to attain only a single value?
  */
 int isl_ast_build_has_value(__isl_keep isl_ast_build *build)
index 81688de..86a9e6e 100644 (file)
 #include <isl_ast_private.h>
 #include <isl_ast_build_private.h>
 
-/* Compute the minimum of the integer affine expression "obj" over the points
- * in build->domain and put the result in *opt.
- */
-enum isl_lp_result isl_ast_build_min(__isl_keep isl_ast_build *build,
-       __isl_keep isl_aff *obj, isl_int *opt)
-{
-       if (!build)
-               return isl_lp_error;
-
-       return isl_set_min(build->domain, obj, opt);
-}
-
-/* Compute the maximum of the integer affine expression "obj" over the points
- * in build->domain and put the result in *opt.
- */
-enum isl_lp_result isl_ast_build_max(__isl_keep isl_ast_build *build,
-       __isl_keep isl_aff *obj, isl_int *opt)
-{
-       if (!build)
-               return isl_lp_error;
-
-       return isl_set_max(build->domain, obj, opt);
-}
-
 /* Compute the "opposite" of the (numerator of the) argument of a div
  * with denonimator "d".
  *
index 516bc62..52133ab 100644 (file)
@@ -221,6 +221,9 @@ __isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff(
 __isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff(
        __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma);
 
+__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain(
+       __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap);
+
 int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build,
        __isl_keep isl_aff *aff);
 
index a0717a9..5806c66 100644 (file)
@@ -18,7 +18,6 @@
 #include <isl_ast_build_expr.h>
 #include <isl_ast_build_private.h>
 #include <isl_ast_graft_private.h>
-#include <isl_list_private.h>
 
 /* Add the constraint to the list that "user" points to, if it is not
  * a div constraint.
@@ -315,24 +314,17 @@ static __isl_give isl_ast_graft *after_each_for(__isl_keep isl_ast_graft *graft,
        return graft;
 }
 
-/* Eliminate the schedule dimension "pos" from "executed" and return
- * the result.
+/* Plug in all the know values of the current and outer dimensions
+ * in the domain of "executed".  In principle, we only need to plug
+ * in the known value of the current dimension since the values of
+ * outer dimensions have been plugged in already.
+ * However, it turns out to be easier to just plug in all known values.
  */
-static __isl_give isl_union_map *eliminate(__isl_take isl_union_map *executed,
-       int pos, __isl_keep isl_ast_build *build)
+static __isl_give isl_union_map *plug_in_values(
+       __isl_take isl_union_map *executed, __isl_keep isl_ast_build *build)
 {
-       isl_space *space;
-       isl_map *elim;
-
-       space = isl_ast_build_get_space(build, 1);
-       space = isl_space_map_from_set(space);
-       elim = isl_map_identity(space);
-       elim = isl_map_eliminate(elim, isl_dim_in, pos, 1);
-
-       executed = isl_union_map_apply_domain(executed,
-                                               isl_union_map_from_map(elim));
-
-       return executed;
+       return isl_ast_build_substitute_values_union_map_domain(build,
+                                                                   executed);
 }
 
 /* Check if the constraint "c" is a lower bound on dimension "pos",
@@ -352,13 +344,12 @@ static int constraint_type(isl_constraint *c, int pos)
  * to be sorted before the lower bounds on "depth", which in
  * turn are sorted before the upper bounds on "depth".
  */
-static int cmp_constraint(const void *a, const void *b, void *user)
+static int cmp_constraint(__isl_keep isl_constraint *a,
+       __isl_keep isl_constraint *b, void *user)
 {
        int *depth = user;
-       isl_constraint * const *c1 = a;
-       isl_constraint * const *c2 = b;
-       int t1 = constraint_type(*c1, *depth);
-       int t2 = constraint_type(*c2, *depth);
+       int t1 = constraint_type(a, *depth);
+       int t2 = constraint_type(b, *depth);
 
        return t1 - t2;
 }
@@ -452,21 +443,23 @@ static __isl_give isl_pw_aff *exact_bound(__isl_keep isl_set *domain,
        return pa;
 }
 
-/* Return a list of "n" lower bounds on dimension "pos"
- * extracted from the "n" constraints starting at "constraint".
- * If "n" is zero, then we extract a lower bound from "domain" instead.
+/* Extract a lower bound on dimension "pos" from each constraint
+ * in "constraints" and return the list of lower bounds.
+ * If "constraints" has zero elements, then we extract a lower bound
+ * from "domain" instead.
  */
 static __isl_give isl_pw_aff_list *lower_bounds(
-       __isl_keep isl_constraint **constraint, int n, int pos,
+       __isl_keep isl_constraint_list *constraints, int pos,
        __isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
 {
        isl_ctx *ctx;
        isl_pw_aff_list *list;
-       int i;
+       int i, n;
 
        if (!build)
                return NULL;
 
+       n = isl_constraint_list_n_constraint(constraints);
        if (n == 0) {
                isl_pw_aff *pa;
                pa = exact_bound(domain, build, 0);
@@ -478,26 +471,31 @@ static __isl_give isl_pw_aff_list *lower_bounds(
 
        for (i = 0; i < n; ++i) {
                isl_aff *aff;
+               isl_constraint *c;
 
-               aff = lower_bound(constraint[i], pos, build);
+               c = isl_constraint_list_get_constraint(constraints, i);
+               aff = lower_bound(c, pos, build);
+               isl_constraint_free(c);
                list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff));
        }
 
        return list;
 }
 
-/* Return a list of "n" upper bounds on dimension "pos"
- * extracted from the "n" constraints starting at "constraint".
- * If "n" is zero, then we extract an upper bound from "domain" instead.
+/* Extract an upper bound on dimension "pos" from each constraint
+ * in "constraints" and return the list of upper bounds.
+ * If "constraints" has zero elements, then we extract an upper bound
+ * from "domain" instead.
  */
 static __isl_give isl_pw_aff_list *upper_bounds(
-       __isl_keep isl_constraint **constraint, int n, int pos,
+       __isl_keep isl_constraint_list *constraints, int pos,
        __isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
 {
        isl_ctx *ctx;
        isl_pw_aff_list *list;
-       int i;
+       int i, n;
 
+       n = isl_constraint_list_n_constraint(constraints);
        if (n == 0) {
                isl_pw_aff *pa;
                pa = exact_bound(domain, build, 1);
@@ -509,8 +507,11 @@ static __isl_give isl_pw_aff_list *upper_bounds(
 
        for (i = 0; i < n; ++i) {
                isl_aff *aff;
+               isl_constraint *c;
 
-               aff = isl_constraint_get_bound(constraint[i], isl_dim_set, pos);
+               c = isl_constraint_list_get_constraint(constraints, i);
+               aff = isl_constraint_get_bound(c, isl_dim_set, pos);
+               isl_constraint_free(c);
                aff = isl_aff_floor(aff);
                list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff));
        }
@@ -642,26 +643,26 @@ static __isl_give isl_ast_graft *refine_degenerate(
        return graft;
 }
 
-/* Return the intersection of the "n" constraints starting at "constraint"
- * as a set.
+/* Return the intersection of constraints in "list" as a set.
  */
-static __isl_give isl_set *intersect_constraints(isl_ctx *ctx,
-       __isl_keep isl_constraint **constraint, int n)
+static __isl_give isl_set *intersect_constraints(
+       __isl_keep isl_constraint_list *list)
 {
-       int i;
+       int i, n;
        isl_basic_set *bset;
 
+       n = isl_constraint_list_n_constraint(list);
        if (n < 1)
-               isl_die(ctx, isl_error_internal,
+               isl_die(isl_constraint_list_get_ctx(list), isl_error_internal,
                        "expecting at least one constraint", return NULL);
 
        bset = isl_basic_set_from_constraint(
-                               isl_constraint_copy(constraint[0]));
+                               isl_constraint_list_get_constraint(list, 0));
        for (i = 1; i < n; ++i) {
                isl_basic_set *bset_i;
 
                bset_i = isl_basic_set_from_constraint(
-                                       isl_constraint_copy(constraint[i]));
+                               isl_constraint_list_get_constraint(list, i));
                bset = isl_basic_set_intersect(bset, bset_i);
        }
 
@@ -999,7 +1000,7 @@ static __isl_give isl_ast_graft *set_for_node_expressions(
 /* Update "graft" based on "bounds" and "domain" for the generic,
  * non-degenerate, case.
  *
- * "constraints" contains the "n_lower" lower and "n_upper" upper bounds
+ * "c_lower" and "c_upper" contain the lower and upper bounds
  * that the loop node should express.
  * "domain" is the subset of the intersection of the constraints
  * for which some code is executed.
@@ -1029,7 +1030,8 @@ static __isl_give isl_ast_graft *set_for_node_expressions(
  */
 static __isl_give isl_ast_graft *refine_generic_bounds(
        __isl_take isl_ast_graft *graft,
-       __isl_keep isl_constraint **constraint, int n_lower, int n_upper,
+       __isl_take isl_constraint_list *c_lower,
+       __isl_take isl_constraint_list *c_upper,
        __isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
 {
        int depth;
@@ -1038,23 +1040,25 @@ static __isl_give isl_ast_graft *refine_generic_bounds(
        int use_list;
        isl_set *upper_set = NULL;
        isl_pw_aff_list *upper_list = NULL;
+       int n_lower, n_upper;
 
-       if (!graft || !build)
-               return isl_ast_graft_free(graft);
+       if (!graft || !c_lower || !c_upper || !build)
+               goto error;
 
        depth = isl_ast_build_get_depth(build);
        ctx = isl_ast_graft_get_ctx(graft);
 
+       n_lower = isl_constraint_list_n_constraint(c_lower);
+       n_upper = isl_constraint_list_n_constraint(c_upper);
+
        use_list = use_upper_bound_list(ctx, n_upper, domain, depth);
 
-       lower = lower_bounds(constraint, n_lower, depth, domain, build);
+       lower = lower_bounds(c_lower, depth, domain, build);
 
        if (use_list)
-               upper_list = upper_bounds(constraint + n_lower, n_upper, depth,
-                                           domain, build);
+               upper_list = upper_bounds(c_upper, depth, domain, build);
        else if (n_upper > 0)
-               upper_set = intersect_constraints(ctx, constraint + n_lower,
-                                                       n_upper);
+               upper_set = intersect_constraints(c_upper);
        else
                upper_set = isl_set_universe(isl_set_get_space(domain));
 
@@ -1071,26 +1075,46 @@ static __isl_give isl_ast_graft *refine_generic_bounds(
        isl_pw_aff_list_free(lower);
        isl_pw_aff_list_free(upper_list);
        isl_set_free(upper_set);
+       isl_constraint_list_free(c_lower);
+       isl_constraint_list_free(c_upper);
 
        return graft;
+error:
+       isl_constraint_list_free(c_lower);
+       isl_constraint_list_free(c_upper);
+       return isl_ast_graft_free(graft);
 }
 
-/* How many constraints in the "constraint" array, starting at position "first"
- * are of the give type?  "n" represents the total number of elements
- * in the array.
+/* Internal data structure used inside count_constraints to keep
+ * track of the number of constraints that are independent of dimension "pos",
+ * the lower bounds in "pos" and the upper bounds in "pos".
  */
-static int count_constraints(isl_constraint **constraint, int n, int first,
-       int pos, int type)
+struct isl_ast_count_constraints_data {
+       int pos;
+
+       int n_indep;
+       int n_lower;
+       int n_upper;
+};
+
+/* Increment data->n_indep, data->lower or data->upper depending
+ * on whether "c" is independenct of dimensions data->pos,
+ * a lower bound or an upper bound.
+ */
+static int count_constraints(__isl_take isl_constraint *c, void *user)
 {
-       int i;
+       struct isl_ast_count_constraints_data *data = user;
 
-       constraint += first;
+       if (isl_constraint_is_lower_bound(c, isl_dim_set, data->pos))
+               data->n_lower++;
+       else if (isl_constraint_is_upper_bound(c, isl_dim_set, data->pos))
+               data->n_upper++;
+       else
+               data->n_indep++;
 
-       for (i = 0; first + i < n; i++)
-               if (constraint_type(constraint[i], pos) != type)
-                       break;
+       isl_constraint_free(c);
 
-       return i;
+       return 0;
 }
 
 /* Update "graft" based on "bounds" and "domain" for the generic,
@@ -1112,42 +1136,51 @@ static int count_constraints(isl_constraint **constraint, int n, int first,
  * where this guard is enforced.
  */
 static __isl_give isl_ast_graft *refine_generic_split(
-       __isl_take isl_ast_graft *graft, __isl_keep isl_constraint_list *list,
+       __isl_take isl_ast_graft *graft, __isl_take isl_constraint_list *list,
        __isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
 {
-       isl_ctx *ctx;
        isl_ast_build *for_build;
        isl_set *guard;
-       int n_indep, n_lower, n_upper;
-       int pos;
-       int n;
+       struct isl_ast_count_constraints_data data;
+       isl_constraint_list *lower;
+       isl_constraint_list *upper;
 
        if (!list)
                return isl_ast_graft_free(graft);
 
-       pos = isl_ast_build_get_depth(build);
+       data.pos = isl_ast_build_get_depth(build);
 
-       if (isl_sort(list->p, list->n, sizeof(isl_constraint *),
-                       &cmp_constraint, &pos) < 0)
+       list = isl_constraint_list_sort(list, &cmp_constraint, &data.pos);
+       if (!list)
                return isl_ast_graft_free(graft);
 
-       n = list->n;
-       n_indep = count_constraints(list->p, n, 0, pos, 0);
-       n_lower = count_constraints(list->p, n, n_indep, pos, 1);
-       n_upper = count_constraints(list->p, n, n_indep + n_lower, pos, 2);
+       data.n_indep = data.n_lower = data.n_upper = 0;
+       if (isl_constraint_list_foreach(list, &count_constraints, &data) < 0) {
+               isl_constraint_list_free(list);
+               return isl_ast_graft_free(graft);
+       }
 
-       if (n_indep == 0)
-               return refine_generic_bounds(graft,
-                    list->p + n_indep, n_lower, n_upper, domain, build);
+       lower = isl_constraint_list_copy(list);
+       lower = isl_constraint_list_drop(lower, 0, data.n_indep);
+       upper = isl_constraint_list_copy(lower);
+       lower = isl_constraint_list_drop(lower, data.n_lower, data.n_upper);
+       upper = isl_constraint_list_drop(upper, 0, data.n_lower);
 
-       ctx = isl_ast_graft_get_ctx(graft);
-       guard = intersect_constraints(ctx, list->p, n_indep);
+       if (data.n_indep == 0) {
+               isl_constraint_list_free(list);
+               return refine_generic_bounds(graft, lower, upper,
+                                               domain, build);
+       }
+
+       list = isl_constraint_list_drop(list, data.n_indep,
+                                       data.n_lower + data.n_upper);
+       guard = intersect_constraints(list);
+       isl_constraint_list_free(list);
 
        for_build = isl_ast_build_copy(build);
        for_build = isl_ast_build_restrict_pending(for_build,
                                                isl_set_copy(guard));
-       graft = refine_generic_bounds(graft,
-                    list->p + n_indep, n_lower, n_upper, domain, for_build);
+       graft = refine_generic_bounds(graft, lower, upper, domain, for_build);
        isl_ast_build_free(for_build);
 
        graft = isl_ast_graft_add_guard(graft, guard, build);
@@ -1205,7 +1238,6 @@ static __isl_give isl_ast_graft *refine_generic(
        graft = refine_generic_split(graft, list, domain, build);
        graft = add_stride_guard(graft, build);
 
-       isl_constraint_list_free(list);
        return graft;
 }
 
@@ -1272,8 +1304,13 @@ static __isl_give isl_ast_node *create_for(__isl_keep isl_ast_build *build,
  * it can be printed as an assignment of the single value to the loop
  * "iterator".
  *
- * If the current level is eliminated, we eliminate the current dimension
- * from the inverse schedule to make sure no inner dimensions depend
+ * If the current level is eliminated, we explicitly plug in the value
+ * for the current level found by isl_ast_build_set_loop_bounds in the
+ * inverse schedule.  This ensures that if we are working on a slice
+ * of the domain based on information available in the inverse schedule
+ * and the build domain, that then this information is also reflected
+ * in the inverse schedule.  This operation also eliminates the current
+ * dimension from the inverse schedule making sure no inner dimensions depend
  * on the current dimension.  Otherwise, we create a for node, marking
  * it degenerate if appropriate.  The initial for node is still incomplete
  * and will be completed in either refine_degenerate or refine_generic.
@@ -1316,7 +1353,7 @@ static __isl_give isl_ast_graft *create_node_scaled(
        if (degenerate < 0 || eliminated < 0)
                executed = isl_union_map_free(executed);
        if (eliminated)
-               executed = eliminate(executed, depth, build);
+               executed = plug_in_values(executed, sub_build);
        else
                node = create_for(build, degenerate);
 
@@ -1630,49 +1667,105 @@ done:
        return list;
 }
 
-struct isl_domain_follows_at_depth_data {
-       int depth;
-       isl_basic_set **piece;
-};
-
 /* Does any element of i follow or coincide with any element of j
- * at the current depth (data->depth) for equal values of the outer
- * dimensions?
+ * at the current depth for equal values of the outer dimensions?
  */
-static int domain_follows_at_depth(int i, int j, void *user)
+static int domain_follows_at_depth(__isl_keep isl_basic_set *i,
+       __isl_keep isl_basic_set *j, void *user)
 {
-       struct isl_domain_follows_at_depth_data *data = user;
+       int depth = *(int *) user;
        isl_basic_map *test;
        int empty;
        int l;
 
-       test = isl_basic_map_from_domain_and_range(
-                       isl_basic_set_copy(data->piece[i]),
-                       isl_basic_set_copy(data->piece[j]));
-       for (l = 0; l < data->depth; ++l)
+       test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i),
+                                                   isl_basic_set_copy(j));
+       for (l = 0; l < depth; ++l)
                test = isl_basic_map_equate(test, isl_dim_in, l,
                                                isl_dim_out, l);
-       test = isl_basic_map_order_ge(test, isl_dim_in, data->depth,
-                                       isl_dim_out, data->depth);
+       test = isl_basic_map_order_ge(test, isl_dim_in, depth,
+                                       isl_dim_out, depth);
        empty = isl_basic_map_is_empty(test);
        isl_basic_map_free(test);
 
        return empty < 0 ? -1 : !empty;
 }
 
+/* Split up each element of "list" into a part that is related to "bset"
+ * according to "gt" and a part that is not.
+ * Return a list that consist of "bset" and all the pieces.
+ */
+static __isl_give isl_basic_set_list *add_split_on(
+       __isl_take isl_basic_set_list *list, __isl_take isl_basic_set *bset,
+       __isl_keep isl_basic_map *gt)
+{
+       int i, n;
+       isl_basic_set_list *res;
+
+       gt = isl_basic_map_copy(gt);
+       gt = isl_basic_map_intersect_domain(gt, isl_basic_set_copy(bset));
+       n = isl_basic_set_list_n_basic_set(list);
+       res = isl_basic_set_list_from_basic_set(bset);
+       for (i = 0; res && i < n; ++i) {
+               isl_basic_set *bset;
+               isl_set *set1, *set2;
+               isl_basic_map *bmap;
+               int empty;
+
+               bset = isl_basic_set_list_get_basic_set(list, i);
+               bmap = isl_basic_map_copy(gt);
+               bmap = isl_basic_map_intersect_range(bmap, bset);
+               bset = isl_basic_map_range(bmap);
+               empty = isl_basic_set_is_empty(bset);
+               if (empty < 0)
+                       res = isl_basic_set_list_free(res);
+               if (empty)  {
+                       isl_basic_set_free(bset);
+                       bset = isl_basic_set_list_get_basic_set(list, i);
+                       res = isl_basic_set_list_add(res, bset);
+                       continue;
+               }
+
+               res = isl_basic_set_list_add(res, isl_basic_set_copy(bset));
+               set1 = isl_set_from_basic_set(bset);
+               bset = isl_basic_set_list_get_basic_set(list, i);
+               set2 = isl_set_from_basic_set(bset);
+               set1 = isl_set_subtract(set2, set1);
+               set1 = isl_set_make_disjoint(set1);
+
+               res = isl_basic_set_list_concat(res,
+                                           isl_basic_set_list_from_set(set1));
+       }
+       isl_basic_map_free(gt);
+       isl_basic_set_list_free(list);
+       return res;
+}
+
 static __isl_give isl_ast_graft_list *generate_sorted_domains(
        __isl_keep isl_basic_set_list *domain_list,
        __isl_keep isl_union_map *executed,
        __isl_keep isl_ast_build *build);
 
-/* Generate code for the "n" schedule domains in "domain_list"
- * with positions specified by the entries of the "pos" array
+/* Internal data structure for add_nodes.
+ *
+ * "executed" and "build" are extra arguments to be passed to add_node.
+ * "list" collects the results.
+ */
+struct isl_add_nodes_data {
+       isl_union_map *executed;
+       isl_ast_build *build;
+
+       isl_ast_graft_list *list;
+};
+
+/* Generate code for the schedule domains in "scc"
  * and add the results to "list".
  *
- * The "n" domains form a strongly connected component in the ordering.
- * If n is larger than 1, then this means that we cannot determine a valid
- * ordering for the n domains in the component.  This should be fairly
- * rare because the individual domains have been made disjoint first.
+ * The domains in "scc" form a strongly connected component in the ordering.
+ * If the number of domains in "scc" is larger than 1, then this means
+ * that we cannot determine a valid ordering for the domains in the component.
+ * This should be fairly rare because the individual domains
+ * have been made disjoint first.
  * The problem is that the domains may be integrally disjoint but not
  * rationally disjoint.  For example, we may have domains
  *
@@ -1687,52 +1780,51 @@ static __isl_give isl_ast_graft_list *generate_sorted_domains(
  * This may happen in particular in case of unrolling since the domain
  * of each slice is replaced by its simple hull.
  *
- * We collect the basic sets in the component, call isl_set_make_disjoint
- * and try again.  Note that we rely here on isl_set_make_disjoint also
- * making the basic sets rationally disjoint.  If the basic sets
- * are rationally disjoint, then the ordering problem does not occur.
- * To see this, there can only be a problem if there are points
- * (i,a) and (j,b) in one set and (i,c) and (j,d) in the other with
- * a < c and b > d.  This means that either the interval spanned
- * by a en b lies inside that spanned by c and or the other way around.
- * In either case, there is a point inside both intervals with the
- * convex combination in terms of a and b and in terms of c and d.
- * Taking the same combination of i and j gives a point in the intersection.
- */
-static __isl_give isl_ast_graft_list *add_nodes(
-       __isl_take isl_ast_graft_list *list, int *pos, int n,
-       __isl_keep isl_basic_set_list *domain_list,
-       __isl_keep isl_union_map *executed,
-       __isl_keep isl_ast_build *build)
+ * For each basic set i in "scc" and for each of the following basic sets j,
+ * we split off that part of the basic set i that shares the outer dimensions
+ * with j and lies before j in the current dimension.
+ * We collect all the pieces in a new list that replaces "scc".
+ */
+static int add_nodes(__isl_take isl_basic_set_list *scc, void *user)
 {
-       int i;
+       struct isl_add_nodes_data *data = user;
+       int i, n, depth;
        isl_basic_set *bset;
-       isl_set *set;
+       isl_basic_set_list *list;
+       isl_space *space;
+       isl_basic_map *gt;
+
+       n = isl_basic_set_list_n_basic_set(scc);
+       bset = isl_basic_set_list_get_basic_set(scc, 0);
+       if (n == 1) {
+               isl_basic_set_list_free(scc);
+               data->list = add_node(data->list,
+                               isl_union_map_copy(data->executed), bset,
+                               isl_ast_build_copy(data->build));
+               return data->list ? 0 : -1;
+       }
 
-       bset = isl_basic_set_list_get_basic_set(domain_list, pos[0]);
-       if (n == 1)
-               return add_node(list, isl_union_map_copy(executed), bset,
-                               isl_ast_build_copy(build));
+       depth = isl_ast_build_get_depth(data->build);
+       space = isl_basic_set_get_space(bset);
+       space = isl_space_map_from_set(space);
+       gt = isl_basic_map_universe(space);
+       for (i = 0; i < depth; ++i)
+               gt = isl_basic_map_equate(gt, isl_dim_in, i, isl_dim_out, i);
+       gt = isl_basic_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth);
 
-       set = isl_set_from_basic_set(bset);
+       list = isl_basic_set_list_from_basic_set(bset);
        for (i = 1; i < n; ++i) {
-               bset = isl_basic_set_list_get_basic_set(domain_list, pos[i]);
-               set = isl_set_union(set, isl_set_from_basic_set(bset));
+               bset = isl_basic_set_list_get_basic_set(scc, i);
+               list = add_split_on(list, bset, gt);
        }
+       isl_basic_map_free(gt);
+       isl_basic_set_list_free(scc);
+       scc = list;
+       data->list = isl_ast_graft_list_concat(data->list,
+                   generate_sorted_domains(scc, data->executed, data->build));
+       isl_basic_set_list_free(scc);
 
-       set = isl_set_make_disjoint(set);
-       if (isl_set_n_basic_set(set) == n)
-               isl_die(isl_ast_graft_list_get_ctx(list), isl_error_internal,
-                       "unable to separate loop parts", goto error);
-       domain_list = isl_basic_set_list_from_set(set);
-       list = isl_ast_graft_list_concat(list,
-                   generate_sorted_domains(domain_list, executed, build));
-       isl_basic_set_list_free(domain_list);
-
-       return list;
-error:
-       isl_set_free(set);
-       return isl_ast_graft_list_free(list);
+       return data->list ? 0 : -1;
 }
 
 /* Sort the domains in "domain_list" according to the execution order
@@ -1753,71 +1845,47 @@ static __isl_give isl_ast_graft_list *generate_sorted_domains(
        __isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build)
 {
        isl_ctx *ctx;
-       isl_ast_graft_list *list;
-       struct isl_domain_follows_at_depth_data data;
-       struct isl_tarjan_graph *g;
-       int i, n;
+       struct isl_add_nodes_data data;
+       int depth;
+       int n;
 
        if (!domain_list)
                return NULL;
 
        ctx = isl_basic_set_list_get_ctx(domain_list);
        n = isl_basic_set_list_n_basic_set(domain_list);
-       list = isl_ast_graft_list_alloc(ctx, n);
+       data.list = isl_ast_graft_list_alloc(ctx, n);
        if (n == 0)
-               return list;
+               return data.list;
        if (n == 1)
-               return add_node(list, isl_union_map_copy(executed),
+               return add_node(data.list, isl_union_map_copy(executed),
                        isl_basic_set_list_get_basic_set(domain_list, 0),
                        isl_ast_build_copy(build));
 
-       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) {
-               int first;
-
-               if (g->order[i] == -1)
-                       isl_die(ctx, isl_error_internal, "cannot happen",
-                               goto error);
-               first = i;
-               while (g->order[i] != -1) {
-                       ++i; --n;
-               }
-               list = add_nodes(list, g->order + first, i - first,
-                                       domain_list, executed, build);
-               ++i;
-       }
-
-       if (0)
-error:         list = isl_ast_graft_list_free(list);
-       isl_tarjan_graph_free(g);
+       depth = isl_ast_build_get_depth(build);
+       data.executed = executed;
+       data.build = build;
+       if (isl_basic_set_list_foreach_scc(domain_list,
+                                       &domain_follows_at_depth, &depth,
+                                       &add_nodes, &data) < 0)
+               data.list = isl_ast_graft_list_free(data.list);
 
-       return list;
+       return data.list;
 }
 
-struct isl_shared_outer_data {
-       int depth;
-       isl_basic_set **piece;
-};
-
-/* Do elements i and j share any values for the outer dimensions?
+/* Do i and j share any values for the outer dimensions?
  */
-static int shared_outer(int i, int j, void *user)
+static int shared_outer(__isl_keep isl_basic_set *i,
+       __isl_keep isl_basic_set *j, void *user)
 {
-       struct isl_shared_outer_data *data = user;
+       int depth = *(int *) user;
        isl_basic_map *test;
        int empty;
        int l;
 
-       test = isl_basic_map_from_domain_and_range(
-                       isl_basic_set_copy(data->piece[i]),
-                       isl_basic_set_copy(data->piece[j]));
-       for (l = 0; l < data->depth; ++l)
+       test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i),
+                                                   isl_basic_set_copy(j));
+       for (l = 0; l < depth; ++l)
                test = isl_basic_map_equate(test, isl_dim_in, l,
                                                isl_dim_out, l);
        empty = isl_basic_map_is_empty(test);
@@ -1826,44 +1894,67 @@ static int shared_outer(int i, int j, void *user)
        return empty < 0 ? -1 : !empty;
 }
 
-/* Call generate_sorted_domains on a list containing the elements
- * of "domain_list indexed by the first "n" elements of "pos".
+/* Internal data structure for generate_sorted_domains_wrap.
+ *
+ * "n" is the total number of basic sets
+ * "executed" and "build" are extra arguments to be passed
+ *     to generate_sorted_domains.
+ *
+ * "single" is set to 1 by generate_sorted_domains_wrap if there
+ * is only a single component.
+ * "list" collects the results.
  */
-static __isl_give isl_ast_graft_list *generate_sorted_domains_part(
-       __isl_keep isl_basic_set_list *domain_list, int *pos, int n,
-       __isl_keep isl_union_map *executed,
-       __isl_keep isl_ast_build *build)
-{
-       int i;
-       isl_ctx *ctx;
-       isl_basic_set_list *slice;
+struct isl_ast_generate_parallel_domains_data {
+       int n;
+       isl_union_map *executed;
+       isl_ast_build *build;
+
+       int single;
        isl_ast_graft_list *list;
+};
 
-       ctx = isl_ast_build_get_ctx(build);
-       slice = isl_basic_set_list_alloc(ctx, n);
-       for (i = 0; i < n; ++i) {
-               isl_basic_set *bset;
+/* Call generate_sorted_domains on "scc", fuse the result into a list
+ * with either zero or one graft and collect the these single element
+ * lists into data->list.
+ *
+ * If there is only one component, i.e., if the number of basic sets
+ * in the current component is equal to the total number of basic sets,
+ * then data->single is set to 1 and the result of generate_sorted_domains
+ * is not fused.
+ */
+static int generate_sorted_domains_wrap(__isl_take isl_basic_set_list *scc,
+       void *user)
+{
+       struct isl_ast_generate_parallel_domains_data *data = user;
+       isl_ast_graft_list *list;
 
-               bset = isl_basic_set_copy(domain_list->p[pos[i]]);
-               slice = isl_basic_set_list_add(slice, bset);
-       }
+       list = generate_sorted_domains(scc, data->executed, data->build);
+       data->single = isl_basic_set_list_n_basic_set(scc) == data->n;
+       if (!data->single)
+               list = isl_ast_graft_list_fuse(list, data->build);
+       if (!data->list)
+               data->list = list;
+       else
+               data->list = isl_ast_graft_list_concat(data->list, list);
 
-       list = generate_sorted_domains(slice, executed, build);
-       isl_basic_set_list_free(slice);
+       isl_basic_set_list_free(scc);
+       if (!data->list)
+               return -1;
 
-       return list;
+       return 0;
 }
 
 /* Look for any (weakly connected) components in the "domain_list"
  * 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.
  *
- * We fuse the result of each call to generate_sorted_domains_part
- * into a list with either zero or one graft and collect these (at most)
+ * If there is more than one component, then generate_sorted_domains_wrap
+ * fuses the result of each call to generate_sorted_domains
+ * into a list with either zero or one graft and collects these (at most)
  * single element lists into a bigger list. This means that the elements of the
  * final list can be freely reordered.  In particular, we sort them
  * according to an arbitrary but fixed ordering to ease merging of
@@ -1873,62 +1964,30 @@ static __isl_give isl_ast_graft_list *generate_parallel_domains(
        __isl_keep isl_basic_set_list *domain_list,
        __isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build)
 {
-       int i, n;
-       isl_ctx *ctx;
-       isl_ast_graft_list *list;
-       struct isl_shared_outer_data data;
-       struct isl_tarjan_graph *g;
+       int depth;
+       struct isl_ast_generate_parallel_domains_data data;
 
        if (!domain_list)
                return NULL;
 
-       n = isl_basic_set_list_n_basic_set(domain_list);
-       if (n <= 1)
+       data.n = isl_basic_set_list_n_basic_set(domain_list);
+       if (data.n <= 1)
                return generate_sorted_domains(domain_list, executed, build);
 
-       ctx = isl_basic_set_list_get_ctx(domain_list);
-
-       data.depth = isl_ast_build_get_depth(build);
-       data.piece = domain_list->p;
-       g = isl_tarjan_graph_init(ctx, n, &shared_outer, &data);
-       if (!g)
-               return NULL;
-
-       i = 0;
-       do {
-               int first;
-               isl_ast_graft_list *list_c;
-
-               if (g->order[i] == -1)
-                       isl_die(ctx, isl_error_internal, "cannot happen",
-                               break);
-               first = i;
-               while (g->order[i] != -1) {
-                       ++i; --n;
-               }
-               if (first == 0 && n == 0) {
-                       isl_tarjan_graph_free(g);
-                       return generate_sorted_domains(domain_list,
-                                                       executed, build);
-               }
-               list_c = generate_sorted_domains_part(domain_list,
-                               g->order + first, i - first, executed, build);
-               list_c = isl_ast_graft_list_fuse(list_c, build);
-               if (first == 0)
-                       list = list_c;
-               else
-                       list = isl_ast_graft_list_concat(list, list_c);
-               ++i;
-       } while (list && n);
-
-       if (n > 0)
-               list = isl_ast_graft_list_free(list);
-
-       list = isl_ast_graft_list_sort(list);
+       depth = isl_ast_build_get_depth(build);
+       data.list = NULL;
+       data.executed = executed;
+       data.build = build;
+       data.single = 0;
+       if (isl_basic_set_list_foreach_scc(domain_list, &shared_outer, &depth,
+                                           &generate_sorted_domains_wrap,
+                                           &data) < 0)
+               data.list = isl_ast_graft_list_free(data.list);
 
-       isl_tarjan_graph_free(g);
+       if (!data.single)
+               data.list = isl_ast_graft_list_sort_guard(data.list);
 
-       return list;
+       return data.list;
 }
 
 /* Internal data for separate_domain.
@@ -2309,7 +2368,7 @@ static __isl_give isl_basic_set_list *do_unroll(__isl_take isl_set *domain,
  *
  * "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]
index 8173433..0ec839b 100644 (file)
@@ -7,7 +7,6 @@
  * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
  */
 
-#include <isl_list_private.h>
 #include <isl_ast_private.h>
 #include <isl_ast_build_expr.h>
 #include <isl_ast_build_private.h>
@@ -178,6 +177,8 @@ static __isl_give isl_set *extract_hoistable_guard(
 
        depth = isl_ast_build_get_depth(build);
        if (depth < isl_set_dim(guard, isl_dim_set)) {
+               guard = isl_set_remove_divs_involving_dims(guard,
+                                               isl_dim_set, depth, 1);
                guard = isl_set_eliminate(guard, isl_dim_set, depth, 1);
                guard = isl_set_compute_divs(guard);
        }
@@ -207,6 +208,78 @@ static __isl_give isl_set *extract_hoistable_guard(
        return guard;
 }
 
+/* Internal data structure used inside insert_if.
+ *
+ * list is the list of guarded nodes created by each call to insert_if.
+ * node is the original node that is guarded by insert_if.
+ * build is the build in which the AST is constructed.
+ */
+struct isl_insert_if_data {
+       isl_ast_node_list *list;
+       isl_ast_node *node;
+       isl_ast_build *build;
+};
+
+static int insert_if(__isl_take isl_basic_set *bset, void *user);
+
+/* Insert an if node around "node" testing the condition encoded
+ * in guard "guard".
+ *
+ * If the user does not want any disjunctions in the if conditions
+ * and if "guard" does involve a disjunction, then we make the different
+ * disjuncts disjoint and insert an if node corresponding to each disjunct
+ * around a copy of "node".  The result is then a block node containing
+ * this sequence of guarded copies of "node".
+ */
+static __isl_give isl_ast_node *ast_node_insert_if(
+       __isl_take isl_ast_node *node, __isl_take isl_set *guard,
+       __isl_keep isl_ast_build *build)
+{
+       struct isl_insert_if_data data;
+       isl_ctx *ctx;
+
+       ctx = isl_ast_build_get_ctx(build);
+       if (isl_options_get_ast_build_allow_or(ctx) ||
+           isl_set_n_basic_set(guard) <= 1) {
+               isl_ast_node *if_node;
+               isl_ast_expr *expr;
+
+               expr = isl_ast_build_expr_from_set(build, guard);
+
+               if_node = isl_ast_node_alloc_if(expr);
+               return isl_ast_node_if_set_then(if_node, node);
+       }
+
+       guard = isl_set_make_disjoint(guard);
+
+       data.list = isl_ast_node_list_alloc(ctx, 0);
+       data.node = node;
+       data.build = build;
+       if (isl_set_foreach_basic_set(guard, &insert_if, &data) < 0)
+               data.list = isl_ast_node_list_free(data.list);
+
+       isl_set_free(guard);
+       isl_ast_node_free(data.node);
+       return isl_ast_node_alloc_block(data.list);
+}
+
+/* Insert an if node around a copy of "data->node" testing the condition
+ * encoded in guard "bset" and add the result to data->list.
+ */
+static int insert_if(__isl_take isl_basic_set *bset, void *user)
+{
+       struct isl_insert_if_data *data = user;
+       isl_ast_node *node;
+       isl_set *set;
+
+       set = isl_set_from_basic_set(bset);
+       node = isl_ast_node_copy(data->node);
+       node = ast_node_insert_if(node, set, data->build);
+       data->list = isl_ast_node_list_add(data->list, node);
+
+       return 0;
+}
+
 /* Insert an if node around graft->node testing the condition encoded
  * in guard "guard", assuming guard involves any conditions.
  */
@@ -215,8 +288,6 @@ static __isl_give isl_ast_graft *insert_if_node(
        __isl_keep isl_ast_build *build)
 {
        int univ;
-       isl_ast_node *node;
-       isl_ast_expr *expr;
 
        if (!graft)
                goto error;
@@ -232,12 +303,9 @@ static __isl_give isl_ast_graft *insert_if_node(
        build = isl_ast_build_copy(build);
        build = isl_ast_build_set_enforced(build,
                                        isl_ast_graft_get_enforced(graft));
-       expr = isl_ast_build_expr_from_set(build, guard);
+       graft->node = ast_node_insert_if(graft->node, guard, build);
        isl_ast_build_free(build);
 
-       node = isl_ast_node_alloc_if(expr);
-       graft->node = isl_ast_node_if_set_then(node, graft->node);
-
        if (!graft->node)
                return isl_ast_graft_free(graft);
 
@@ -617,7 +685,8 @@ static __isl_give isl_basic_set *extract_shared_enforced(
 /* Record "guard" in "graft" so that it will be enforced somewhere
  * up the tree.  If the graft already has a guard, then it may be partially
  * redundant in combination with the new guard and in the context
- * of build->domain.  We therefore (re)compute the gist of the intersection.
+ * of build->domain.  We therefore (re)compute the gist of the intersection
+ * and coalesce the result.
  */
 static __isl_give isl_ast_graft *store_guard(__isl_take isl_ast_graft *graft,
        __isl_take isl_set *guard, __isl_keep isl_ast_build *build)
@@ -637,6 +706,7 @@ static __isl_give isl_ast_graft *store_guard(__isl_take isl_ast_graft *graft,
 
        graft->guard = isl_set_intersect(graft->guard, guard);
        graft->guard = isl_ast_build_compute_gist(build, graft->guard);
+       graft->guard = isl_set_coalesce(graft->guard);
        if (!graft->guard)
                return isl_ast_graft_free(graft);
 
@@ -1004,27 +1074,18 @@ __isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff(
 
 /* Compare two grafts based on their guards.
  */
-static int cmp_graft(const void *a, const void *b)
+static int cmp_graft(__isl_keep isl_ast_graft *a, __isl_keep isl_ast_graft *b,
+       void *user)
 {
-       isl_ast_graft * const *g1 = a;
-       isl_ast_graft * const *g2 = b;
-
-       return isl_set_plain_cmp((*g1)->guard, (*g2)->guard);
+       return isl_set_plain_cmp(a->guard, b->guard);
 }
 
 /* Order the elements in "list" based on their guards.
  */
-__isl_give isl_ast_graft_list *isl_ast_graft_list_sort(
+__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard(
        __isl_take isl_ast_graft_list *list)
 {
-       if (!list)
-               return NULL;
-       if (list->n <= 1)
-               return list;
-
-       qsort(list->p, list->n, sizeof(list->p[0]), &cmp_graft);
-
-       return list;
+       return isl_ast_graft_list_sort(list, &cmp_graft, NULL);
 }
 
 /* Merge the given two lists into a single list of grafts,
index 7bd54bc..ab44e59 100644 (file)
@@ -53,7 +53,7 @@ __isl_give isl_ast_graft_list *isl_ast_graft_list_fuse(
 __isl_give isl_ast_graft *isl_ast_graft_alloc_domain(
        __isl_take isl_map *schedule, __isl_keep isl_ast_build *build);
 void *isl_ast_graft_free(__isl_take isl_ast_graft *graft);
-__isl_give isl_ast_graft_list *isl_ast_graft_list_sort(
+__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard(
        __isl_take isl_ast_graft_list *list);
 
 __isl_give isl_ast_graft_list *isl_ast_graft_list_merge(
index e545a8a..43e9f01 100644 (file)
@@ -1,16 +1,22 @@
 /*
  * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
  * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
  */
 
 #include <isl_band_private.h>
 #include <isl_schedule_private.h>
-#include <isl_list_private.h>
+
+#undef BASE
+#define BASE band
+
+#include <isl_list_templ.c>
 
 isl_ctx *isl_band_get_ctx(__isl_keep isl_band *band)
 {
@@ -445,13 +451,26 @@ error:
  * a child band is created to refer to the point loops.
  * The children of this point loop band are the children
  * of the original band.
+ *
+ * If the scale tile loops option is set, then the tile loops
+ * are scaled by the tile sizes.  If the shift point loops option is set,
+ * then the point loops are shifted to start at zero.
+ * In particular, these options affect the tile and point loop schedules
+ * as follows
+ *
+ *     scale   shift   original        tile            point
+ *
+ *     0       0       i               floor(i/s)      i
+ *     1       0       i               s * floor(i/s)  i
+ *     0       1       i               floor(i/s)      i - s * floor(i/s)
+ *     1       1       i               s * floor(i/s)  i - s * floor(i/s)
  */
 int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes)
 {
        isl_ctx *ctx;
        isl_band *child;
        isl_band_list *list = NULL;
-       isl_union_pw_multi_aff *sched;
+       isl_union_pw_multi_aff *sched = NULL, *child_sched = NULL;
 
        if (!band || !sizes)
                goto error;
@@ -465,7 +484,17 @@ int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes)
 
        sched = isl_union_pw_multi_aff_copy(band->pma);
        sched = isl_union_pw_multi_aff_tile(sched, sizes);
-       if (!sched)
+
+       child_sched = isl_union_pw_multi_aff_copy(child->pma);
+       if (isl_options_get_tile_shift_point_loops(ctx)) {
+               isl_union_pw_multi_aff *scaled;
+               scaled = isl_union_pw_multi_aff_copy(sched);
+               if (!isl_options_get_tile_scale_tile_loops(ctx))
+                       scaled = isl_union_pw_multi_aff_scale_vec(scaled,
+                                                       isl_vec_copy(sizes));
+               child_sched = isl_union_pw_multi_aff_sub(child_sched, scaled);
+       }
+       if (!sched || !child_sched)
                goto error;
 
        child->children = band->children;
@@ -473,15 +502,132 @@ int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes)
        child->parent = band;
        isl_union_pw_multi_aff_free(band->pma);
        band->pma = sched;
+       isl_union_pw_multi_aff_free(child->pma);
+       child->pma = child_sched;
 
        isl_vec_free(sizes);
        return 0;
 error:
+       isl_union_pw_multi_aff_free(sched);
+       isl_union_pw_multi_aff_free(child_sched);
        isl_band_list_free(list);
        isl_vec_free(sizes);
        return -1;
 }
 
+/* Internal data structure used inside isl_union_pw_multi_aff_drop.
+ *
+ * "pos" is the position of the first dimension to drop.
+ * "n" is the number of dimensions to drop.
+ * "res" accumulates the result.
+ */
+struct isl_union_pw_multi_aff_drop_data {
+       int pos;
+       int n;
+       isl_union_pw_multi_aff *res;
+};
+
+/* Drop the data->n output dimensions starting at data->pos from "pma"
+ * and add the result to data->res.
+ */
+static int pw_multi_aff_drop(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+       struct isl_union_pw_multi_aff_drop_data *data = user;
+
+       pma = isl_pw_multi_aff_drop_dims(pma, isl_dim_out, data->pos, data->n);
+
+       data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
+       if (!data->res)
+               return -1;
+
+       return 0;
+}
+
+/* Drop the "n" output dimensions starting at "pos" from "sched".
+ */
+static isl_union_pw_multi_aff *isl_union_pw_multi_aff_drop(
+       __isl_take isl_union_pw_multi_aff *sched, int pos, int n)
+{
+       isl_space *space;
+       struct isl_union_pw_multi_aff_drop_data data = { pos, n };
+
+       space = isl_union_pw_multi_aff_get_space(sched);
+       data.res = isl_union_pw_multi_aff_empty(space);
+
+       if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched,
+                                               &pw_multi_aff_drop, &data) < 0)
+               data.res = isl_union_pw_multi_aff_free(data.res);
+
+       isl_union_pw_multi_aff_free(sched);
+       return data.res;
+}
+
+/* Drop the "n" dimensions starting at "pos" from "band".
+ */
+static int isl_band_drop(__isl_keep isl_band *band, int pos, int n)
+{
+       int i;
+       isl_union_pw_multi_aff *sched;
+
+       if (!band)
+               return -1;
+       if (n == 0)
+               return 0;
+
+       sched = isl_union_pw_multi_aff_copy(band->pma);
+       sched = isl_union_pw_multi_aff_drop(sched, pos, n);
+       if (!sched)
+               return -1;
+
+       isl_union_pw_multi_aff_free(band->pma);
+       band->pma = sched;
+
+       for (i = pos + n; i < band->n; ++i)
+               band->zero[i - n] = band->zero[i];
+
+       band->n -= n;
+
+       return 0;
+}
+
+/* Split the given band into two nested bands, one with the first "pos"
+ * dimensions of "band" and one with the remaining band->n - pos dimensions.
+ */
+int isl_band_split(__isl_keep isl_band *band, int pos)
+{
+       isl_ctx *ctx;
+       isl_band *child;
+       isl_band_list *list;
+
+       if (!band)
+               return -1;
+
+       ctx = isl_band_get_ctx(band);
+
+       if (pos < 0 || pos > band->n)
+               isl_die(ctx, isl_error_invalid, "position out of bounds",
+                       return -1);
+
+       child = isl_band_dup(band);
+       if (isl_band_drop(child, 0, pos) < 0)
+               child = isl_band_free(child);
+       list = isl_band_list_alloc(ctx, 1);
+       list = isl_band_list_add(list, child);
+       if (!list)
+               return -1;
+
+       if (isl_band_drop(band, pos, band->n - pos) < 0) {
+               isl_band_list_free(list);
+               return -1;
+       }
+
+       child->children = band->children;
+       band->children = list;
+       child->parent = band;
+
+       return 0;
+}
+
 __isl_give isl_printer *isl_printer_print_band(__isl_take isl_printer *p,
        __isl_keep isl_band *band)
 {
index 8f201f6..ef0e0ed 100644 (file)
@@ -33,6 +33,11 @@ struct isl_band {
        isl_band_list *children;
 };
 
+#undef EL
+#define EL isl_band
+
+#include <isl_list_templ.h>
+
 __isl_give isl_band *isl_band_alloc(isl_ctx *ctx);
 
 __isl_give isl_union_map *isl_band_list_get_suffix_schedule(
index c2c3bb4..ed80560 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
  * Copyright 2010      INRIA Saclay
- * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
@@ -298,6 +298,124 @@ static int check_facets(struct isl_map *map, int i, int j,
        return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
 }
 
+/* Check if basic map "i" contains the basic map represented
+ * by the tableau "tab".
+ */
+static int contains(struct isl_map *map, int i, int *ineq_i,
+       struct isl_tab *tab)
+{
+       int k, l;
+       unsigned dim;
+
+       dim = isl_basic_map_total_dim(map->p[i]);
+       for (k = 0; k < map->p[i]->n_eq; ++k) {
+               for (l = 0; l < 2; ++l) {
+                       int stat;
+                       isl_seq_neg(map->p[i]->eq[k], map->p[i]->eq[k], 1+dim);
+                       stat = status_in(map->p[i]->eq[k], tab);
+                       if (stat != STATUS_VALID)
+                               return 0;
+               }
+       }
+
+       for (k = 0; k < map->p[i]->n_ineq; ++k) {
+               int stat;
+               if (ineq_i[k] == STATUS_REDUNDANT)
+                       continue;
+               stat = status_in(map->p[i]->ineq[k], tab);
+               if (stat != STATUS_VALID)
+                       return 0;
+       }
+       return 1;
+}
+
+/* Basic map "i" has an inequality (say "k") that is adjacent
+ * to some inequality of basic map "j".  All the other inequalities
+ * are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * Note that this function is only called if some of the equalities or
+ * inequalities of basic map "j" do cut basic map "i".  The function is
+ * correct even if there are no such cut constraints, but in that case
+ * the additional checks performed by this function are overkill.
+ *
+ * In particular, we replace constraint k, say f >= 0, by constraint
+ * f <= -1, add the inequalities of "j" that are valid for "i"
+ * and check if the result is a subset of basic map "j".
+ * If so, then we know that this result is exactly equal to basic map "j"
+ * since all its constraints are valid for basic map "j".
+ * By combining the valid constraints of "i" (all equalities and all
+ * inequalities except "k") and the valid constraints of "j" we therefore
+ * obtain a basic map that is equal to their union.
+ * In this case, there is no need to perform a rollback of the tableau
+ * since it is going to be destroyed in fuse().
+ *
+ *
+ *     |\__                    |\__
+ *     |   \__                 |   \__
+ *     |      \_       =>      |      \__
+ *     |_______| _             |_________\
+ *
+ *
+ *     |\                      |\
+ *     | \                     | \
+ *     |  \                    |  \
+ *     |  |                    |   \
+ *     |  ||\          =>      |    \
+ *     |  || \                 |     \
+ *     |  ||  |                |      |
+ *     |__||_/                 |_____/
+ */
+static int is_adj_ineq_extension(__isl_keep isl_map *map, int i, int j,
+       struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+       int k;
+       struct isl_tab_undo *snap;
+       unsigned n_eq = map->p[i]->n_eq;
+       unsigned total = isl_basic_map_total_dim(map->p[i]);
+       int r;
+
+       if (isl_tab_extend_cons(tabs[i], 1 + map->p[j]->n_ineq) < 0)
+               return -1;
+
+       for (k = 0; k < map->p[i]->n_ineq; ++k)
+               if (ineq_i[k] == STATUS_ADJ_INEQ)
+                       break;
+       if (k >= map->p[i]->n_ineq)
+               isl_die(isl_map_get_ctx(map), isl_error_internal,
+                       "ineq_i should have exactly one STATUS_ADJ_INEQ",
+                       return -1);
+
+       snap = isl_tab_snap(tabs[i]);
+
+       if (isl_tab_unrestrict(tabs[i], n_eq + k) < 0)
+               return -1;
+
+       isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+       isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+       r = isl_tab_add_ineq(tabs[i], map->p[i]->ineq[k]);
+       isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+       isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+       if (r < 0)
+               return -1;
+
+       for (k = 0; k < map->p[j]->n_ineq; ++k) {
+               if (ineq_j[k] != STATUS_VALID)
+                       continue;
+               if (isl_tab_add_ineq(tabs[i], map->p[j]->ineq[k]) < 0)
+                       return -1;
+       }
+
+       if (contains(map, j, ineq_j, tabs[i]))
+               return fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, NULL);
+
+       if (isl_tab_rollback(tabs[i], snap) < 0)
+               return -1;
+
+       return 0;
+}
+
+
 /* Both basic maps have at least one inequality with and adjacent
  * (but opposite) inequality in the other basic map.
  * Check that there are no cut constraints and that there is only
@@ -324,53 +442,40 @@ static int check_facets(struct isl_map *map, int i, int j,
  *         |   |
  *         |   |
  *         |___|
+ *
+ * If there are some cut constraints on one side, then we may
+ * still be able to fuse the two basic maps, but we need to perform
+ * some additional checks in is_adj_ineq_extension.
  */
 static int check_adj_ineq(struct isl_map *map, int i, int j,
-       struct isl_tab **tabs, int *ineq_i, int *ineq_j)
+       struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
 {
-       int changed = 0;
+       int count_i, count_j;
+       int cut_i, cut_j;
 
-       if (any(ineq_i, map->p[i]->n_ineq, STATUS_CUT) ||
-           any(ineq_j, map->p[j]->n_ineq, STATUS_CUT))
-               /* ADJ INEQ CUT */
-               ;
-       else if (count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) == 1 &&
-                count(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ) == 1)
-               changed = fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
-       /* else ADJ INEQ TOO MANY */
+       count_i = count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ);
+       count_j = count(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ);
 
-       return changed;
-}
+       if (count_i != 1 && count_j != 1)
+               return 0;
 
-/* Check if basic map "i" contains the basic map represented
- * by the tableau "tab".
- */
-static int contains(struct isl_map *map, int i, int *ineq_i,
-       struct isl_tab *tab)
-{
-       int k, l;
-       unsigned dim;
+       cut_i = any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) ||
+               any(ineq_i, map->p[i]->n_ineq, STATUS_CUT);
+       cut_j = any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT) ||
+               any(ineq_j, map->p[j]->n_ineq, STATUS_CUT);
 
-       dim = isl_basic_map_total_dim(map->p[i]);
-       for (k = 0; k < map->p[i]->n_eq; ++k) {
-               for (l = 0; l < 2; ++l) {
-                       int stat;
-                       isl_seq_neg(map->p[i]->eq[k], map->p[i]->eq[k], 1+dim);
-                       stat = status_in(map->p[i]->eq[k], tab);
-                       if (stat != STATUS_VALID)
-                               return 0;
-               }
-       }
+       if (!cut_i && !cut_j && count_i == 1 && count_j == 1)
+               return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
 
-       for (k = 0; k < map->p[i]->n_ineq; ++k) {
-               int stat;
-               if (ineq_i[k] == STATUS_REDUNDANT)
-                       continue;
-               stat = status_in(map->p[i]->ineq[k], tab);
-               if (stat != STATUS_VALID)
-                       return 0;
-       }
-       return 1;
+       if (count_i == 1 && !cut_i)
+               return is_adj_ineq_extension(map, i, j, tabs,
+                                               eq_i, ineq_i, eq_j, ineq_j);
+
+       if (count_j == 1 && !cut_j)
+               return is_adj_ineq_extension(map, j, i, tabs,
+                                               eq_j, ineq_j, eq_i, ineq_i);
+
+       return 0;
 }
 
 /* Basic map "i" has an inequality "k" that is adjacent to some equality
@@ -383,7 +488,7 @@ static int contains(struct isl_map *map, int i, int *ineq_i,
  * map with exactly the other basic map (we already know that this
  * other basic map is included in the extension, because there
  * were no "cut" inequalities in "i") and we can replace the
- * two basic maps by thie extension.
+ * two basic maps by this extension.
  *        ____                   _____
  *       /    ||                /     |
  *      /     ||               /      |
@@ -391,7 +496,7 @@ static int contains(struct isl_map *map, int i, int *ineq_i,
  *       \    ||                \     |
  *        \___||                 \____|
  */
-static int is_extension(struct isl_map *map, int i, int j, int k,
+static int is_adj_eq_extension(struct isl_map *map, int i, int j, int k,
        struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
 {
        int changed = 0;
@@ -1048,11 +1153,12 @@ static int check_adj_eq(struct isl_map *map, int i, int j,
                /* ADJ EQ TOO MANY */
                return 0;
 
-       for (k = 0; k < map->p[i]->n_ineq ; ++k)
+       for (k = 0; k < map->p[i]->n_ineq; ++k)
                if (ineq_i[k] == STATUS_ADJ_EQ)
                        break;
 
-       changed = is_extension(map, i, j, k, tabs, eq_i, ineq_i, eq_j, ineq_j);
+       changed = is_adj_eq_extension(map, i, j, k, tabs,
+                                       eq_i, ineq_i, eq_j, ineq_j);
        if (changed)
                return changed;
 
@@ -1200,7 +1306,15 @@ unbounded:
  *             => the pair can be replaced by a basic map consisting
  *                of the valid constraints in both basic maps
  *
- *     4. there is a single adjacent pair of an inequality and an equality,
+ *     4. one basic map has a single adjacent inequality, while the other
+ *        constraints are "valid".  The other basic map has some
+ *        "cut" constraints, but replacing the adjacent inequality by
+ *        its opposite and adding the valid constraints of the other
+ *        basic map results in a subset of the other basic map
+ *             => the pair can be replaced by a basic map consisting
+ *                of the valid constraints in both basic maps
+ *
+ *     5. there is a single adjacent pair of an inequality and an equality,
  *        the other constraints of the basic map containing the inequality are
  *        "valid".  Moreover, if the inequality the basic map is relaxed
  *        and then turned into an equality, then resulting facet lies
@@ -1208,7 +1322,7 @@ unbounded:
  *             => the pair can be replaced by the basic map containing
  *                the inequality, with the inequality relaxed.
  *
- *     5. there is a single adjacent pair of an inequality and an equality,
+ *     6. there is a single adjacent pair of an inequality and an equality,
  *        the other constraints of the basic map containing the inequality are
  *        "valid".  Moreover, the facets corresponding to both
  *        the inequality and the equality can be wrapped around their
@@ -1217,7 +1331,7 @@ unbounded:
  *                of the valid constraints in both basic maps together
  *                with all wrapping constraints
  *
- *     6. one of the basic maps extends beyond the other by at most one.
+ *     7. one of the basic maps extends beyond the other by at most one.
  *        Moreover, the facets corresponding to the cut constraints and
  *        the pieces of the other basic map at offset one from these cut
  *        constraints can be wrapped around their ridges to include
@@ -1226,7 +1340,7 @@ unbounded:
  *                of the valid constraints in both basic maps together
  *                with all wrapping constraints
  *
- *     7. the two basic maps live in adjacent hyperplanes.  In principle
+ *     8. the two basic maps live in adjacent hyperplanes.  In principle
  *        such sets can always be combined through wrapping, but we impose
  *        that there is only one such pair, to avoid overeager coalescing.
  *
@@ -1299,10 +1413,8 @@ static int coalesce_local_pair(__isl_keep isl_map *map, int i, int j,
                /* BAD ADJ INEQ */
        } else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) ||
                   any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ)) {
-               if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) &&
-                   !any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
-                       changed = check_adj_ineq(map, i, j, tabs,
-                                                ineq_i, ineq_j);
+               changed = check_adj_ineq(map, i, j, tabs,
+                                       eq_i, ineq_i, eq_j, ineq_j);
        } else {
                if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) &&
                    !any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
index 7f19658..483e26c 100644 (file)
 #include <isl_aff_private.h>
 #include <isl_local_space_private.h>
 
+#undef BASE
+#define BASE constraint
+
+#include <isl_list_templ.c>
+
 isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c)
 {
        return c ? isl_local_space_get_ctx(c->ls) : NULL;
index 8314325..1a3b44e 100644 (file)
@@ -12,6 +12,11 @@ struct isl_constraint {
        isl_vec         *v;
 };
 
+#undef EL
+#define EL isl_constraint
+
+#include <isl_list_templ.h>
+
 struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
        isl_int **line);
 
index 6f02684..7720be4 100644 (file)
--- a/isl_ctx.c
+++ b/isl_ctx.c
@@ -11,6 +11,9 @@
 #include <isl/vec.h>
 #include <isl_options_private.h>
 
+#define __isl_calloc(type,size)                ((type *)calloc(1, size))
+#define __isl_calloc_type(type)                __isl_calloc(type,sizeof(type))
+
 void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
        const char *file, int line)
 {
@@ -86,7 +89,7 @@ isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt)
                opt_allocated = 1;
        }
 
-       ctx = isl_calloc_type(NULL, struct isl_ctx);
+       ctx = __isl_calloc_type(struct isl_ctx);
        if (!ctx)
                goto error;
 
index 4447d9b..9589032 100644 (file)
@@ -1,10 +1,13 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
  *
  * Use of this software is governed by the MIT license
  *
  * Written by Sven Verdoolaege, K.U.Leuven, Departement
  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
  */
 
 #include <isl_mat_private.h>
@@ -374,6 +377,59 @@ error:
 
 /* Given a set of equalities
  *
+ *             B(y) + A x = 0                                          (*)
+ *
+ * compute and return an affine transformation T,
+ *
+ *             y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints for some value of x.
+ *
+ * Let [H 0] be the Hermite Normal Form of A, i.e.,
+ *
+ *             A = [H 0] Q
+ *
+ * Then y is a solution of (*) iff
+ *
+ *             H^-1 B(y) (= - [I 0] Q x)
+ *
+ * is an integer vector.  Let d be the common denominator of H^-1.
+ * We impose
+ *
+ *             d H^-1 B(y) = 0 mod d
+ *
+ * and compute the solution using isl_mat_parameter_compression.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+       __isl_take isl_mat *A)
+{
+       isl_ctx *ctx;
+       isl_vec *d;
+       int n_row, n_col;
+
+       if (!A)
+               return isl_mat_free(B);
+
+       ctx = isl_mat_get_ctx(A);
+       n_row = A->n_row;
+       n_col = A->n_col;
+       A = isl_mat_left_hermite(A, 0, NULL, NULL);
+       A = isl_mat_drop_cols(A, n_row, n_col - n_row);
+       A = isl_mat_lin_to_aff(A);
+       A = isl_mat_right_inverse(A);
+       d = isl_vec_alloc(ctx, n_row);
+       if (A)
+               d = isl_vec_set(d, A->row[0][0]);
+       A = isl_mat_drop_rows(A, 0, 1);
+       A = isl_mat_drop_cols(A, 0, 1);
+       B = isl_mat_product(A, B);
+
+       return isl_mat_parameter_compression(B, d);
+}
+
+/* Given a set of equalities
+ *
  *             M x - c = 0
  *
  * this function computes a unimodular transformation from a lower-dimensional
@@ -413,8 +469,8 @@ error:
  *
  *             x2' = Q2 x
  */
-struct isl_mat *isl_mat_variable_compression(struct isl_mat *B,
-       struct isl_mat **T2)
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+       __isl_give isl_mat **T2)
 {
        int i;
        struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
index 30ccbbf..0206cd1 100644 (file)
 extern "C" {
 #endif
 
-struct isl_mat *isl_mat_variable_compression(
-                       struct isl_mat *B, struct isl_mat **T2);
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+       __isl_give isl_mat **T2);
 struct isl_mat *isl_mat_parameter_compression(
                        struct isl_mat *B, struct isl_vec *d);
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+       __isl_take isl_mat *A);
 struct isl_basic_set *isl_basic_set_remove_equalities(
        struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2);
 
index ba93a69..82cad6f 100644 (file)
@@ -650,6 +650,8 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
 #define PARTS pw_qpolynomial_fold
 #define ALIGN_DOMAIN
 
+#define NO_SUB
+
 #include <isl_union_templ.c>
 
 __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
index 26f19c6..410218d 100644 (file)
--- a/isl_id.c
+++ b/isl_id.c
 #include <isl_ctx_private.h>
 #include <isl_id_private.h>
 
+#undef BASE
+#define BASE id
+
+#include <isl_list_templ.c>
+
 /* A special, static isl_id to use as domains (and ranges)
  * of sets and parameters domains.
  * The user should never get a hold on this isl_id.
index c583b31..6266b47 100644 (file)
@@ -28,6 +28,11 @@ struct isl_id {
        __isl_give void (*free_user)(void *user);
 };
 
+#undef EL
+#define EL isl_id
+
+#include <isl_list_templ.h>
+
 uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id);
 
 extern isl_id isl_id_none;
index a19fe6e..7400629 100644 (file)
@@ -942,7 +942,11 @@ static __isl_give isl_multi_pw_aff *read_tuple_var_list(struct isl_stream *s,
                        new_name = p >= n;
                }
 
-               if (new_name) {
+               if (tok->type == '*') {
+                       if (vars_add_anon(v) < 0)
+                               goto error;
+                       isl_token_free(tok);
+               } else if (new_name) {
                        res = tuple_set_dim_name(res, i, v->v->name);
                        isl_token_free(tok);
                        if (isl_stream_eat_if_available(s, '='))
@@ -1349,7 +1353,7 @@ static __isl_give isl_map *read_conjuncts(struct isl_stream *s,
        if (negate)
                res = isl_map_subtract(isl_map_copy(map), res);
 
-       while (isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
+       while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
                isl_map *res_i;
 
                negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
@@ -1686,8 +1690,9 @@ static __isl_give isl_pw_qpolynomial *read_factor(struct isl_stream *s,
                pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
        } else if (tok->type == ISL_TOKEN_VALUE) {
                struct isl_token *tok2;
-               tok2 = isl_stream_next_token(s);
                isl_qpolynomial *qp;
+
+               tok2 = isl_stream_next_token(s);
                if (tok2 && tok2->type == '/') {
                        isl_token_free(tok2);
                        tok2 = next_token(s);
@@ -2748,6 +2753,47 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
        return pma;
 }
 
+/* Read an isl_union_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_union_pw_multi_aff.
+ * It would be more efficient if we were to construct
+ * the isl_union_pw_multi_aff directly.
+ */
+__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
+       struct isl_stream *s)
+{
+       struct isl_obj obj;
+
+       obj = obj_read(s);
+       if (!obj.v)
+               return NULL;
+
+       if (obj.type == isl_obj_map || obj.type == isl_obj_set)
+               obj = to_union(s->ctx, obj);
+       if (obj.type == isl_obj_union_map)
+               return isl_union_pw_multi_aff_from_union_map(obj.v);
+       if (obj.type == isl_obj_union_set)
+               return isl_union_pw_multi_aff_from_union_set(obj.v);
+
+       obj.type->free(obj.v);
+       isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+               return NULL);
+}
+
+/* Read an isl_union_pw_multi_aff from "str".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+       isl_ctx *ctx, const char *str)
+{
+       isl_union_pw_multi_aff *upma;
+       struct isl_stream *s = isl_stream_new_str(ctx, str);
+       if (!s)
+               return NULL;
+       upma = isl_stream_read_union_pw_multi_aff(s);
+       isl_stream_free(s);
+       return upma;
+}
+
 /* Assuming "pa" represents a single affine expression defined on a universe
  * domain, extract this affine expression.
  */
diff --git a/isl_list.c b/isl_list.c
deleted file mode 100644 (file)
index bb926b7..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2008-2009 Katholieke Universiteit Leuven
- *
- * Use of this software is governed by the MIT license
- *
- * Written by Sven Verdoolaege, K.U.Leuven, Departement
- * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
- */
-
-#include <isl_list_private.h>
-#include <isl/constraint.h>
-#include <isl/set.h>
-#include <isl/aff.h>
-#include <isl/band.h>
-
-#undef BASE
-#define BASE constraint
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE basic_set
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE set
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE aff
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE pw_aff
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE band
-
-#include <isl_list_templ.c>
-
-#undef BASE
-#define BASE id
-
-#include <isl_list_templ.c>
diff --git a/isl_list_private.h b/isl_list_private.h
deleted file mode 100644 (file)
index 26d5641..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef ISL_LIST_PRIVATE_H
-#define ISL_LIST_PRIVATE_H
-
-#include <isl/list.h>
-
-#undef EL
-#define EL isl_constraint
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_basic_set
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_set
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_aff
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_pw_aff
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_band
-
-#include <isl_list_templ.h>
-
-#undef EL
-#define EL isl_id
-
-#include <isl_list_templ.h>
-
-#endif
index 0af5b76..71024ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
  * Copyright 2011      INRIA Saclay
- * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
@@ -12,6 +12,9 @@
  * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
  */
 
+#include <isl_sort.h>
+#include <isl_tarjan.h>
+
 #define xCAT(A,B) A ## B
 #define CAT(A,B) xCAT(A,B)
 #undef EL
@@ -20,6 +23,8 @@
 #define FN(TYPE,NAME) xFN(TYPE,NAME)
 #define xLIST(EL) EL ## _list
 #define LIST(EL) xLIST(EL)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
 
 isl_ctx *FN(LIST(EL),get_ctx)(__isl_keep LIST(EL) *list)
 {
@@ -283,6 +288,157 @@ int FN(LIST(EL),foreach)(__isl_keep LIST(EL) *list,
        return 0;
 }
 
+/* Internal data structure for isl_*_list_sort.
+ *
+ * "cmp" is the original comparison function.
+ * "user" is a user provided pointer that should be passed to "cmp".
+ */
+S(LIST(EL),sort_data) {
+       int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+       void *user;
+};
+
+/* Compare two entries of an isl_*_list based on the user provided
+ * comparison function on pairs of isl_* objects.
+ */
+static int FN(LIST(EL),cmp)(const void *a, const void *b, void *user)
+{
+       S(LIST(EL),sort_data) *data = user;
+       EL * const *el1 = a;
+       EL * const *el2 = b;
+
+       return data->cmp(*el1, *el2, data->user);
+}
+
+/* Sort the elements of "list" in ascending order according to
+ * comparison function "cmp".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),sort)(__isl_take LIST(EL) *list,
+       int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user), void *user)
+{
+       S(LIST(EL),sort_data) data = { cmp, user };
+
+       if (!list)
+               return NULL;
+       if (list->n <= 1)
+               return list;
+       list = FN(LIST(EL),cow)(list);
+       if (!list)
+               return NULL;
+
+       if (isl_sort(list->p, list->n, sizeof(list->p[0]),
+                       &FN(LIST(EL),cmp), &data) < 0)
+               return FN(LIST(EL),free)(list);
+
+       return list;
+}
+
+/* Internal data structure for isl_*_list_foreach_scc.
+ *
+ * "list" is the original list.
+ * "follows" is the user provided callback that defines the edges of the graph.
+ */
+S(LIST(EL),foreach_scc_data) {
+       LIST(EL) *list;
+       int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+       void *follows_user;
+};
+
+/* Does element i of data->list follow element j?
+ *
+ * Use the user provided callback to find out.
+ */
+static int FN(LIST(EL),follows)(int i, int j, void *user)
+{
+       S(LIST(EL),foreach_scc_data) *data = user;
+
+       return data->follows(data->list->p[i], data->list->p[j],
+                               data->follows_user);
+}
+
+/* Call "fn" on the sublist of "list" that consists of the elements
+ * with indices specified by the "n" elements of "pos".
+ */
+static int FN(LIST(EL),call_on_scc)(__isl_keep LIST(EL) *list, int *pos, int n,
+       int (*fn)(__isl_take LIST(EL) *scc, void *user), void *user)
+{
+       int i;
+       isl_ctx *ctx;
+       LIST(EL) *slice;
+
+       ctx = FN(LIST(EL),get_ctx)(list);
+       slice = FN(LIST(EL),alloc)(ctx, n);
+       for (i = 0; i < n; ++i) {
+               EL *el;
+
+               el = FN(EL,copy)(list->p[pos[i]]);
+               slice = FN(LIST(EL),add)(slice, el);
+       }
+
+       return fn(slice, user);
+}
+
+/* Call "fn" on each of the strongly connected components (SCCs) of
+ * the graph with as vertices the elements of "list" and
+ * a directed edge from node b to node a iff follows(a, b)
+ * returns 1.  follows should return -1 on error.
+ *
+ * If SCC a contains a node i that follows a node j in another SCC b
+ * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a
+ * after being called on SCC b.
+ *
+ * We simply call isl_tarjan_graph_init, extract the SCCs from the result and
+ * call fn on each of them.
+ */
+int FN(LIST(EL),foreach_scc)(__isl_keep LIST(EL) *list,
+       int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user),
+       void *follows_user,
+       int (*fn)(__isl_take LIST(EL) *scc, void *user), void *fn_user)
+{
+       S(LIST(EL),foreach_scc_data) data = { list, follows, follows_user };
+       int i, n;
+       isl_ctx *ctx;
+       struct isl_tarjan_graph *g;
+
+       if (!list)
+               return -1;
+       if (list->n == 0)
+               return 0;
+       if (list->n == 1)
+               return fn(FN(LIST(EL),copy)(list), fn_user);
+
+       ctx = FN(LIST(EL),get_ctx)(list);
+       n = list->n;
+       g = isl_tarjan_graph_init(ctx, n, &FN(LIST(EL),follows), &data);
+       if (!g)
+               return -1;
+
+       i = 0;
+       do {
+               int first;
+
+               if (g->order[i] == -1)
+                       isl_die(ctx, isl_error_internal, "cannot happen",
+                               break);
+               first = i;
+               while (g->order[i] != -1) {
+                       ++i; --n;
+               }
+               if (first == 0 && n == 0) {
+                       isl_tarjan_graph_free(g);
+                       return fn(FN(LIST(EL),copy)(list), fn_user);
+               }
+               if (FN(LIST(EL),call_on_scc)(list, g->order + first, i - first,
+                                           fn, fn_user) < 0)
+                       break;
+               ++i;
+       } while (n);
+
+       isl_tarjan_graph_free(g);
+
+       return n > 0 ? -1 : 0;
+}
+
 __isl_give LIST(EL) *FN(FN(LIST(EL),from),BASE)(__isl_take EL *el)
 {
        isl_ctx *ctx;
index 9c60f5a..893f9d9 100644 (file)
@@ -13,12 +13,4 @@ struct LIST(EL) {
        struct EL *p[1];
 };
 
-#define ISL_DECLARE_LIST_PRIVATE(EL)                                   \
-__isl_give isl_##EL##_list *isl_##EL##_list_dup(                       \
-       __isl_keep isl_##EL##_list *list);
-
-ISL_DECLARE_LIST_PRIVATE(basic_set)
-ISL_DECLARE_LIST_PRIVATE(set)
-ISL_DECLARE_LIST_PRIVATE(aff)
-ISL_DECLARE_LIST_PRIVATE(pw_aff)
-ISL_DECLARE_LIST_PRIVATE(band)
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list);
index 6c4fb84..42f3e9f 100644 (file)
@@ -219,6 +219,9 @@ __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
        if (isl_int_is_zero(ls->div->row[pos][0]))
                isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
                        "expression of div unknown", return NULL);
+       if (!isl_local_space_is_set(ls))
+               isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+                       "cannot represent divs of map spaces", return NULL);
 
        aff = isl_aff_alloc(isl_local_space_copy(ls));
        if (!aff)
@@ -1104,7 +1107,7 @@ __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
                        continue;
                }
                isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
-                                   ma, n_div_ma, n_div_ls, f, c1, c2, g, 1);
+                               ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
                normalize_div(res, n_div_ma + i);
        }
 
index c4636c1..0478d72 100644 (file)
--- a/isl_map.c
+++ b/isl_map.c
@@ -1,7 +1,7 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
  * Copyright 2010      INRIA Saclay
- * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
@@ -18,7 +18,6 @@
 #include <isl/blk.h>
 #include "isl_space_private.h"
 #include "isl_equalities.h"
-#include <isl_list_private.h>
 #include <isl/lp.h>
 #include <isl/seq.h>
 #include <isl/set.h>
@@ -33,6 +32,7 @@
 #include <isl_local_space_private.h>
 #include <isl_aff_private.h>
 #include <isl_options_private.h>
+#include <isl_morph.h>
 
 static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
 {
@@ -1673,13 +1673,25 @@ struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset)
                isl_basic_map_set_to_empty((struct isl_basic_map *)bset);
 }
 
-void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
+/* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints
+ * of "bmap").
+ */
+static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b)
 {
-       int i;
-       unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
        isl_int *t = bmap->div[a];
        bmap->div[a] = bmap->div[b];
        bmap->div[b] = t;
+}
+
+/* Swap divs "a" and "b" in "bmap" and adjust the constraints and
+ * div definitions accordingly.
+ */
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
+{
+       int i;
+       unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
+
+       swap_div(bmap, a, b);
 
        for (i = 0; i < bmap->n_eq; ++i)
                isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]);
@@ -3355,31 +3367,22 @@ static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
        return res;
 }
 
-/* Turn the n dimensions of type type, starting at first
- * into existentially quantified variables.
+/* Insert "n" rows in the divs of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the new divs.
+ * The space of "bmap" is not adjusted, however, which means
+ * that "bmap" is left in an inconsistent state.  Removing "n" dimensions
+ * from the space of "bmap" is the responsibility of the caller.
  */
-__isl_give isl_basic_map *isl_basic_map_project_out(
-               __isl_take isl_basic_map *bmap,
-               enum isl_dim_type type, unsigned first, unsigned n)
+static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap,
+       int n)
 {
        int i;
        size_t row_size;
        isl_int **new_div;
        isl_int *old;
 
-       if (n == 0)
-               return basic_map_space_reset(bmap, type);
-
-       if (!bmap)
-               return NULL;
-
-       if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
-               return isl_basic_map_remove_dims(bmap, type, first, n);
-
-       isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
-                       goto error);
-
-       bmap = move_last(bmap, type, first, n);
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
@@ -3389,10 +3392,10 @@ __isl_give isl_basic_map *isl_basic_map_project_out(
        bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2,
                                        (bmap->extra + n) * (1 + row_size));
        if (!bmap->block2.data)
-               goto error;
+               return isl_basic_map_free(bmap);
        new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n);
        if (!new_div)
-               goto error;
+               return isl_basic_map_free(bmap);
        for (i = 0; i < n; ++i) {
                new_div[i] = bmap->block2.data +
                                (bmap->extra + i) * (1 + row_size);
@@ -3405,6 +3408,34 @@ __isl_give isl_basic_map *isl_basic_map_project_out(
        bmap->n_div += n;
        bmap->extra += n;
 
+       return bmap;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_basic_map *isl_basic_map_project_out(
+               __isl_take isl_basic_map *bmap,
+               enum isl_dim_type type, unsigned first, unsigned n)
+{
+       if (n == 0)
+               return basic_map_space_reset(bmap, type);
+
+       if (!bmap)
+               return NULL;
+
+       if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+               return isl_basic_map_remove_dims(bmap, type, first, n);
+
+       isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+                       goto error);
+
+       bmap = move_last(bmap, type, first, n);
+       bmap = isl_basic_map_cow(bmap);
+       bmap = insert_div_rows(bmap, n);
+       if (!bmap)
+               return NULL;
+
        bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
        if (!bmap->dim)
                goto error;
@@ -5339,6 +5370,39 @@ static int remove_if_empty(__isl_keep isl_map *map, int i)
        return 0;
 }
 
+/* Perform "fn" on each basic map of "map", where we may not be holding
+ * the only reference to "map".
+ * In particular, "fn" should be a semantics preserving operation
+ * that we want to apply to all copies of "map".  We therefore need
+ * to be careful not to modify "map" in a way that breaks "map"
+ * in case anything goes wrong.
+ */
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+       __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap))
+{
+       struct isl_basic_map *bmap;
+       int i;
+
+       if (!map)
+               return NULL;
+
+       for (i = map->n - 1; i >= 0; --i) {
+               bmap = isl_basic_map_copy(map->p[i]);
+               bmap = fn(bmap);
+               if (!bmap)
+                       goto error;
+               isl_basic_map_free(map->p[i]);
+               map->p[i] = bmap;
+               if (remove_if_empty(map, i) < 0)
+                       goto error;
+       }
+
+       return map;
+error:
+       isl_map_free(map);
+       return NULL;
+}
+
 struct isl_map *isl_map_fix_si(struct isl_map *map,
                enum isl_dim_type type, unsigned pos, int value)
 {
@@ -5998,19 +6062,33 @@ __isl_give isl_set *isl_set_partial_lexmax(
                        dom, empty);
 }
 
+/* Compute the lexicographic minimum (or maximum if "max" is set)
+ * of "bmap" over its domain.
+ *
+ * Since we are not interested in the part of the domain space where
+ * there is no solution, we initialize the domain to those constraints
+ * of "bmap" that only involve the parameters and the input dimensions.
+ * This relieves the parametric programming engine from detecting those
+ * inequalities and transferring them to the context.  More importantly,
+ * it ensures that those inequalities are transferred first and not
+ * intermixed with inequalities that actually split the domain.
+ */
 __isl_give isl_map *isl_basic_map_lexopt(__isl_take isl_basic_map *bmap, int max)
 {
-       struct isl_basic_set *dom = NULL;
-       isl_space *dom_dim;
+       int n_div;
+       int n_out;
+       isl_basic_map *copy;
+       isl_basic_set *dom;
 
-       if (!bmap)
-               goto error;
-       dom_dim = isl_space_domain(isl_space_copy(bmap->dim));
-       dom = isl_basic_set_universe(dom_dim);
+       n_div = isl_basic_map_dim(bmap, isl_dim_div);
+       n_out = isl_basic_map_dim(bmap, isl_dim_out);
+       copy = isl_basic_map_copy(bmap);
+       copy = isl_basic_map_drop_constraints_involving_dims(copy,
+                                                       isl_dim_div, 0, n_div);
+       copy = isl_basic_map_drop_constraints_involving_dims(copy,
+                                                       isl_dim_out, 0, n_out);
+       dom = isl_basic_map_domain(copy);
        return isl_basic_map_partial_lexopt(bmap, dom, NULL, max);
-error:
-       isl_basic_map_free(bmap);
-       return NULL;
 }
 
 __isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap)
@@ -6033,16 +6111,6 @@ __isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
        return (isl_set *)isl_basic_map_lexmax((isl_basic_map *)bset);
 }
 
-__isl_give isl_set *isl_set_lexmin(__isl_take isl_set *set)
-{
-       return (isl_set *)isl_map_lexmin((isl_map *)set);
-}
-
-__isl_give isl_set *isl_set_lexmax(__isl_take isl_set *set)
-{
-       return (isl_set *)isl_map_lexmax((isl_map *)set);
-}
-
 /* Extract the first and only affine expression from list
  * and then add it to *pwaff with the given dom.
  * This domain is known to be disjoint from other domains
@@ -6314,6 +6382,72 @@ error:
        return NULL;
 }
 
+/* Given a basic set "bset" that only involves parameters and existentially
+ * quantified variables, return the index of the first equality
+ * that only involves parameters.  If there is no such equality then
+ * return bset->n_eq.
+ *
+ * This function assumes that isl_basic_set_gauss has been called on "bset".
+ */
+static int first_parameter_equality(__isl_keep isl_basic_set *bset)
+{
+       int i, j;
+       unsigned nparam, n_div;
+
+       if (!bset)
+               return -1;
+
+       nparam = isl_basic_set_dim(bset, isl_dim_param);
+       n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+       for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) {
+               if (!isl_int_is_zero(bset->eq[i][1 + nparam + j]))
+                       ++i;
+       }
+
+       return i;
+}
+
+/* Compute an explicit representation for the existentially quantified
+ * variables in "bset" by computing the "minimal value" of the set
+ * variables.  Since there are no set variables, the computation of
+ * the minimal value essentially computes an explicit representation
+ * of the non-empty part(s) of "bset".
+ *
+ * The input only involves parameters and existentially quantified variables.
+ * All equalities among parameters have been removed.
+ *
+ * Since the existentially quantified variables in the result are in general
+ * going to be different from those in the input, we first replace
+ * them by the minimal number of variables based on their equalities.
+ * This should simplify the parametric integer programming.
+ */
+static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset)
+{
+       isl_morph *morph1, *morph2;
+       isl_set *set;
+       unsigned n;
+
+       if (!bset)
+               return NULL;
+       if (bset->n_eq == 0)
+               return isl_basic_set_lexmin(bset);
+
+       morph1 = isl_basic_set_parameter_compression(bset);
+       bset = isl_morph_basic_set(isl_morph_copy(morph1), bset);
+       bset = isl_basic_set_lift(bset);
+       morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+       bset = isl_morph_basic_set(morph2, bset);
+       n = isl_basic_set_dim(bset, isl_dim_set);
+       bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+
+       set = isl_basic_set_lexmin(bset);
+
+       set = isl_morph_set(isl_morph_inverse(morph1), set);
+
+       return set;
+}
+
 /* Project the given basic set onto its parameter domain, possibly introducing
  * new, explicit, existential variables in the constraints.
  * The input has parameters and (possibly implicit) existential variables.
@@ -6325,21 +6459,27 @@ error:
  * among the parameters by performing a variable compression on
  * the parameters.  Afterward, an inverse transformation is performed
  * and the equalities among the parameters are inserted back in.
+ *
+ * The variable compression on the parameters may uncover additional
+ * equalities that were only implicit before.  We therefore check
+ * if there are any new parameter equalities in the result and
+ * if so recurse.  The removal of parameter equalities is required
+ * for the parameter compression performed by base_compute_divs.
  */
 static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
 {
-       int i, j;
+       int i;
        struct isl_mat *eq;
        struct isl_mat *T, *T2;
        struct isl_set *set;
-       unsigned nparam, n_div;
+       unsigned nparam;
 
        bset = isl_basic_set_cow(bset);
        if (!bset)
                return NULL;
 
        if (bset->n_eq == 0)
-               return isl_basic_set_lexmin(bset);
+               return base_compute_divs(bset);
 
        bset = isl_basic_set_gauss(bset, NULL);
        if (!bset)
@@ -6347,16 +6487,11 @@ static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
        if (isl_basic_set_plain_is_empty(bset))
                return isl_set_from_basic_set(bset);
 
-       nparam = isl_basic_set_dim(bset, isl_dim_param);
-       n_div = isl_basic_set_dim(bset, isl_dim_div);
-
-       for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) {
-               if (!isl_int_is_zero(bset->eq[i][1 + nparam + j]))
-                       ++i;
-       }
+       i = first_parameter_equality(bset);
        if (i == bset->n_eq)
-               return isl_basic_set_lexmin(bset);
+               return base_compute_divs(bset);
 
+       nparam = isl_basic_set_dim(bset, isl_dim_param);
        eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, i, bset->n_eq - i,
                0, 1 + nparam);
        eq = isl_mat_cow(eq);
@@ -6370,47 +6505,174 @@ static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
        }
        bset = basic_set_parameter_preimage(bset, T);
 
-       set = isl_basic_set_lexmin(bset);
+       i = first_parameter_equality(bset);
+       if (!bset)
+               set = NULL;
+       else if (i == bset->n_eq)
+               set = base_compute_divs(bset);
+       else
+               set = parameter_compute_divs(bset);
        set = set_parameter_preimage(set, T2);
        set = set_append_equalities(set, eq);
        return set;
 }
 
-/* Compute an explicit representation for all the existentially
- * quantified variables.
- * The input and output dimensions are first turned into parameters.
- * compute_divs then returns a map with the same parameters and
+/* Insert the divs from "ls" before those of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the divs from "ls".
+ * The caller is responsible for removing the same number of dimensions
+ * from the space of "bmap".
+ */
+static __isl_give isl_basic_map *insert_divs_from_local_space(
+       __isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls)
+{
+       int i;
+       int n_div;
+       int old_n_div;
+
+       n_div = isl_local_space_dim(ls, isl_dim_div);
+       if (n_div == 0)
+               return bmap;
+
+       old_n_div = bmap->n_div;
+       bmap = insert_div_rows(bmap, n_div);
+       if (!bmap)
+               return NULL;
+
+       for (i = 0; i < n_div; ++i) {
+               isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+               isl_seq_clr(bmap->div[i] + ls->div->n_col, old_n_div);
+       }
+
+       return bmap;
+}
+
+/* Replace the space of "bmap" by the space and divs of "ls".
+ *
+ * If "ls" has any divs, then we simplify the result since we may
+ * have discovered some additional equalities that could simplify
+ * the div expressions.
+ */
+static __isl_give isl_basic_map *basic_replace_space_by_local_space(
+       __isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls)
+{
+       int n_div;
+
+       bmap = isl_basic_map_cow(bmap);
+       if (!bmap || !ls)
+               goto error;
+
+       n_div = isl_local_space_dim(ls, isl_dim_div);
+       bmap = insert_divs_from_local_space(bmap, ls);
+       if (!bmap)
+               goto error;
+
+       isl_space_free(bmap->dim);
+       bmap->dim = isl_local_space_get_space(ls);
+       if (!bmap->dim)
+               goto error;
+
+       isl_local_space_free(ls);
+       if (n_div > 0)
+               bmap = isl_basic_map_simplify(bmap);
+       bmap = isl_basic_map_finalize(bmap);
+       return bmap;
+error:
+       isl_basic_map_free(bmap);
+       isl_local_space_free(ls);
+       return NULL;
+}
+
+/* Replace the space of "map" by the space and divs of "ls".
+ */
+static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map,
+       __isl_take isl_local_space *ls)
+{
+       int i;
+
+       map = isl_map_cow(map);
+       if (!map || !ls)
+               goto error;
+
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = basic_replace_space_by_local_space(map->p[i],
+                                                   isl_local_space_copy(ls));
+               if (!map->p[i])
+                       goto error;
+       }
+       isl_space_free(map->dim);
+       map->dim = isl_local_space_get_space(ls);
+       if (!map->dim)
+               goto error;
+
+       isl_local_space_free(ls);
+       return map;
+error:
+       isl_local_space_free(ls);
+       isl_map_free(map);
+       return NULL;
+}
+
+/* Compute an explicit representation for the existentially
+ * quantified variables for which do not know any explicit representation yet.
+ *
+ * We first sort the existentially quantified variables so that the
+ * existentially quantified variables for which we already have an explicit
+ * representation are placed before those for which we do not.
+ * The input dimensions, the output dimensions and the existentially
+ * quantified variables for which we already have an explicit
+ * representation are then turned into parameters.
+ * compute_divs returns a map with the same parameters and
  * no input or output dimensions and the dimension specification
- * is reset to that of the input.
+ * is reset to that of the input, including the existentially quantified
+ * variables for which we already had an explicit representation.
  */
 static struct isl_map *compute_divs(struct isl_basic_map *bmap)
 {
        struct isl_basic_set *bset;
        struct isl_set *set;
        struct isl_map *map;
-       isl_space *dim, *orig_dim = NULL;
+       isl_space *dim;
+       isl_local_space *ls;
        unsigned         nparam;
        unsigned         n_in;
        unsigned         n_out;
+       unsigned n_known;
+       int i;
 
+       bmap = isl_basic_map_sort_divs(bmap);
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
 
+       for (n_known = 0; n_known < bmap->n_div; ++n_known)
+               if (isl_int_is_zero(bmap->div[n_known][0]))
+                       break;
+
        nparam = isl_basic_map_dim(bmap, isl_dim_param);
        n_in = isl_basic_map_dim(bmap, isl_dim_in);
        n_out = isl_basic_map_dim(bmap, isl_dim_out);
-       dim = isl_space_set_alloc(bmap->ctx, nparam + n_in + n_out, 0);
+       dim = isl_space_set_alloc(bmap->ctx,
+                                   nparam + n_in + n_out + n_known, 0);
        if (!dim)
                goto error;
 
-       orig_dim = bmap->dim;
-       bmap->dim = dim;
+       ls = isl_basic_map_get_local_space(bmap);
+       ls = isl_local_space_drop_dims(ls, isl_dim_div,
+                                       n_known, bmap->n_div - n_known);
+       if (n_known > 0) {
+               for (i = n_known; i < bmap->n_div; ++i)
+                       swap_div(bmap, i - n_known, i);
+               bmap->n_div -= n_known;
+               bmap->extra -= n_known;
+       }
+       bmap = isl_basic_map_reset_space(bmap, dim);
        bset = (struct isl_basic_set *)bmap;
 
        set = parameter_compute_divs(bset);
        map = (struct isl_map *)set;
-       map = isl_map_reset_space(map, orig_dim);
+       map = replace_space_by_local_space(map, ls);
 
        return map;
 error:
@@ -10251,7 +10513,8 @@ __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
        isl_mat_free(eq);
        isl_mat_free(ineq);
 
-       return bmap;
+       bmap = isl_basic_map_simplify(bmap);
+       return isl_basic_map_finalize(bmap);
 error:
        isl_space_free(dim);
        isl_mat_free(eq);
@@ -10793,32 +11056,29 @@ __isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap,
        return bmap;
 }
 
-/* Add a constraint imposing that the value of the first dimension is
+/* Construct a basic map where the value of the first dimension is
  * greater than that of the second.
  */
-__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+static __isl_give isl_basic_map *greator(__isl_take isl_space *space,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
 {
        isl_basic_map *bmap = NULL;
        int i;
 
-       if (!map)
+       if (!space)
                return NULL;
 
-       if (pos1 >= isl_map_dim(map, type1))
-               isl_die(map->ctx, isl_error_invalid,
+       if (pos1 >= isl_space_dim(space, type1))
+               isl_die(isl_space_get_ctx(space), isl_error_invalid,
                        "index out of bounds", goto error);
-       if (pos2 >= isl_map_dim(map, type2))
-               isl_die(map->ctx, isl_error_invalid,
+       if (pos2 >= isl_space_dim(space, type2))
+               isl_die(isl_space_get_ctx(space), isl_error_invalid,
                        "index out of bounds", goto error);
 
-       if (type1 == type2 && pos1 == pos2) {
-               isl_space *space = isl_map_get_space(map);
-               isl_map_free(map);
-               return isl_map_empty(space);
-       }
+       if (type1 == type2 && pos1 == pos2)
+               return isl_basic_map_empty(space);
 
-       bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 0, 1);
+       bmap = isl_basic_map_alloc_space(space, 0, 0, 1);
        i = isl_basic_map_alloc_inequality(bmap);
        if (i < 0)
                goto error;
@@ -10830,16 +11090,44 @@ __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
        isl_int_set_si(bmap->ineq[i][0], -1);
        bmap = isl_basic_map_finalize(bmap);
 
-       map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
-
-       return map;
+       return bmap;
 error:
+       isl_space_free(space);
        isl_basic_map_free(bmap);
-       isl_map_free(map);
        return NULL;
 }
 
 /* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+       isl_basic_map *gt;
+
+       gt = greator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+       bmap = isl_basic_map_intersect(bmap, gt);
+
+       return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+       isl_basic_map *bmap;
+
+       bmap = greator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+       map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+       return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
  * smaller than that of the second.
  */
 __isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
@@ -10994,40 +11282,37 @@ error:
        return NULL;
 }
 
-/* Check if the range of "ma" is compatible with "space".
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "bmap".
  * Return -1 if anything is wrong.
  */
-static int check_space_compatible_range_multi_aff(
-       __isl_keep isl_space *space, __isl_keep isl_multi_aff *ma)
+static int check_basic_map_compatible_range_multi_aff(
+       __isl_keep isl_basic_map *bmap, enum isl_dim_type type,
+       __isl_keep isl_multi_aff *ma)
 {
        int m;
        isl_space *ma_space;
 
        ma_space = isl_multi_aff_get_space(ma);
-       m = isl_space_is_range_internal(space, ma_space);
+       m = isl_space_tuple_match(bmap->dim, type, ma_space, isl_dim_out);
        isl_space_free(ma_space);
        if (m >= 0 && !m)
-               isl_die(isl_space_get_ctx(space), isl_error_invalid,
+               isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
                        "spaces don't match", return -1);
        return m;
 }
 
-/* Check if the range of "ma" is compatible with "bset".
- * Return -1 if anything is wrong.
- */
-static int check_basic_set_compatible_range_multi_aff(
-       __isl_keep isl_basic_set *bset, __isl_keep isl_multi_aff *ma)
-{
-       return check_space_compatible_range_multi_aff(bset->dim, ma);
-}
-
-/* Copy the divs from "ma" to "bset", adding zeros for the coefficients
- * of the other divs in "bset".
+/* Copy the divs from "ma" to "bmap", adding zeros for the "n_before"
+ * coefficients before the transformed range of dimensions,
+ * the "n_after" coefficients after the transformed range of dimensions
+ * and the coefficients of the other divs in "bmap".
  */
-static int set_ma_divs(__isl_keep isl_basic_set *bset,
-       __isl_keep isl_multi_aff *ma, int n_div)
+static int set_ma_divs(__isl_keep isl_basic_map *bmap,
+       __isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div)
 {
        int i;
+       int n_param;
+       int n_set;
        isl_local_space *ls;
 
        if (n_div == 0)
@@ -11037,10 +11322,28 @@ static int set_ma_divs(__isl_keep isl_basic_set *bset,
        if (!ls)
                return -1;
 
+       n_param = isl_local_space_dim(ls, isl_dim_param);
+       n_set = isl_local_space_dim(ls, isl_dim_set);
        for (i = 0; i < n_div; ++i) {
-               isl_seq_cpy(bset->div[i], ls->div->row[i], ls->div->n_col);
-               isl_seq_clr(bset->div[i] + ls->div->n_col, bset->n_div - n_div);
-               if (isl_basic_set_add_div_constraints(bset, i) < 0)
+               int o_bmap = 0, o_ls = 0;
+
+               isl_seq_cpy(bmap->div[i], ls->div->row[i], 1 + 1 + n_param);
+               o_bmap += 1 + 1 + n_param;
+               o_ls += 1 + 1 + n_param;
+               isl_seq_clr(bmap->div[i] + o_bmap, n_before);
+               o_bmap += n_before;
+               isl_seq_cpy(bmap->div[i] + o_bmap,
+                           ls->div->row[i] + o_ls, n_set);
+               o_bmap += n_set;
+               o_ls += n_set;
+               isl_seq_clr(bmap->div[i] + o_bmap, n_after);
+               o_bmap += n_after;
+               isl_seq_cpy(bmap->div[i] + o_bmap,
+                           ls->div->row[i] + o_ls, n_div);
+               o_bmap += n_div;
+               o_ls += n_div;
+               isl_seq_clr(bmap->div[i] + o_bmap, bmap->n_div - n_div);
+               if (isl_basic_set_add_div_constraints(bmap, i) < 0)
                        goto error;
        }
 
@@ -11071,74 +11374,117 @@ static int multi_aff_strides(__isl_keep isl_multi_aff *ma)
  *
  *     x_i = (f_i y + h_i)/m_i
  *
- * with m_i different from one, add a constraint to "bset"
+ * with m_i different from one, add a constraint to "bmap"
  * of the form
  *
  *     f_i y + h_i = m_i alpha_i
  *
  * with alpha_i an additional existentially quantified variable.
  */
-static __isl_give isl_basic_set *add_ma_strides(
-       __isl_take isl_basic_set *bset, __isl_keep isl_multi_aff *ma)
+static __isl_give isl_basic_map *add_ma_strides(
+       __isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma,
+       int n_before, int n_after)
 {
        int i, k;
        int div;
        int total;
+       int n_param;
+       int n_in;
+       int n_div;
 
-       total = isl_basic_set_total_dim(bset);
+       total = isl_basic_map_total_dim(bmap);
+       n_param = isl_multi_aff_dim(ma, isl_dim_param);
+       n_in = isl_multi_aff_dim(ma, isl_dim_in);
+       n_div = isl_multi_aff_dim(ma, isl_dim_div);
        for (i = 0; i < ma->n; ++i) {
-               int len;
+               int o_bmap = 0, o_ma = 1;
 
                if (isl_int_is_one(ma->p[i]->v->el[0]))
                        continue;
-               div = isl_basic_set_alloc_div(bset);
-               k = isl_basic_set_alloc_equality(bset);
+               div = isl_basic_map_alloc_div(bmap);
+               k = isl_basic_map_alloc_equality(bmap);
                if (div < 0 || k < 0)
                        goto error;
-               isl_int_set_si(bset->div[div][0], 0);
-               len = ma->p[i]->v->size;
-               isl_seq_cpy(bset->eq[k], ma->p[i]->v->el + 1, len - 1);
-               isl_seq_clr(bset->eq[k] + len - 1, 1 + total - (len - 1));
-               isl_int_neg(bset->eq[k][1 + total], ma->p[i]->v->el[0]);
+               isl_int_set_si(bmap->div[div][0], 0);
+               isl_seq_cpy(bmap->eq[k] + o_bmap,
+                           ma->p[i]->v->el + o_ma, 1 + n_param);
+               o_bmap += 1 + n_param;
+               o_ma += 1 + n_param;
+               isl_seq_clr(bmap->eq[k] + o_bmap, n_before);
+               o_bmap += n_before;
+               isl_seq_cpy(bmap->eq[k] + o_bmap,
+                           ma->p[i]->v->el + o_ma, n_in);
+               o_bmap += n_in;
+               o_ma += n_in;
+               isl_seq_clr(bmap->eq[k] + o_bmap, n_after);
+               o_bmap += n_after;
+               isl_seq_cpy(bmap->eq[k] + o_bmap,
+                           ma->p[i]->v->el + o_ma, n_div);
+               o_bmap += n_div;
+               o_ma += n_div;
+               isl_seq_clr(bmap->eq[k] + o_bmap, 1 + total - o_bmap);
+               isl_int_neg(bmap->eq[k][1 + total], ma->p[i]->v->el[0]);
                total++;
        }
 
-       return bset;
+       return bmap;
 error:
-       isl_basic_set_free(bset);
+       isl_basic_map_free(bmap);
        return NULL;
 }
 
-/* Compute the preimage of "bset" under the function represented by "ma".
- * In other words, plug in "ma" in "bset".  The result is a basic set
- * that lives in the domain space of "ma".
+/* Replace the domain or range space (depending on "type) of "space" by "set".
+ */
+static __isl_give isl_space *isl_space_set(__isl_take isl_space *space,
+       enum isl_dim_type type, __isl_take isl_space *set)
+{
+       if (type == isl_dim_in) {
+               space = isl_space_range(space);
+               space = isl_space_map_from_domain_and_range(set, space);
+       } else {
+               space = isl_space_domain(space);
+               space = isl_space_map_from_domain_and_range(space, set);
+       }
+
+       return space;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "bmap" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
  *
- * If bset is represented by
+ * If bmap is represented by
  *
- *     A(p) + B x + C(divs) >= 0
+ *     A(p) + S u + B x + T v + C(divs) >= 0,
  *
+ * where u and x are input and output dimensions if type == isl_dim_out
+ * while x and v are input and output dimensions if type == isl_dim_in,
  * and ma is represented by
  *
  *     x = D(p) + F(y) + G(divs')
  *
  * then the result is
  *
- *     A(p) + B D(p) + B F(y) + B G(divs') + C(divs) >= 0
+ *     A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0
  *
  * The divs in the input set are similarly adjusted.
  * In particular
  *
- *     floor((a_i(p) + b_i x + c_i(divs))/n_i)
+ *     floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i)
  *
  * becomes
  *
- *     floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
+ *     floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v +
+ *             B_i G(divs') + c_i(divs))/n_i)
  *
- * If bset is not a rational set and if F(y) involves any denominators
+ * If bmap is not a rational map and if F(y) involves any denominators
  *
  *     x_i = (f_i y + h_i)/m_i
  *
- * the additional constraints are added to ensure that we only
+ * then additional constraints are added to ensure that we only
  * map back integer points.  That is we enforce
  *
  *     f_i y + h_i = m_i alpha_i
@@ -11146,16 +11492,17 @@ error:
  * with alpha_i an additional existentially quantified variable.
  *
  * We first copy over the divs from "ma".
- * Then we add the modified constraints and divs from "bset".
+ * Then we add the modified constraints and divs from "bmap".
  * Finally, we add the stride constraints, if needed.
  */
-__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
-       __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma)
+__isl_give isl_basic_map *isl_basic_map_preimage_multi_aff(
+       __isl_take isl_basic_map *bmap, enum isl_dim_type type,
+       __isl_take isl_multi_aff *ma)
 {
        int i, k;
        isl_space *space;
-       isl_basic_set *res = NULL;
-       int n_div_bset, n_div_ma;
+       isl_basic_map *res = NULL;
+       int n_before, n_after, n_div_bmap, n_div_ma;
        isl_int f, c1, c2, g;
        int rational, strides;
 
@@ -11165,144 +11512,212 @@ __isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
        isl_int_init(g);
 
        ma = isl_multi_aff_align_divs(ma);
-       if (!bset || !ma)
+       if (!bmap || !ma)
                goto error;
-       if (check_basic_set_compatible_range_multi_aff(bset, ma) < 0)
+       if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0)
                goto error;
 
-       n_div_bset = isl_basic_set_dim(bset, isl_dim_div);
+       if (type == isl_dim_in) {
+               n_before = 0;
+               n_after = isl_basic_map_dim(bmap, isl_dim_out);
+       } else {
+               n_before = isl_basic_map_dim(bmap, isl_dim_in);
+               n_after = 0;
+       }
+       n_div_bmap = isl_basic_map_dim(bmap, isl_dim_div);
        n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
 
-       space = isl_space_domain(isl_multi_aff_get_space(ma));
-       rational = isl_basic_set_is_rational(bset);
+       space = isl_multi_aff_get_domain_space(ma);
+       space = isl_space_set(isl_basic_map_get_space(bmap), type, space);
+       rational = isl_basic_map_is_rational(bmap);
        strides = rational ? 0 : multi_aff_strides(ma);
-       res = isl_basic_set_alloc_space(space, n_div_ma + n_div_bset + strides,
-                           bset->n_eq + strides, bset->n_ineq + 2 * n_div_ma);
+       res = isl_basic_map_alloc_space(space, n_div_ma + n_div_bmap + strides,
+                           bmap->n_eq + strides, bmap->n_ineq + 2 * n_div_ma);
        if (rational)
-               res = isl_basic_set_set_rational(res);
+               res = isl_basic_map_set_rational(res);
 
-       for (i = 0; i < n_div_ma + n_div_bset; ++i)
-               if (isl_basic_set_alloc_div(res) < 0)
+       for (i = 0; i < n_div_ma + n_div_bmap; ++i)
+               if (isl_basic_map_alloc_div(res) < 0)
                        goto error;
 
-       if (set_ma_divs(res, ma, n_div_ma) < 0)
+       if (set_ma_divs(res, ma, n_before, n_after, n_div_ma) < 0)
                goto error;
 
-       for (i = 0; i < bset->n_eq; ++i) {
-               k = isl_basic_set_alloc_equality(res);
+       for (i = 0; i < bmap->n_eq; ++i) {
+               k = isl_basic_map_alloc_equality(res);
                if (k < 0)
                        goto error;
-               isl_seq_preimage(res->eq[k], bset->eq[i], ma, n_div_ma,
-                                       n_div_bset, f, c1, c2, g, 0);
+               isl_seq_preimage(res->eq[k], bmap->eq[i], ma, n_before,
+                               n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
        }
 
-       for (i = 0; i < bset->n_ineq; ++i) {
-               k = isl_basic_set_alloc_inequality(res);
+       for (i = 0; i < bmap->n_ineq; ++i) {
+               k = isl_basic_map_alloc_inequality(res);
                if (k < 0)
                        goto error;
-               isl_seq_preimage(res->ineq[k], bset->ineq[i], ma, n_div_ma,
-                                       n_div_bset, f, c1, c2, g, 0);
+               isl_seq_preimage(res->ineq[k], bmap->ineq[i], ma, n_before,
+                               n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
        }
 
-       for (i = 0; i < bset->n_div; ++i) {
-               if (isl_int_is_zero(bset->div[i][0])) {
+       for (i = 0; i < bmap->n_div; ++i) {
+               if (isl_int_is_zero(bmap->div[i][0])) {
                        isl_int_set_si(res->div[n_div_ma + i][0], 0);
                        continue;
                }
-               isl_seq_preimage(res->div[n_div_ma + i], bset->div[i],
-                                   ma, n_div_ma, n_div_bset, f, c1, c2, g, 1);
+               isl_seq_preimage(res->div[n_div_ma + i], bmap->div[i], ma,
+                                   n_before, n_after, n_div_ma, n_div_bmap,
+                                   f, c1, c2, g, 1);
        }
 
        if (strides)
-               res = add_ma_strides(res, ma);
+               res = add_ma_strides(res, ma, n_before, n_after);
 
        isl_int_clear(f);
        isl_int_clear(c1);
        isl_int_clear(c2);
        isl_int_clear(g);
-       isl_basic_set_free(bset);
+       isl_basic_map_free(bmap);
        isl_multi_aff_free(ma);
        res = isl_basic_set_simplify(res);
-       return isl_basic_set_finalize(res);
+       return isl_basic_map_finalize(res);
 error:
        isl_int_clear(f);
        isl_int_clear(c1);
        isl_int_clear(c2);
        isl_int_clear(g);
-       isl_basic_set_free(bset);
+       isl_basic_map_free(bmap);
        isl_multi_aff_free(ma);
-       isl_basic_set_free(res);
+       isl_basic_map_free(res);
        return NULL;
 }
 
-/* Check if the range of "ma" is compatible with "set".
+/* Compute the preimage of "bset" under the function represented by "ma".
+ * In other words, plug in "ma" in "bset".  The result is a basic set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
+       __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma)
+{
+       return isl_basic_map_preimage_multi_aff(bset, isl_dim_set, ma);
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "map".
  * Return -1 if anything is wrong.
  */
-static int check_set_compatible_range_multi_aff(
-       __isl_keep isl_set *set, __isl_keep isl_multi_aff *ma)
+static int check_map_compatible_range_multi_aff(
+       __isl_keep isl_map *map, enum isl_dim_type type,
+       __isl_keep isl_multi_aff *ma)
 {
-       return check_space_compatible_range_multi_aff(set->dim, ma);
+       int m;
+       isl_space *ma_space;
+
+       ma_space = isl_multi_aff_get_space(ma);
+       m = isl_space_tuple_match(map->dim, type, ma_space, isl_dim_out);
+       isl_space_free(ma_space);
+       if (m >= 0 && !m)
+               isl_die(isl_map_get_ctx(map), isl_error_invalid,
+                       "spaces don't match", return -1);
+       return m;
 }
 
-/* Compute the preimage of "set" under the function represented by "ma".
- * In other words, plug in "ma" in "set.  The result is a set
- * that lives in the domain space of "ma".
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * The parameters are assumed to have been aligned.
  */
-static __isl_give isl_set *set_preimage_multi_aff(__isl_take isl_set *set,
-       __isl_take isl_multi_aff *ma)
+static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map,
+       enum isl_dim_type type, __isl_take isl_multi_aff *ma)
 {
        int i;
+       isl_space *space;
 
-       set = isl_set_cow(set);
+       map = isl_map_cow(map);
        ma = isl_multi_aff_align_divs(ma);
-       if (!set || !ma)
+       if (!map || !ma)
                goto error;
-       if (check_set_compatible_range_multi_aff(set, ma) < 0)
+       if (check_map_compatible_range_multi_aff(map, type, ma) < 0)
                goto error;
 
-       for (i = 0; i < set->n; ++i) {
-               set->p[i] = isl_basic_set_preimage_multi_aff(set->p[i],
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = isl_basic_map_preimage_multi_aff(map->p[i], type,
                                                        isl_multi_aff_copy(ma));
-               if (!set->p[i])
+               if (!map->p[i])
                        goto error;
        }
 
-       isl_space_free(set->dim);
-       set->dim = isl_multi_aff_get_domain_space(ma);
-       if (!set->dim)
+       space = isl_multi_aff_get_domain_space(ma);
+       space = isl_space_set(isl_map_get_space(map), type, space);
+
+       isl_space_free(map->dim);
+       map->dim = space;
+       if (!map->dim)
                goto error;
 
        isl_multi_aff_free(ma);
-       if (set->n > 1)
-               ISL_F_CLR(set, ISL_MAP_DISJOINT);
-       ISL_F_CLR(set, ISL_SET_NORMALIZED);
-       return set;
+       if (map->n > 1)
+               ISL_F_CLR(map, ISL_MAP_DISJOINT);
+       ISL_F_CLR(map, ISL_SET_NORMALIZED);
+       return map;
 error:
        isl_multi_aff_free(ma);
-       isl_set_free(set);
+       isl_map_free(map);
        return NULL;
 }
 
-__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
-       __isl_take isl_multi_aff *ma)
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map,
+       enum isl_dim_type type, __isl_take isl_multi_aff *ma)
 {
-       if (!set || !ma)
+       if (!map || !ma)
                goto error;
 
-       if (isl_space_match(set->dim, isl_dim_param, ma->space, isl_dim_param))
-               return set_preimage_multi_aff(set, ma);
+       if (isl_space_match(map->dim, isl_dim_param, ma->space, isl_dim_param))
+               return map_preimage_multi_aff(map, type, ma);
 
-       if (!isl_space_has_named_params(set->dim) ||
+       if (!isl_space_has_named_params(map->dim) ||
            !isl_space_has_named_params(ma->space))
-               isl_die(set->ctx, isl_error_invalid,
+               isl_die(map->ctx, isl_error_invalid,
                        "unaligned unnamed parameters", goto error);
-       set = isl_set_align_params(set, isl_multi_aff_get_space(ma));
-       ma = isl_multi_aff_align_params(ma, isl_set_get_space(set));
+       map = isl_map_align_params(map, isl_multi_aff_get_space(ma));
+       ma = isl_multi_aff_align_params(ma, isl_map_get_space(map));
 
-       return set_preimage_multi_aff(set, ma);
+       return map_preimage_multi_aff(map, type, ma);
 error:
        isl_multi_aff_free(ma);
-       return isl_set_free(set);
+       return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "ma".
+ * In other words, plug in "ma" "set".  The result is a set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+       __isl_take isl_multi_aff *ma)
+{
+       return isl_map_preimage_multi_aff(set, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+       __isl_take isl_multi_aff *ma)
+{
+       return isl_map_preimage_multi_aff(map, isl_dim_in, ma);
 }
 
 /* Compute the preimage of "set" under the function represented by "pma".
index 0c41702..1196a87 100644 (file)
@@ -130,3 +130,13 @@ __isl_give TYPE *SF(isl_map_lexmax,SUFFIX)(__isl_take isl_map *map)
 {
        return SF(isl_map_lexopt,SUFFIX)(map, 1);
 }
+
+__isl_give TYPE *SF(isl_set_lexmin,SUFFIX)(__isl_take isl_set *set)
+{
+       return SF(isl_map_lexmin,SUFFIX)(set);
+}
+
+__isl_give TYPE *SF(isl_set_lexmax,SUFFIX)(__isl_take isl_set *set)
+{
+       return SF(isl_map_lexmax,SUFFIX)(set);
+}
index 5da97be..93010df 100644 (file)
 #define isl_basic_set  isl_basic_map
 #define isl_set                isl_map
 #define isl_basic_set_list     isl_basic_map_list
+#define isl_set_list   isl_map_list
+#include <isl/list.h>
+ISL_DECLARE_LIST(basic_map)
+ISL_DECLARE_LIST(map)
 #include <isl/set.h>
 #include <isl/map.h>
 #include <isl_reordering.h>
@@ -70,6 +74,11 @@ struct isl_basic_map {
        struct isl_blk block2;
 };
 
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
 /* A "map" is a (possibly disjoint) union of basic maps.
  * A "set" is a (possibly disjoint) union of basic sets.
  *
@@ -95,6 +104,11 @@ struct isl_map {
        struct isl_basic_map *p[1];
 };
 
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
 __isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
        __isl_take isl_reordering *r);
 __isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
index 47b13c0..5cb6bfb 100644 (file)
@@ -1042,9 +1042,39 @@ static int ok_to_set_div_from_bound(struct isl_basic_map *bmap,
        return 1;
 }
 
+/* Would an expression for div "div" based on inequality "ineq" of "bmap"
+ * be a better expression than the current one?
+ *
+ * If we do not have any expression yet, then any expression would be better.
+ * Otherwise we check if the last variable involved in the inequality
+ * (disregarding the div that it would define) is in an earlier position
+ * than the last variable involved in the current div expression.
+ */
+static int better_div_constraint(__isl_keep isl_basic_map *bmap,
+       int div, int ineq)
+{
+       unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+       int last_div;
+       int last_ineq;
+
+       if (isl_int_is_zero(bmap->div[div][0]))
+               return 1;
+
+       if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1,
+                                 bmap->n_div - (div + 1)) >= 0)
+               return 0;
+
+       last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div);
+       last_div = isl_seq_last_non_zero(bmap->div[div] + 1,
+                                        total + bmap->n_div);
+
+       return last_ineq < last_div;
+}
+
 /* Given two constraints "k" and "l" that are opposite to each other,
  * except for the constant term, check if we can use them
- * to obtain an expression for one of the hitherto unknown divs.
+ * to obtain an expression for one of the hitherto unknown divs or
+ * a "better" expression for a div for which we already have an expression.
  * "sum" is the sum of the constant terms of the constraints.
  * If this sum is strictly smaller than the coefficient of one
  * of the divs, then this pair can be used define the div.
@@ -1060,12 +1090,12 @@ static struct isl_basic_map *check_for_div_constraints(
        unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
 
        for (i = 0; i < bmap->n_div; ++i) {
-               if (!isl_int_is_zero(bmap->div[i][0]))
-                       continue;
                if (isl_int_is_zero(bmap->ineq[k][total + i]))
                        continue;
                if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
                        continue;
+               if (!better_div_constraint(bmap, i, k))
+                       continue;
                if (!ok_to_set_div_from_bound(bmap, i, k))
                        break;
                if (isl_int_is_pos(bmap->ineq[k][total + i]))
index cff8123..6b54849 100644 (file)
--- a/isl_mat.c
+++ b/isl_mat.c
@@ -8,10 +8,10 @@
  */
 
 #include <isl_ctx_private.h>
+#include <isl_map_private.h>
 #include <isl/space.h>
 #include <isl/seq.h>
 #include <isl_mat_private.h>
-#include "isl_map_private.h"
 #include <isl_space_private.h>
 
 isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
@@ -204,19 +204,21 @@ struct isl_mat *isl_mat_cow(struct isl_mat *mat)
        return mat2;
 }
 
-void isl_mat_free(struct isl_mat *mat)
+void *isl_mat_free(struct isl_mat *mat)
 {
        if (!mat)
-               return;
+               return NULL;
 
        if (--mat->ref > 0)
-               return;
+               return NULL;
 
        if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED))
                isl_blk_free(mat->ctx, mat->block);
        isl_ctx_deref(mat->ctx);
        free(mat->row);
        free(mat);
+
+       return NULL;
 }
 
 int isl_mat_rows(__isl_keep isl_mat *mat)
@@ -967,7 +969,8 @@ struct isl_mat *isl_mat_swap_rows(struct isl_mat *mat, unsigned i, unsigned j)
        return mat;
 }
 
-struct isl_mat *isl_mat_product(struct isl_mat *left, struct isl_mat *right)
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+       __isl_take isl_mat *right)
 {
        int i, j, k;
        struct isl_mat *prod;
@@ -1245,6 +1248,9 @@ struct isl_mat *isl_mat_drop_cols(struct isl_mat *mat, unsigned col, unsigned n)
 {
        int r;
 
+       if (n == 0)
+               return mat;
+
        mat = isl_mat_cow(mat);
        if (!mat)
                return NULL;
index 9fc39d2..3700874 100644 (file)
@@ -479,23 +479,20 @@ error:
  *
  * Let the equalities be given as
  *
- *     B(p) + A x = 0
+ *     B(p) + A x = 0.
  *
- * and let [H 0] be the Hermite Normal Form of A, then
+ * We use isl_mat_parameter_compression_ext to compute the compression
  *
- *     H^-1 B(p)
- *
- * needs to be integer, so we impose that each row is divisible by
- * the denominator.
+ *     p = T p'.
  */
 __isl_give isl_morph *isl_basic_set_parameter_compression(
        __isl_keep isl_basic_set *bset)
 {
        unsigned nparam;
        unsigned nvar;
+       unsigned n_div;
        int n_eq;
        isl_mat *H, *B;
-       isl_vec *d;
        isl_mat *map, *inv;
        isl_basic_set *dom, *ran;
 
@@ -507,35 +504,24 @@ __isl_give isl_morph *isl_basic_set_parameter_compression(
        if (bset->n_eq == 0)
                return isl_morph_identity(bset);
 
-       isl_assert(bset->ctx, bset->n_div == 0, return NULL);
-
        n_eq = bset->n_eq;
        nparam = isl_basic_set_dim(bset, isl_dim_param);
        nvar = isl_basic_set_dim(bset, isl_dim_set);
+       n_div = isl_basic_set_dim(bset, isl_dim_div);
 
        if (isl_seq_first_non_zero(bset->eq[bset->n_eq - 1] + 1 + nparam,
-                                   nvar) == -1)
+                                   nvar + n_div) == -1)
                isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
                        "input not allowed to have parameter equalities",
                        return NULL);
-       if (n_eq > nvar)
+       if (n_eq > nvar + n_div)
                isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
                        "input not gaussed", return NULL);
 
-       d = isl_vec_alloc(bset->ctx, n_eq);
        B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
-       H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 1 + nparam, nvar);
-       H = isl_mat_left_hermite(H, 0, NULL, NULL);
-       H = isl_mat_drop_cols(H, n_eq, nvar - n_eq);
-       H = isl_mat_lin_to_aff(H);
-       H = isl_mat_right_inverse(H);
-       if (!H || !d)
-               goto error;
-       d = isl_vec_set(d, H->row[0][0]);
-       H = isl_mat_drop_rows(H, 0, 1);
-       H = isl_mat_drop_cols(H, 0, 1);
-       B = isl_mat_product(H, B);
-       inv = isl_mat_parameter_compression(B, d);
+       H = isl_mat_sub_alloc6(bset->ctx, bset->eq,
+                               0, n_eq, 1 + nparam, nvar + n_div);
+       inv = isl_mat_parameter_compression_ext(B, H);
        inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar));
        map = isl_mat_right_inverse(isl_mat_copy(inv));
 
@@ -543,11 +529,6 @@ __isl_give isl_morph *isl_basic_set_parameter_compression(
        ran = isl_basic_set_universe(isl_space_copy(bset->dim));
 
        return isl_morph_alloc(dom, ran, map, inv);
-error:
-       isl_mat_free(H);
-       isl_mat_free(B);
-       isl_vec_free(d);
-       return NULL;
 }
 
 /* Add stride constraints to "bset" based on the inverse mapping
@@ -573,6 +554,7 @@ error:
  *
  *     exists alpha in Z^m: B x = d alpha
  *
+ * This function is similar to add_strides in isl_affine_hull.c
  */
 static __isl_give isl_basic_set *add_strides(__isl_take isl_basic_set *bset,
        __isl_keep isl_morph *morph)
index 7080493..a275f1b 100644 (file)
@@ -8,6 +8,10 @@
  * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
  */
 
+#include <isl_space_private.h>
+#include <isl/set.h>
+#include <isl_reordering.h>
+
 #define xCAT(A,B) A ## B
 #define CAT(A,B) xCAT(A,B)
 #undef EL
@@ -794,3 +798,43 @@ error:
        FN(MULTI(BASE),free)(multi2);
        return NULL;
 }
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+       __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+       __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+       __attribute__ ((unused));
+
+/* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
+ * return the result.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+       __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+       __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+{
+       int i;
+       isl_ctx *ctx;
+
+       multi1 = FN(MULTI(BASE),cow)(multi1);
+       if (!multi1 || !multi2)
+               goto error;
+
+       ctx = FN(MULTI(BASE),get_ctx)(multi1);
+       if (!isl_space_is_equal(multi1->space, multi2->space))
+               isl_die(ctx, isl_error_invalid,
+                       "spaces don't match", goto error);
+
+       for (i = 0; i < multi1->n; ++i) {
+               multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
+               if (!multi1->p[i])
+                       goto error;
+       }
+
+       FN(MULTI(BASE),free)(multi2);
+       return multi1;
+error:
+       FN(MULTI(BASE),free)(multi1);
+       FN(MULTI(BASE),free)(multi2);
+       return NULL;
+}
index 5a28219..342d9a2 100644 (file)
@@ -1,3 +1,5 @@
+#include <isl/space.h>
+
 #define xCAT(A,B) A ## B
 #define CAT(A,B) xCAT(A,B)
 #undef EL
index a5c6f66..4e5946a 100644 (file)
@@ -176,6 +176,8 @@ ISL_ARG_CHOICE(struct isl_options, schedule_fuse, 0, "schedule-fuse", fuse,
        ISL_SCHEDULE_FUSE_MAX, "level of fusion during scheduling")
 ISL_ARG_BOOL(struct isl_options, tile_scale_tile_loops, 0,
        "tile-scale-tile-loops", 1, "scale tile loops")
+ISL_ARG_BOOL(struct isl_options, tile_shift_point_loops, 0,
+       "tile-shift-point-loops", 1, "shift point loops to start at zero")
 ISL_ARG_STR(struct isl_options, ast_iterator_type, 0,
        "ast-iterator-type", "type", "int",
        "type used for iterators during printing of AST")
@@ -198,6 +200,8 @@ ISL_ARG_BOOL(struct isl_options, ast_build_scale_strides, 0,
        "allow iterators of strided loops to be scaled down")
 ISL_ARG_BOOL(struct isl_options, ast_build_allow_else, 0,
        "ast-build-allow-else", 1, "generate if statements with else branches")
+ISL_ARG_BOOL(struct isl_options, ast_build_allow_or, 0,
+       "ast-build-allow-or", 1, "generate if conditions with disjunctions")
 ISL_ARG_VERSION(print_version)
 ISL_ARGS_END
 
@@ -269,6 +273,11 @@ ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
        tile_scale_tile_loops)
 
 ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+       tile_shift_point_loops)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+       tile_shift_point_loops)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
        ast_build_atomic_upper_bound)
 ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
        ast_build_atomic_upper_bound)
@@ -307,3 +316,8 @@ ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
        ast_build_allow_else)
 ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
        ast_build_allow_else)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+       ast_build_allow_or)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+       ast_build_allow_or)
index b7cacb1..494bd1a 100644 (file)
@@ -58,6 +58,7 @@ struct isl_options {
        int                     schedule_fuse;
 
        int                     tile_scale_tile_loops;
+       int                     tile_shift_point_loops;
 
        char                    *ast_iterator_type;
 
@@ -68,6 +69,7 @@ struct isl_options {
        int                     ast_build_separation_bounds;
        int                     ast_build_scale_strides;
        int                     ast_build_allow_else;
+       int                     ast_build_allow_or;
 };
 
 #endif
index bc0937d..2dfdd0f 100644 (file)
@@ -3956,14 +3956,6 @@ error:
        return NULL;
 }
 
-__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sub(
-       __isl_take isl_union_pw_qpolynomial *upwqp1,
-       __isl_take isl_union_pw_qpolynomial *upwqp2)
-{
-       return isl_union_pw_qpolynomial_add(upwqp1,
-                                       isl_union_pw_qpolynomial_neg(upwqp2));
-}
-
 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul(
        __isl_take isl_union_pw_qpolynomial *upwqp1,
        __isl_take isl_union_pw_qpolynomial *upwqp2)
index cd027aa..e58dd57 100644 (file)
@@ -1,11 +1,13 @@
 /*
  * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
  *
  * Use of this software is governed by the MIT license
  *
  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
  * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
  */
 
 #include <isl_ctx_private.h>
@@ -24,7 +26,6 @@
 #include <isl_sort.h>
 #include <isl_schedule_private.h>
 #include <isl_band_private.h>
-#include <isl_list_private.h>
 #include <isl_options_private.h>
 #include <isl_tarjan.h>
 
@@ -326,7 +327,7 @@ static struct isl_sched_edge *graph_find_edge(struct isl_sched_graph *graph,
        return entry->data;
 }
 
-/* Check whether the dependence graph has an edge of the give type
+/* Check whether the dependence graph has an edge of the given type
  * between the given two nodes.
  */
 static int graph_has_edge(struct isl_sched_graph *graph,
@@ -3083,6 +3084,10 @@ static __isl_give isl_band_list *construct_band_list(
  * Because of the way the schedule is constructed, we know that
  * the position of the band inside the schedule of a node is the same
  * for all active nodes.
+ *
+ * The partial schedule for the band is created before the children
+ * are created to that construct_band_list can refer to the partial
+ * schedule of the parent.
  */
 static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
        __isl_keep isl_band *parent,
@@ -3101,17 +3106,6 @@ static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
        band->parent = parent;
 
        for (i = 0; i < schedule->n; ++i)
-               if (active[i] && schedule->node[i].n_band > band_nr + 1)
-                       break;
-
-       if (i < schedule->n) {
-               band->children = construct_band_list(schedule, band,
-                                               band_nr + 1, active, n_active);
-               if (!band->children)
-                       goto error;
-       }
-
-       for (i = 0; i < schedule->n; ++i)
                if (active[i])
                        break;
 
@@ -3151,12 +3145,245 @@ static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
        if (!band->pma)
                goto error;
 
+       for (i = 0; i < schedule->n; ++i)
+               if (active[i] && schedule->node[i].n_band > band_nr + 1)
+                       break;
+
+       if (i < schedule->n) {
+               band->children = construct_band_list(schedule, band,
+                                               band_nr + 1, active, n_active);
+               if (!band->children)
+                       goto error;
+       }
+
        return band;
 error:
        isl_band_free(band);
        return NULL;
 }
 
+/* Internal data structure used inside cmp_band and pw_multi_aff_extract_int.
+ *
+ * r is set to a negative value if anything goes wrong.
+ *
+ * c1 stores the result of extract_int.
+ * c2 is a temporary value used inside cmp_band_in_ancestor.
+ * t is a temporary value used inside extract_int.
+ *
+ * first and equal are used inside extract_int.
+ * first is set if we are looking at the first isl_multi_aff inside
+ * the isl_union_pw_multi_aff.
+ * equal is set if all the isl_multi_affs have been equal so far.
+ */
+struct isl_cmp_band_data {
+       int r;
+
+       int first;
+       int equal;
+
+       isl_int t;
+       isl_int c1;
+       isl_int c2;
+};
+
+/* Check if "ma" assigns a constant value.
+ * Note that this function is only called on isl_multi_affs
+ * with a single output dimension.
+ *
+ * If "ma" assigns a constant value then we compare it to data->c1
+ * or assign it to data->c1 if this is the first isl_multi_aff we consider.
+ * If "ma" does not assign a constant value or if it assigns a value
+ * that is different from data->c1, then we set data->equal to zero
+ * and terminate the check.
+ */
+static int multi_aff_extract_int(__isl_take isl_set *set,
+       __isl_take isl_multi_aff *ma, void *user)
+{
+       isl_aff *aff;
+       struct isl_cmp_band_data *data = user;
+
+       aff = isl_multi_aff_get_aff(ma, 0);
+       data->r = isl_aff_is_cst(aff);
+       if (data->r >= 0 && data->r) {
+               isl_aff_get_constant(aff, &data->t);
+               if (data->first) {
+                       isl_int_set(data->c1, data->t);
+                       data->first = 0;
+               } else if (!isl_int_eq(data->c1, data->t))
+                       data->equal = 0;
+       } else if (data->r >= 0 && !data->r)
+               data->equal = 0;
+
+       isl_aff_free(aff);
+       isl_set_free(set);
+       isl_multi_aff_free(ma);
+
+       if (data->r < 0)
+               return -1;
+       if (!data->equal)
+               return -1;
+       return 0;
+}
+
+/* This function is called for each isl_pw_multi_aff in
+ * the isl_union_pw_multi_aff checked by extract_int.
+ * Check all the isl_multi_affs inside "pma".
+ */
+static int pw_multi_aff_extract_int(__isl_take isl_pw_multi_aff *pma,
+       void *user)
+{
+       int r;
+
+       r = isl_pw_multi_aff_foreach_piece(pma, &multi_aff_extract_int, user);
+       isl_pw_multi_aff_free(pma);
+
+       return r;
+}
+
+/* Check if "upma" assigns a single constant value to its domain.
+ * If so, return 1 and store the result in data->c1.
+ * If not, return 0.
+ *
+ * A negative return value from isl_union_pw_multi_aff_foreach_pw_multi_aff
+ * means that either an error occurred or that we have broken off the check
+ * because we already know the result is going to be negative.
+ * In the latter case, data->equal is set to zero.
+ */
+static int extract_int(__isl_keep isl_union_pw_multi_aff *upma,
+       struct isl_cmp_band_data *data)
+{
+       data->first = 1;
+       data->equal = 1;
+
+       if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+                                       &pw_multi_aff_extract_int, data) < 0) {
+               if (!data->equal)
+                       return 0;
+               return -1;
+       }
+
+       return !data->first && data->equal;
+}
+
+/* Compare "b1" and "b2" based on the parent schedule of their ancestor
+ * "ancestor".
+ *
+ * If the parent of "ancestor" also has a single member, then we
+ * first try to compare the two band based on the partial schedule
+ * of this parent.
+ *
+ * Otherwise, or if the result is inconclusive, we look at the partial schedule
+ * of "ancestor" itself.
+ * In particular, we specialize the parent schedule based
+ * on the domains of the child schedules, check if both assign
+ * a single constant value and, if so, compare the two constant values.
+ * If the specialized parent schedules do not assign a constant value,
+ * then they cannot be used to order the two bands and so in this case
+ * we return 0.
+ */
+static int cmp_band_in_ancestor(__isl_keep isl_band *b1,
+       __isl_keep isl_band *b2, struct isl_cmp_band_data *data,
+       __isl_keep isl_band *ancestor)
+{
+       isl_union_pw_multi_aff *upma;
+       isl_union_set *domain;
+       int r;
+
+       if (data->r < 0)
+               return 0;
+
+       if (ancestor->parent && ancestor->parent->n == 1) {
+               r = cmp_band_in_ancestor(b1, b2, data, ancestor->parent);
+               if (data->r < 0)
+                       return 0;
+               if (r)
+                       return r;
+       }
+
+       upma = isl_union_pw_multi_aff_copy(b1->pma);
+       domain = isl_union_pw_multi_aff_domain(upma);
+       upma = isl_union_pw_multi_aff_copy(ancestor->pma);
+       upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
+       r = extract_int(upma, data);
+       isl_union_pw_multi_aff_free(upma);
+
+       if (r < 0)
+               data->r = -1;
+       if (r < 0 || !r)
+               return 0;
+
+       isl_int_set(data->c2, data->c1);
+
+       upma = isl_union_pw_multi_aff_copy(b2->pma);
+       domain = isl_union_pw_multi_aff_domain(upma);
+       upma = isl_union_pw_multi_aff_copy(ancestor->pma);
+       upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
+       r = extract_int(upma, data);
+       isl_union_pw_multi_aff_free(upma);
+
+       if (r < 0)
+               data->r = -1;
+       if (r < 0 || !r)
+               return 0;
+
+       return isl_int_cmp(data->c2, data->c1);
+}
+
+/* Compare "a" and "b" based on the parent schedule of their parent.
+ */
+static int cmp_band(const void *a, const void *b, void *user)
+{
+       isl_band *b1 = *(isl_band * const *) a;
+       isl_band *b2 = *(isl_band * const *) b;
+       struct isl_cmp_band_data *data = user;
+
+       return cmp_band_in_ancestor(b1, b2, data, b1->parent);
+}
+
+/* Sort the elements in "list" based on the partial schedules of its parent
+ * (and ancestors).  In particular if the parent assigns constant values
+ * to the domains of the bands in "list", then the elements are sorted
+ * according to that order.
+ * This order should be a more "natural" order for the user, but otherwise
+ * shouldn't have any effect.
+ * If we would be constructing an isl_band forest directly in
+ * isl_union_set_compute_schedule then there wouldn't be any need
+ * for a reordering, since the children would be added to the list
+ * in their natural order automatically.
+ *
+ * If there is only one element in the list, then there is no need to sort
+ * anything.
+ * If the partial schedule of the parent has more than one member
+ * (or if there is no parent), then it's
+ * defnitely not assigning constant values to the different children in
+ * the list and so we wouldn't be able to use it to sort the list.
+ */
+static __isl_give isl_band_list *sort_band_list(__isl_take isl_band_list *list,
+       __isl_keep isl_band *parent)
+{
+       struct isl_cmp_band_data data;
+
+       if (!list)
+               return NULL;
+       if (list->n <= 1)
+               return list;
+       if (!parent || parent->n != 1)
+               return list;
+
+       data.r = 0;
+       isl_int_init(data.c1);
+       isl_int_init(data.c2);
+       isl_int_init(data.t);
+       isl_sort(list->p, list->n, sizeof(list->p[0]), &cmp_band, &data);
+       if (data.r < 0)
+               list = isl_band_list_free(list);
+       isl_int_clear(data.c1);
+       isl_int_clear(data.c2);
+       isl_int_clear(data.t);
+
+       return list;
+}
+
 /* Construct a list of bands that start at the same position (with
  * sequence number band_nr) in the schedules of the nodes that
  * were active in the parent band.
@@ -3241,6 +3468,8 @@ static __isl_give isl_band_list *construct_band_list(
 
        free(active);
 
+       list = sort_band_list(list, parent);
+
        return list;
 }
 
diff --git a/isl_set_list.c b/isl_set_list.c
new file mode 100644 (file)
index 0000000..b279827
--- /dev/null
@@ -0,0 +1,21 @@
+#include <isl/set.h>
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE basic_set
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE set
+
+#include <isl_list_templ.c>
index e6f957c..499dd1a 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <isl_space_private.h>
 #include <isl_id_private.h>
 #include <isl_reordering.h>
index cc4a89e..8c4a682 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef ISL_SPACE_PRIVATE
+#define ISL_SPACE_PRIVATE
+
 #include <isl/space.h>
 #include <isl/hash.h>
 #include <isl/id.h>
@@ -51,3 +54,5 @@ __isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local
 
 __isl_give isl_space *isl_space_extend_domain_with_range(
        __isl_take isl_space *domain, __isl_take isl_space *model);
+
+#endif
index 35ff7fc..e4cc386 100644 (file)
--- a/isl_tab.c
+++ b/isl_tab.c
@@ -89,6 +89,11 @@ error:
        return NULL;
 }
 
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab)
+{
+       return tab ? isl_mat_get_ctx(tab->mat) : NULL;
+}
+
 int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new)
 {
        unsigned off;
@@ -2600,6 +2605,29 @@ error:
        return NULL;
 }
 
+/* Remove the sign constraint from constraint "con".
+ *
+ * If the constraint variable was originally marked non-negative,
+ * then we make sure we mark it non-negative again during rollback.
+ */
+int isl_tab_unrestrict(struct isl_tab *tab, int con)
+{
+       struct isl_tab_var *var;
+
+       if (!tab)
+               return -1;
+
+       var = &tab->con[con];
+       if (!var->is_nonneg)
+               return 0;
+
+       var->is_nonneg = 0;
+       if (isl_tab_push_var(tab, isl_tab_undo_unrestrict, var) < 0)
+               return -1;
+
+       return 0;
+}
+
 int isl_tab_select_facet(struct isl_tab *tab, int con)
 {
        if (!tab)
@@ -3051,6 +3079,21 @@ static int unrelax(struct isl_tab *tab, struct isl_tab_var *var)
        return 0;
 }
 
+/* Undo the operation performed by isl_tab_unrestrict.
+ *
+ * In particular, mark the variable as being non-negative and make
+ * sure the sample value respects this constraint.
+ */
+static int ununrestrict(struct isl_tab *tab, struct isl_tab_var *var)
+{
+       var->is_nonneg = 1;
+
+       if (var->is_row && restore_row(tab, var) < -1)
+               return -1;
+
+       return 0;
+}
+
 static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNUSED;
 static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo)
 {
@@ -3093,6 +3136,8 @@ static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo)
                break;
        case isl_tab_undo_relax:
                return unrelax(tab, var);
+       case isl_tab_undo_unrestrict:
+               return ununrestrict(tab, var);
        default:
                isl_die(tab->mat->ctx, isl_error_internal,
                        "perform_undo_var called on invalid undo record",
@@ -3193,6 +3238,7 @@ static int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo)
        case isl_tab_undo_zero:
        case isl_tab_undo_allocate:
        case isl_tab_undo_relax:
+       case isl_tab_undo_unrestrict:
                return perform_undo_var(tab, undo);
        case isl_tab_undo_bmap_eq:
                return isl_basic_map_free_equality(tab->bmap, 1);
index b48db73..8b808f0 100644 (file)
--- a/isl_tab.h
+++ b/isl_tab.h
@@ -35,6 +35,7 @@ enum isl_tab_undo_type {
        isl_tab_undo_zero,
        isl_tab_undo_allocate,
        isl_tab_undo_relax,
+       isl_tab_undo_unrestrict,
        isl_tab_undo_bmap_ineq,
        isl_tab_undo_bmap_eq,
        isl_tab_undo_bmap_div,
@@ -181,6 +182,8 @@ struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx,
        unsigned n_row, unsigned n_var, unsigned M);
 void isl_tab_free(struct isl_tab *tab);
 
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab);
+
 __isl_give struct isl_tab *isl_tab_from_basic_map(
        __isl_keep isl_basic_map *bmap, int track);
 __isl_give struct isl_tab *isl_tab_from_basic_set(
@@ -234,6 +237,7 @@ int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED
 
 struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED;
 int isl_tab_select_facet(struct isl_tab *tab, int con) WARN_UNUSED;
+int isl_tab_unrestrict(struct isl_tab *tab, int con) WARN_UNUSED;
 
 void isl_tab_dump(__isl_keep struct isl_tab *tab);
 
index 6f4a2a7..2592a28 100644 (file)
@@ -3876,6 +3876,24 @@ error:
        sol->error = 1;
 }
 
+/* Does "sol" contain a pair of partial solutions that could potentially
+ * be merged?
+ *
+ * We currently only check that "sol" is not in an error state
+ * and that there are at least two partial solutions of which the final two
+ * are defined at the same level.
+ */
+static int sol_has_mergeable_solutions(struct isl_sol *sol)
+{
+       if (sol->error)
+               return 0;
+       if (!sol->partial)
+               return 0;
+       if (!sol->partial->next)
+               return 0;
+       return sol->partial->level == sol->partial->next->level;
+}
+
 /* Compute the lexicographic minimum of the set represented by the main
  * tableau "tab" within the context "sol->context_tab".
  *
@@ -3886,10 +3904,20 @@ error:
  * corresponding rows may not be marked as being non-negative.
  * In parts of the context where the added equality does not hold,
  * the main tableau is marked as being empty.
+ *
+ * Before we embark on the actual computation, we save a copy
+ * of the context.  When we return, we check if there are any
+ * partial solutions that can potentially be merged.  If so,
+ * we perform a rollback to the initial state of the context.
+ * The merging of partial solutions happens inside calls to
+ * sol_dec_level that are pushed onto the undo stack of the context.
+ * If there are no partial solutions that can potentially be merged
+ * then the rollback is skipped as it would just be wasted effort.
  */
 static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab)
 {
        int row;
+       void *saved;
 
        if (!tab)
                goto error;
@@ -3939,8 +3967,15 @@ static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab)
                row = tab->n_redundant - 1;
        }
 
+       saved = sol->context->op->save(sol->context);
+
        find_solutions(sol, tab);
 
+       if (sol_has_mergeable_solutions(sol))
+               sol->context->op->restore(sol->context, saved);
+       else
+               sol->context->op->discard(saved);
+
        sol->level = 0;
        sol_pop(sol);
 
index 951ac75..34d9626 100644 (file)
@@ -205,6 +205,9 @@ int test_parse(struct isl_ctx *ctx)
                                      "[n] -> { [i] : i <= n }") < 0)
                return -1;
 
+       if (test_parse_map_equal(ctx, "{ [*] }", "{ [a] }") < 0)
+               return -1;
+
        return 0;
 }
 
@@ -716,8 +719,9 @@ int test_affine_hull(struct isl_ctx *ctx)
 {
        const char *str;
        isl_set *set;
-       isl_basic_set *bset;
+       isl_basic_set *bset, *bset2;
        int n;
+       int subset;
 
        test_affine_hull_case(ctx, "affine2");
        test_affine_hull_case(ctx, "affine");
@@ -735,6 +739,33 @@ int test_affine_hull(struct isl_ctx *ctx)
                isl_die(ctx, isl_error_unknown, "not expecting any divs",
                        return -1);
 
+       /* Check that isl_map_affine_hull is not confused by
+        * the reordering of divs in isl_map_align_divs.
+        */
+       str = "{ [a, b, c, 0] : exists (e0 = [(b)/32], e1 = [(c)/32]: "
+                               "32e0 = b and 32e1 = c); "
+               "[a, 0, c, 0] : exists (e0 = [(c)/32]: 32e0 = c) }";
+       set = isl_set_read_from_str(ctx, str);
+       bset = isl_set_affine_hull(set);
+       isl_basic_set_free(bset);
+       if (!bset)
+               return -1;
+
+       str = "{ [a] : exists e0, e1, e2: 32e1 = 31 + 31a + 31e0 and "
+                       "32e2 = 31 + 31e0 }";
+       set = isl_set_read_from_str(ctx, str);
+       bset = isl_set_affine_hull(set);
+       str = "{ [a] : exists e : a = 32 e }";
+       bset2 = isl_basic_set_read_from_str(ctx, str);
+       subset = isl_basic_set_is_subset(bset, bset2);
+       isl_basic_set_free(bset);
+       isl_basic_set_free(bset2);
+       if (subset < 0)
+               return -1;
+       if (!subset)
+               isl_die(ctx, isl_error_unknown, "not as accurate as expected",
+                       return -1);
+
        return 0;
 }
 
@@ -927,140 +958,35 @@ error:
        return r;
 }
 
-int test_coalesce(struct isl_ctx *ctx)
-{
+/* Inputs for coalescing tests.
+ * "str" is a string representation of the input set.
+ * "single_disjunct" is set if we expect the result to consist of
+ *     a single disjunct.
+ */
+struct {
+       int single_disjunct;
        const char *str;
-       struct isl_set *set, *set2;
-       struct isl_map *map, *map2;
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: x >= 0 & x <= 10 & y >= 0 & y <= 10 or "
-                      "y >= x & x >= 2 & 5 >= y }");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
-                      "x + y >= 10 & y <= x & x + y <= 20 & y >= 0}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
-                      "x + y >= 10 & y <= x & x + y <= 19 & y >= 0}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 2);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x >= 6 & x <= 10 & y <= x}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x >= 7 & x <= 10 & y <= x}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 2);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x >= 6 & x <= 10 & y + 1 <= x}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 2);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x = 6 & y <= 6}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x = 7 & y <= 6}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 2);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x = 6 & y <= 5}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       set2 = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x = 6 & y <= 5}");
-       assert(isl_set_is_equal(set, set2));
-       isl_set_free(set);
-       isl_set_free(set2);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y]: y >= 0 & x <= 5 & y <= x or "
-                      "y >= 0 & x = 6 & y <= 7}");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 2);
-       isl_set_free(set);
-
-       set = isl_set_read_from_str(ctx,
-               "[n] -> { [i] : i = 1 and n >= 2 or 2 <= i and i <= n }");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       set2 = isl_set_read_from_str(ctx,
-               "[n] -> { [i] : i = 1 and n >= 2 or 2 <= i and i <= n }");
-       assert(isl_set_is_equal(set, set2));
-       isl_set_free(set);
-       isl_set_free(set2);
-
-       set = isl_set_read_from_str(ctx,
-               "{[x,y] : x >= 0 and y >= 0 or 0 <= y and y <= 5 and x = -1}");
-       set = isl_set_coalesce(set);
-       set2 = isl_set_read_from_str(ctx,
-               "{[x,y] : x >= 0 and y >= 0 or 0 <= y and y <= 5 and x = -1}");
-       assert(isl_set_is_equal(set, set2));
-       isl_set_free(set);
-       isl_set_free(set2);
-
-       set = isl_set_read_from_str(ctx,
-               "[n] -> { [i] : 1 <= i and i <= n - 1 or "
-                               "2 <= i and i <= n }");
-       set = isl_set_coalesce(set);
-       assert(set && set->n == 1);
-       set2 = isl_set_read_from_str(ctx,
-               "[n] -> { [i] : 1 <= i and i <= n - 1 or "
-                               "2 <= i and i <= n }");
-       assert(isl_set_is_equal(set, set2));
-       isl_set_free(set);
-       isl_set_free(set2);
-
-       map = isl_map_read_from_str(ctx,
-               "[n] -> { [i0] -> [o0] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
-               "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
-               "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
-               "4e4 = -2 + o0 and i0 >= 8 + 2n and o0 >= 2 + i0 and "
-               "o0 <= 56 + 2n and o0 <= -12 + 4n and i0 <= 57 + 2n and "
-               "i0 <= -11 + 4n and o0 >= 6 + 2n and 4e0 <= i0 and "
-               "4e0 >= -3 + i0 and 4e1 <= o0 and 4e1 >= -3 + o0 and "
-               "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0);"
-               "[i0] -> [o0] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
-               "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
-               "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
-               "4e4 = -2 + o0 and 2e0 >= 3 + n and e0 <= -4 + n and "
-               "2e0 <= 27 + n and e1 <= -4 + n and 2e1 <= 27 + n and "
-               "2e1 >= 2 + n and e1 >= 1 + e0 and i0 >= 7 + 2n and "
-               "i0 <= -11 + 4n and i0 <= 57 + 2n and 4e0 <= -2 + i0 and "
-               "4e0 >= -3 + i0 and o0 >= 6 + 2n and o0 <= -11 + 4n and "
-               "o0 <= 57 + 2n and 4e1 <= -2 + o0 and 4e1 >= -3 + o0 and "
-               "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0 ) }");
-       map = isl_map_coalesce(map);
-       map2 = isl_map_read_from_str(ctx,
-               "[n] -> { [i0] -> [o0] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
+} coalesce_tests[] = {
+       { 1, "{[x,y]: x >= 0 & x <= 10 & y >= 0 & y <= 10 or "
+                      "y >= x & x >= 2 & 5 >= y }" },
+       { 1, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
+                      "x + y >= 10 & y <= x & x + y <= 20 & y >= 0}" },
+       { 0, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
+                      "x + y >= 10 & y <= x & x + y <= 19 & y >= 0}" },
+       { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+                      "y >= 0 & x >= 6 & x <= 10 & y <= x}" },
+       { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+                      "y >= 0 & x >= 7 & x <= 10 & y <= x}" },
+       { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+                      "y >= 0 & x >= 6 & x <= 10 & y + 1 <= x}" },
+       { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 6}" },
+       { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 7 & y <= 6}" },
+       { 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 5}" },
+       { 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 7}" },
+       { 1, "[n] -> { [i] : i = 1 and n >= 2 or 2 <= i and i <= n }" },
+       { 0, "{[x,y] : x >= 0 and y >= 0 or 0 <= y and y <= 5 and x = -1}" },
+       { 1, "[n] -> { [i] : 1 <= i and i <= n - 1 or 2 <= i and i <= n }" },
+       { 0, "[n] -> { [[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
                "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
                "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
                "4e4 = -2 + o0 and i0 >= 8 + 2n and o0 >= 2 + i0 and "
@@ -1068,7 +994,7 @@ int test_coalesce(struct isl_ctx *ctx)
                "i0 <= -11 + 4n and o0 >= 6 + 2n and 4e0 <= i0 and "
                "4e0 >= -3 + i0 and 4e1 <= o0 and 4e1 >= -3 + o0 and "
                "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0);"
-               "[i0] -> [o0] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
+               "[[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
                "e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
                "e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
                "4e4 = -2 + o0 and 2e0 >= 3 + n and e0 <= -4 + n and "
@@ -1077,24 +1003,13 @@ int test_coalesce(struct isl_ctx *ctx)
                "i0 <= -11 + 4n and i0 <= 57 + 2n and 4e0 <= -2 + i0 and "
                "4e0 >= -3 + i0 and o0 >= 6 + 2n and o0 <= -11 + 4n and "
                "o0 <= 57 + 2n and 4e1 <= -2 + o0 and 4e1 >= -3 + o0 and "
-               "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0 ) }");
-       assert(isl_map_is_equal(map, map2));
-       isl_map_free(map);
-       isl_map_free(map2);
-
-       str = "[n, m] -> { [] -> [o0, o2, o3] : (o3 = 1 and o0 >= 1 + m and "
+               "4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0 ) }" },
+       { 0, "[n, m] -> { [o0, o2, o3] : (o3 = 1 and o0 >= 1 + m and "
              "o0 <= n + m and o2 <= m and o0 >= 2 + n and o2 >= 3) or "
              "(o0 >= 2 + n and o0 >= 1 + m and o0 <= n + m and n >= 1 and "
-             "o3 <= -1 + o2 and o3 >= 1 - m + o2 and o3 >= 2 and o3 <= n) }";
-       map = isl_map_read_from_str(ctx, str);
-       map = isl_map_coalesce(map);
-       map2 = isl_map_read_from_str(ctx, str);
-       assert(isl_map_is_equal(map, map2));
-       isl_map_free(map);
-       isl_map_free(map2);
-
-       str = "[M, N] -> { [i0, i1, i2, i3, i4, i5, i6] -> "
-         "[o0, o1, o2, o3, o4, o5, o6] : "
+             "o3 <= -1 + o2 and o3 >= 1 - m + o2 and o3 >= 2 and o3 <= n) }" },
+       { 0, "[M, N] -> { [[i0, i1, i2, i3, i4, i5, i6] -> "
+         "[o0, o1, o2, o3, o4, o5, o6]] : "
          "(o6 <= -4 + 2M - 2N + i0 + i1 - i2 + i6 - o0 - o1 + o2 and "
          "o3 <= -2 + i3 and o6 >= 2 + i0 + i3 + i6 - o0 - o3 and "
          "o6 >= 2 - M + N + i3 + i4 + i6 - o3 - o4 and o0 <= -1 + i0 and "
@@ -1107,97 +1022,83 @@ int test_coalesce(struct isl_ctx *ctx)
          "(N >= 2 and o3 <= -1 + i3 and o0 <= -1 + i0 and "
          "o6 >= i3 + i6 - o3 and M >= 0 and "
          "2o6 >= 1 + i0 + i3 + 2i6 - o0 - o3 and "
-         "o6 >= 1 - M + i0 + i6 - o0 and N >= 2M and o6 >= i0 + i6 - o0) }";
-       map = isl_map_read_from_str(ctx, str);
-       map = isl_map_coalesce(map);
-       map2 = isl_map_read_from_str(ctx, str);
-       assert(isl_map_is_equal(map, map2));
-       isl_map_free(map);
-       isl_map_free(map2);
-
-       str = "[M, N] -> { [] -> [o0] : (o0 = 0 and M >= 1 and N >= 2) or "
+         "o6 >= 1 - M + i0 + i6 - o0 and N >= 2M and o6 >= i0 + i6 - o0) }" },
+       { 0, "[M, N] -> { [o0] : (o0 = 0 and M >= 1 and N >= 2) or "
                "(o0 = 0 and M >= 1 and N >= 2M and N >= 2 + M) or "
                "(o0 = 0 and M >= 2 and N >= 3) or "
-               "(M = 0 and o0 = 0 and N >= 3) }";
-       map = isl_map_read_from_str(ctx, str);
-       map = isl_map_coalesce(map);
-       map2 = isl_map_read_from_str(ctx, str);
-       assert(isl_map_is_equal(map, map2));
-       isl_map_free(map);
-       isl_map_free(map2);
-
-       str = "{ [i0, i1, i2, i3] : (i1 = 10i0 and i0 >= 1 and 10i0 <= 100 and "
-               "i3 <= 9 + 10 i2 and i3 >= 1 + 10i2 and i3 >= 0) or "
-               "(i1 <= 9 + 10i0 and i1 >= 1 + 10i0 and i2 >= 0 and "
-               "i0 >= 0 and i1 <= 100 and i3 <= 9 + 10i2 and i3 >= 1 + 10i2) }";
-       map = isl_map_read_from_str(ctx, str);
-       map = isl_map_coalesce(map);
-       map2 = isl_map_read_from_str(ctx, str);
-       assert(isl_map_is_equal(map, map2));
-       isl_map_free(map);
-       isl_map_free(map2);
-
-       test_coalesce_set(ctx,
-               "[M] -> { [i1] : (i1 >= 2 and i1 <= M) or "
-                               "(i1 = M and M >= 1) }", 0);
-       test_coalesce_set(ctx,
-               "{[x,y] : x,y >= 0; [x,y] : 10 <= x <= 20 and y >= -1 }", 0);
-       test_coalesce_set(ctx,
-               "{ [x, y] : (x >= 1 and y >= 1 and x <= 2 and y <= 2) or "
-               "(y = 3 and x = 1) }", 1);
-       test_coalesce_set(ctx,
-               "[M] -> { [i0, i1, i2, i3, i4] : (i1 >= 3 and i4 >= 2 + i2 and "
+               "(M = 0 and o0 = 0 and N >= 3) }" },
+       { 0, "{ [i0, i1, i2, i3] : (i1 = 10i0 and i0 >= 1 and 10i0 <= 100 and "
+           "i3 <= 9 + 10 i2 and i3 >= 1 + 10i2 and i3 >= 0) or "
+           "(i1 <= 9 + 10i0 and i1 >= 1 + 10i0 and i2 >= 0 and "
+           "i0 >= 0 and i1 <= 100 and i3 <= 9 + 10i2 and i3 >= 1 + 10i2) }" },
+       { 0, "[M] -> { [i1] : (i1 >= 2 and i1 <= M) or (i1 = M and M >= 1) }" },
+       { 0, "{[x,y] : x,y >= 0; [x,y] : 10 <= x <= 20 and y >= -1 }" },
+       { 1, "{ [x, y] : (x >= 1 and y >= 1 and x <= 2 and y <= 2) or "
+               "(y = 3 and x = 1) }" },
+       { 1, "[M] -> { [i0, i1, i2, i3, i4] : (i1 >= 3 and i4 >= 2 + i2 and "
                "i2 >= 2 and i0 >= 2 and i3 >= 1 + i2 and i0 <= M and "
                "i1 <= M and i3 <= M and i4 <= M) or "
                "(i1 >= 2 and i4 >= 1 + i2 and i2 >= 2 and i0 >= 2 and "
                "i3 >= 1 + i2 and i0 <= M and i1 <= -1 + M and i3 <= M and "
-               "i4 <= -1 + M) }", 1);
-       test_coalesce_set(ctx,
-               "{ [x, y] : (x >= 0 and y >= 0 and x <= 10 and y <= 10) or "
-               "(x >= 1 and y >= 1 and x <= 11 and y <= 11) }", 1);
-       if (test_coalesce_unbounded_wrapping(ctx) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{[x,0] : x >= 0; [x,1] : x <= 20}", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [x, 1 - x] : 0 <= x <= 1; [0,0] }", 1) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [0,0]; [i,i] : 1 <= i <= 10 }", 1) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [0,0]; [i,j] : 1 <= i,j <= 10 }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [0,0]; [i,2i] : 1 <= i <= 10 }", 1) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [0,0]; [i,2i] : 2 <= i <= 10 }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [1,0]; [i,2i] : 1 <= i <= 10 }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [0,1]; [i,2i] : 1 <= i <= 10 }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [a, b] : exists e : 2e = a and "
-                   "a >= 0 and (a <= 3 or (b <= 0 and b >= -4 + a)) }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx,
-               "{ [i, j, i', j'] : i <= 2 and j <= 2 and "
+               "i4 <= -1 + M) }" },
+       { 1, "{ [x, y] : (x >= 0 and y >= 0 and x <= 10 and y <= 10) or "
+               "(x >= 1 and y >= 1 and x <= 11 and y <= 11) }" },
+       { 0, "{[x,0] : x >= 0; [x,1] : x <= 20}" },
+       { 1, "{ [x, 1 - x] : 0 <= x <= 1; [0,0] }" },
+       { 1, "{ [0,0]; [i,i] : 1 <= i <= 10 }" },
+       { 0, "{ [0,0]; [i,j] : 1 <= i,j <= 10 }" },
+       { 1, "{ [0,0]; [i,2i] : 1 <= i <= 10 }" },
+       { 0, "{ [0,0]; [i,2i] : 2 <= i <= 10 }" },
+       { 0, "{ [1,0]; [i,2i] : 1 <= i <= 10 }" },
+       { 0, "{ [0,1]; [i,2i] : 1 <= i <= 10 }" },
+       { 0, "{ [a, b] : exists e : 2e = a and "
+                   "a >= 0 and (a <= 3 or (b <= 0 and b >= -4 + a)) }" },
+       { 0, "{ [i, j, i', j'] : i <= 2 and j <= 2 and "
                        "j' >= -1 + 2i + j - 2i' and i' <= -1 + i and "
                        "j >= 1 and j' <= i + j - i' and i >= 1; "
-               "[1, 1, 1, 1] }", 0) < 0)
-               return -1;
-       if (test_coalesce_set(ctx, "{ [i,j] : exists a,b : i = 2a and j = 3b; "
-                                    "[i,j] : exists a : j = 3a }", 1) < 0)
-               return -1;
-       if (test_coalesce_set(ctx,
-               "{ [a, b, c] : (c <= 7 - b and b <= 1 and b >= 0 and "
+               "[1, 1, 1, 1] }" },
+       { 1, "{ [i,j] : exists a,b : i = 2a and j = 3b; "
+                "[i,j] : exists a : j = 3a }" },
+       { 1, "{ [a, b, c] : (c <= 7 - b and b <= 1 and b >= 0 and "
                        "c >= 3 + b and b <= 3 + 8a and b >= -26 + 8a and "
                        "a >= 3) or "
                    "(b <= 1 and c <= 7 and b >= 0 and c >= 4 + b and "
-                       "b <= 3 + 8a and b >= -26 + 8a and a >= 3) }", 1) < 0)
-               return -1;
-       if (test_coalesce_set(ctx,
-               "{ [a, 0, c] : c >= 1 and c <= 29 and c >= -1 + 8a and "
+                       "b <= 3 + 8a and b >= -26 + 8a and a >= 3) }" },
+       { 1, "{ [a, 0, c] : c >= 1 and c <= 29 and c >= -1 + 8a and "
                                "c <= 6 + 8a and a >= 3; "
-                   "[a, -1, c] : c >= 1 and c <= 30 and c >= 8a and "
-                               "c <= 7 + 8a and a >= 3 and a <= 4 }", 1) < 0)
+               "[a, -1, c] : c >= 1 and c <= 30 and c >= 8a and "
+                               "c <= 7 + 8a and a >= 3 and a <= 4 }" },
+       { 1, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; "
+               "[x,0] : 3 <= x <= 4 }" },
+       { 1, "{ [x,y] : 0 <= x <= 3 and y >= 0 and x + 3y <= 6; "
+               "[x,0] : 4 <= x <= 5 }" },
+       { 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; "
+               "[x,0] : 3 <= x <= 5 }" },
+       { 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + y <= 4; "
+               "[x,0] : 3 <= x <= 4 }" },
+       { 1 , "{ [i0, i1] : i0 <= 122 and i0 >= 1 and 128i1 >= -249 + i0 and "
+                       "i1 <= 0; "
+               "[i0, 0] : i0 >= 123 and i0 <= 124 }" },
+};
+
+/* Test the functionality of isl_set_coalesce.
+ * That is, check that the output is always equal to the input
+ * and in some cases that the result consists of a single disjunct.
+ */
+static int test_coalesce(struct isl_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coalesce_tests); ++i) {
+               const char *str = coalesce_tests[i].str;
+               int check_one = coalesce_tests[i].single_disjunct;
+               if (test_coalesce_set(ctx, str, check_one) < 0)
+                       return -1;
+       }
+
+       if (test_coalesce_unbounded_wrapping(ctx) < 0)
                return -1;
+
        return 0;
 }
 
@@ -1451,8 +1352,9 @@ void test_lex(struct isl_ctx *ctx)
        isl_map_free(map);
 }
 
-void test_lexmin(struct isl_ctx *ctx)
+static int test_lexmin(struct isl_ctx *ctx)
 {
+       int equal;
        const char *str;
        isl_basic_map *bmap;
        isl_map *map, *map2;
@@ -1548,6 +1450,23 @@ void test_lexmin(struct isl_ctx *ctx)
        assert(isl_map_is_equal(map, map2));
        isl_map_free(map);
        isl_map_free(map2);
+
+       str = "[i] -> { [i', j] : j = i - 8i' and i' >= 0 and i' <= 7 and "
+                               " 8i' <= i and 8i' >= -7 + i }";
+       set = isl_set_read_from_str(ctx, str);
+       pma = isl_set_lexmin_pw_multi_aff(isl_set_copy(set));
+       set2 = isl_set_from_pw_multi_aff(pma);
+       equal = isl_set_is_equal(set, set2);
+       isl_set_free(set);
+       isl_set_free(set2);
+       if (equal < 0)
+               return -1;
+       if (!equal)
+               isl_die(ctx, isl_error_unknown,
+                       "unexpected difference between set and "
+                       "piecewise affine expression", return -1);
+
+       return 0;
 }
 
 struct must_may {
@@ -3443,7 +3362,7 @@ struct {
          "{ A[i,j] : j = [(i)/6] and exists a : i = 3 a }" },
 };
 
-int test_preimage(isl_ctx *ctx)
+static int test_preimage_basic_set(isl_ctx *ctx)
 {
        int i;
        isl_basic_set *bset1, *bset2;
@@ -3469,6 +3388,76 @@ int test_preimage(isl_ctx *ctx)
 }
 
 struct {
+       const char *map;
+       const char *ma;
+       const char *res;
+} preimage_domain_tests[] = {
+       { "{ B[i,j] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }",
+         "{ A[j,i] -> B[i,j] }",
+         "{ A[j,i] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }" },
+       { "{ B[i] -> C[i]; D[i] -> E[i] }",
+         "{ A[i] -> B[i + 1] }",
+         "{ A[i] -> C[i + 1] }" },
+       { "{ B[i] -> C[i]; B[i] -> E[i] }",
+         "{ A[i] -> B[i + 1] }",
+         "{ A[i] -> C[i + 1]; A[i] -> E[i + 1] }" },
+       { "{ B[i] -> C[([i/2])] }",
+         "{ A[i] -> B[2i] }",
+         "{ A[i] -> C[i] }" },
+       { "{ B[i,j] -> C[([i/2]), ([(i+j)/3])] }",
+         "{ A[i] -> B[([i/5]), ([i/7])] }",
+         "{ A[i] -> C[([([i/5])/2]), ([(([i/5])+([i/7]))/3])] }" },
+       { "[N] -> { B[i] -> C[([N/2]), i, ([N/3])] }",
+         "[N] -> { A[] -> B[([N/5])] }",
+         "[N] -> { A[] -> C[([N/2]), ([N/5]), ([N/3])] }" },
+       { "{ B[i] -> C[i] : exists a : i = 5 a }",
+         "{ A[i] -> B[2i] }",
+         "{ A[i] -> C[2i] : exists a : 2i = 5 a }" },
+       { "{ B[i] -> C[i] : exists a : i = 2 a; "
+           "B[i] -> D[i] : exists a : i = 2 a + 1 }",
+         "{ A[i] -> B[2i] }",
+         "{ A[i] -> C[2i] }" },
+};
+
+static int test_preimage_union_map(isl_ctx *ctx)
+{
+       int i;
+       isl_union_map *umap1, *umap2;
+       isl_multi_aff *ma;
+       int equal;
+
+       for (i = 0; i < ARRAY_SIZE(preimage_domain_tests); ++i) {
+               umap1 = isl_union_map_read_from_str(ctx,
+                                               preimage_domain_tests[i].map);
+               ma = isl_multi_aff_read_from_str(ctx,
+                                               preimage_domain_tests[i].ma);
+               umap2 = isl_union_map_read_from_str(ctx,
+                                               preimage_domain_tests[i].res);
+               umap1 = isl_union_map_preimage_domain_multi_aff(umap1, ma);
+               equal = isl_union_map_is_equal(umap1, umap2);
+               isl_union_map_free(umap1);
+               isl_union_map_free(umap2);
+               if (equal < 0)
+                       return -1;
+               if (!equal)
+                       isl_die(ctx, isl_error_unknown, "bad preimage",
+                               return -1);
+       }
+
+       return 0;
+}
+
+static int test_preimage(isl_ctx *ctx)
+{
+       if (test_preimage_basic_set(ctx) < 0)
+               return -1;
+       if (test_preimage_union_map(ctx) < 0)
+               return -1;
+
+       return 0;
+}
+
+struct {
        const char *ma1;
        const char *ma;
        const char *res;
@@ -3847,6 +3836,76 @@ static int test_ast_gen4(isl_ctx *ctx)
        return 0;
 }
 
+/* This function is called for each leaf in the AST generated
+ * from test_ast_gen5.
+ *
+ * We finalize the AST generation by extending the outer schedule
+ * with a zero-dimensional schedule.  If this results in any for loops,
+ * then this means that we did not pass along enough information
+ * about the outer schedule to the inner AST generation.
+ */
+static __isl_give isl_ast_node *create_leaf(__isl_take isl_ast_build *build,
+       void *user)
+{
+       isl_union_map *schedule, *extra;
+       isl_ast_node *tree;
+
+       schedule = isl_ast_build_get_schedule(build);
+       extra = isl_union_map_copy(schedule);
+       extra = isl_union_map_from_domain(isl_union_map_domain(extra));
+       schedule = isl_union_map_range_product(schedule, extra);
+       tree = isl_ast_build_ast_from_schedule(build, schedule);
+       isl_ast_build_free(build);
+
+       if (!tree)
+               return NULL;
+
+       if (isl_ast_node_get_type(tree) == isl_ast_node_for)
+               isl_die(isl_ast_node_get_ctx(tree), isl_error_unknown,
+                       "code should not contain any for loop",
+                       return isl_ast_node_free(tree));
+
+       return tree;
+}
+
+/* Check that we do not lose any information when going back and
+ * forth between internal and external schedule.
+ *
+ * In particular, we create an AST where we unroll the only
+ * non-constant dimension in the schedule.  We therefore do
+ * not expect any for loops in the AST.  However, older versions
+ * of isl would not pass along enough information about the outer
+ * schedule when performing an inner code generation from a create_leaf
+ * callback, resulting in the inner code generation producing a for loop.
+ */
+static int test_ast_gen5(isl_ctx *ctx)
+{
+       const char *str;
+       isl_set *set;
+       isl_union_map *schedule, *options;
+       isl_ast_build *build;
+       isl_ast_node *tree;
+
+       str = "{ A[] -> [1, 1, 2]; B[i] -> [1, i, 0] : i >= 1 and i <= 2 }";
+       schedule = isl_union_map_read_from_str(ctx, str);
+
+       str = "{ [a, b, c] -> unroll[1] : exists (e0 = [(a)/4]: "
+                               "4e0 >= -1 + a - b and 4e0 <= -2 + a + b) }";
+       options = isl_union_map_read_from_str(ctx, str);
+
+       set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+       build = isl_ast_build_from_context(set);
+       build = isl_ast_build_set_options(build, options);
+        build = isl_ast_build_set_create_leaf(build, &create_leaf, NULL);
+       tree = isl_ast_build_ast_from_schedule(build, schedule);
+       isl_ast_build_free(build);
+       isl_ast_node_free(tree);
+       if (!tree)
+               return -1;
+
+       return 0;
+}
+
 static int test_ast_gen(isl_ctx *ctx)
 {
        if (test_ast_gen1(ctx) < 0)
@@ -3857,6 +3916,8 @@ static int test_ast_gen(isl_ctx *ctx)
                return -1;
        if (test_ast_gen4(ctx) < 0)
                return -1;
+       if (test_ast_gen5(ctx) < 0)
+               return -1;
        return 0;
 }
 
@@ -3946,10 +4007,34 @@ static int test_partial_lexmin(isl_ctx *ctx)
        return 0;
 }
 
+/* Check that the variable compression performed on the existentially
+ * quantified variables inside isl_basic_set_compute_divs is not confused
+ * by the implicit equalities among the parameters.
+ */
+static int test_compute_divs(isl_ctx *ctx)
+{
+       const char *str;
+       isl_basic_set *bset;
+       isl_set *set;
+
+       str = "[a, b, c, d, e] -> { [] : exists (e0: 2d = b and a <= 124 and "
+               "b <= 2046 and b >= 0 and b <= 60 + 64a and 2e >= b + 2c and "
+               "2e >= b and 2e <= 1 + b and 2e <= 1 + b + 2c and "
+               "32768e0 >= -124 + a and 2097152e0 <= 60 + 64a - b) }";
+       bset = isl_basic_set_read_from_str(ctx, str);
+       set = isl_basic_set_compute_divs(bset);
+       isl_set_free(set);
+       if (!set)
+               return -1;
+
+       return 0;
+}
+
 struct {
        const char *name;
        int (*fn)(isl_ctx *ctx);
 } tests [] = {
+       { "compute divs", &test_compute_divs },
        { "partial lexmin", &test_partial_lexmin },
        { "simplify", &test_simplify },
        { "curry", &test_curry },
@@ -3984,6 +4069,7 @@ struct {
        { "factorize", &test_factorize },
        { "subset", &test_subset },
        { "subtract", &test_subtract },
+       { "lexmin", &test_lexmin },
 };
 
 int main()
@@ -4016,7 +4102,6 @@ int main()
        test_convex_hull(ctx);
        test_gist(ctx);
        test_closure(ctx);
-       test_lexmin(ctx);
        isl_ctx_free(ctx);
        return 0;
 error:
index 1528ebd..0edaf55 100644 (file)
@@ -12,6 +12,7 @@
 #include <isl_map_private.h>
 #include <isl/ctx.h>
 #include <isl/hash.h>
+#include <isl/aff.h>
 #include <isl/map.h>
 #include <isl/set.h>
 #include <isl_space_private.h>
@@ -41,6 +42,7 @@ static __isl_give isl_union_map *isl_union_map_alloc(__isl_take isl_space *dim,
 {
        isl_union_map *umap;
 
+       dim = isl_space_params(dim);
        if (!dim)
                return NULL;
 
@@ -2531,3 +2533,84 @@ error:
        isl_union_set_free(res);
        return NULL;
 }
+
+/* Internal data structure for isl_union_map_preimage_domain_multi_aff.
+ *
+ * "ma" is the function under which the preimage should be taken.
+ * "space" is the space of "ma".
+ * "res" collects the results.
+ */
+struct isl_union_map_preimage_domain_data {
+       isl_space *space;
+       isl_multi_aff *ma;
+       isl_union_map *res;
+};
+
+/* Compute the preimage of the domain of *entry under the function
+ * represented by data->ma, provided the domain space of *entry
+ * match the target space of data->ma, and add the result to data->res.
+ */
+static int preimage_domain_entry(void **entry, void *user)
+{
+       int m;
+       isl_map *map = *entry;
+       struct isl_union_map_preimage_domain_data *data = user;
+       int empty;
+
+       m = isl_space_tuple_match(map->dim, isl_dim_in,
+                                       data->space, isl_dim_out);
+       if (m < 0)
+               return -1;
+       if (!m)
+               return 0;
+
+       map = isl_map_copy(map);
+       map = isl_map_preimage_domain_multi_aff(map,
+                                               isl_multi_aff_copy(data->ma));
+
+       empty = isl_map_is_empty(map);
+       if (empty < 0 || empty) {
+               isl_map_free(map);
+               return empty < 0 ? -1 : 0;
+       }
+
+       data->res = isl_union_map_add_map(data->res, map);
+
+       return 0;
+}
+
+/* Compute the preimage of the domain of "umap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with domain space equal to the target space of "ma",
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff(
+       __isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma)
+{
+       isl_ctx *ctx;
+       isl_space *space;
+       struct isl_union_map_preimage_domain_data data;
+
+       if (!umap || !ma)
+               goto error;
+
+       ctx = isl_union_map_get_ctx(umap);
+       space = isl_union_map_get_space(umap);
+       data.space = isl_multi_aff_get_space(ma);
+       data.ma = ma;
+       data.res = isl_union_map_alloc(space, umap->table.n);
+       if (isl_hash_table_foreach(ctx, &umap->table, &preimage_domain_entry,
+                                       &data) < 0)
+               data.res = isl_union_map_free(data.res);
+
+       isl_space_free(data.space);
+       isl_union_map_free(umap);
+       isl_multi_aff_free(ma);
+       return data.res;
+error:
+       isl_union_map_free(umap);
+       isl_multi_aff_free(ma);
+       return NULL;
+}
index f6f46e2..cd55f4e 100644 (file)
@@ -465,6 +465,15 @@ error:
        return NULL;
 }
 
+#ifndef NO_SUB
+/* Subtract "u2" from "u1" and return the result.
+ */
+__isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2)
+{
+       return match_bin_op(u1, u2, &FN(PART,sub));
+}
+#endif
+
 S(UNION,any_set_data) {
        isl_set *set;
        UNION *res;
index 60ac548..308e64f 100644 (file)
@@ -1,6 +1,6 @@
-# ===========================================================================
-#    http://www.nongnu.org/autoconf-archive/ax_create_pkgconfig_info.html
-# ===========================================================================
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_create_pkgconfig_info.html
+# ============================================================================
 #
 # SYNOPSIS
 #
@@ -14,8 +14,8 @@
 #     $2 = (empty)
 #     $3 = $PACKAGE_LIBS $LIBS (as set at that point in configure.ac)
 #     $4 = $PACKAGE_SUMMARY (or $1 Library)
-#     $5 = $CPPFLAGS $PACKAGE_CFLAGS (as set at the point in configure.ac)
-#     $6 = $LDFLAGS $PACKAGE_LDFLAGS (as set at the point in configure.ac)
+#     $5 = $PACKAGE_CFLAGS (as set at the point in configure.ac)
+#     $6 = $PACKAGE_LDFLAGS (as set at the point in configure.ac)
 #
 #     PACKAGE_NAME defaults to $PACKAGE if not set.
 #     PACKAGE_LIBS defaults to -l$PACKAGE_NAME if not set.
@@ -34,7 +34,7 @@
 #
 #   This program is free software; you can redistribute it and/or modify it
 #   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation; either version 2 of the License, or (at your
+#   Free Software Foundation; either version 3 of the License, or (at your
 #   option) any later version.
 #
 #   This program is distributed in the hope that it will be useful, but
@@ -58,6 +58,8 @@
 #   modified version of the Autoconf Macro, you may extend this special
 #   exception to the GPL to apply to your modified version as well.
 
+#serial 12
+
 AC_DEFUN([AX_CREATE_PKGCONFIG_INFO],[dnl
 AS_VAR_PUSHDEF([PKGCONFIG_suffix],[ax_create_pkgconfig_suffix])dnl
 AS_VAR_PUSHDEF([PKGCONFIG_libdir],[ax_create_pkgconfig_libdir])dnl
@@ -145,13 +147,13 @@ PKGCONFIG_libs=`eval echo "$PKGCONFIG_libs"`
 AC_MSG_RESULT($PKGCONFIG_libs)
 
 AC_MSG_CHECKING(our pkgconfig cppflags)
-PKGCONFIG_cppflags="ifelse($5,,$CPPFLAGS $PACKAGE_CFLAGS,$5)"
+PKGCONFIG_cppflags="ifelse($5,,$PACKAGE_CFLAGS,$5)"
 PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"`
 PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"`
 AC_MSG_RESULT($PKGCONFIG_cppflags)
 
 AC_MSG_CHECKING(our pkgconfig ldflags)
-PKGCONFIG_ldflags="ifelse($6,,$LDFLAGS $PACKAGE_LDFLAGS,$5)"
+PKGCONFIG_ldflags="ifelse($6,,$PACKAGE_LDFLAGS,$5)"
 PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"`
 PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"`
 AC_MSG_RESULT($PKGCONFIG_ldflags)
index 02678f4..387b3e5 100644 (file)
@@ -5,5 +5,5 @@
   for (int c0 = floord(n, 3); c0 <= 2 * floord(n, 3); c0 += 1)
     for (int c1 = 0; c1 < n; c1 += 1)
       for (int c3 = max(1, (n % 3) - n + 3 * c0); c3 <= min(n, (n % 3) - n + 3 * c0 + 2); c3 += 1)
-        S2(c1 + 1, c3, 0, (n + 3) / 3 - 1, c0 - (n + 3) / 3 + 1);
+        S2(c1 + 1, c3, 0, n / 3, c0 - n / 3);
 }
index 26fba66..4d43f4c 100644 (file)
@@ -1,5 +1,3 @@
 for (int c0 = 1; c0 <= 5; c0 += 1)
-  if (c0 <= 2 || (t1 + c0 >= 8 && c0 >= 2 && c0 <= 3) || (b == 1 && t1 + c0 >= 10 && c0 >= 3) || (b == 1 && t1 <= 6 && t1 + c0 <= 9))
-    for (int c1 = max(t1, t1 - 64 * b + 64); c1 <= min(70, -((c0 + 1) % 2) - c0 + 73); c1 += 64)
-      if ((c0 <= 2 && c0 >= 1 && c0 + c1 <= 71 && c1 >= 7) || (c1 == t1 + 64 && c0 <= 3 && c0 >= 2 && t1 + c0 >= 8) || (c1 == t1 && b == 1 && c0 >= 3 && t1 + c0 >= 10) || (c1 == t1 && b == 1 && t1 <= 6 && t1 + c0 <= 9))
-        A(c0, 64 * b + c1 - 8);
+  for (int c1 = max(t1, t1 - 64 * b + 64); c1 <= min(70, -((c0 + 1) % 2) - c0 + 73); c1 += 64)
+    A(c0, 64 * b + c1 - 8);
index 06b32e5..743b0c9 100644 (file)
@@ -1,3 +1,3 @@
 if (m >= 8 * floord(m + 1, 8))
-  for (int c0 = 4 * floord(floord(m + 1, 8), 4); c0 <= n; c0 += 1)
+  for (int c0 = 4 * floord(m + 1, 32); c0 <= n; c0 += 1)
     s0(c0);
index 051393f..6c348e7 100644 (file)
@@ -3,6 +3,6 @@ for (int c0 = 0; c0 <= 3; c0 += 1)
     for (int c2 = c0; c2 <= min(min(3, 2 * c0 - c1 + 1), 3 * c1 + 2); c2 += 1)
       for (int c3 = max(max(max(c2 - (c2 + 2) / 3, c2 + floord(3 * c1 - c2 - 1, 6)), c1 - (-c1 + 3) / 3), c0 - (-c2 + 3) / 3); c3 <= min(c0 + c0 / 2 + 1, 3); c3 += 1)
         for (int c5 = max(max(max(max(c1 - (c1 - 2 * c3 + 5) / 5, 0), c3 - (c3 + 3) / 3), 2 * c3 - 4), c2 - (c2 + 3) / 3); c5 <= min(min(c1 + 1, c3), -c2 + 2 * c3 - (c2 + 3) / 3 + 2); c5 += 1)
-          for (int c6 = max(max(max(max(max(333 * c2 + (c2 + 1) / 3, -200 * c1 + 400 * c3 - 199), 1000 * c0 - 500 * c5 - 501), 333 * c1 + c1 / 3), 250 * c3 + 1), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332); c6 <= min(min(min(min(min(min(500 * c0 + 499, 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334), -200 * c1 + 400 * c3 + 400), 500 * c5 + 501), 1000), 1000 * c0 - 500 * c5 + 997); c6 += 1)
+          for (int c6 = max(max(max(max(max(1000 * c0 - 500 * c5 - 501, -200 * c1 + 400 * c3 - 199), 333 * c1 + c1 / 3), 250 * c3 + 1), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332), 333 * c2 + (c2 + 1) / 3); c6 <= min(min(min(min(min(min(-200 * c1 + 400 * c3 + 400, 500 * c0 + 499), 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334), 500 * c5 + 501), 1000), 1000 * c0 - 500 * c5 + 997); c6 += 1)
             for (int c7 = max(max(max(max(c6, 500 * c5 + 2), 1000 * c3 - 2 * c6 + 2), 500 * c1 + (c6 + 1) / 2), 1000 * c0 - c6); c7 <= min(min(min(min(500 * c5 + 501, 2 * c6 + 1), 1000 * c0 - c6 + 999), 500 * c1 + (c6 + 1) / 2 + 499), 1000 * c3 - 2 * c6 + 1001); c7 += 1)
               s0(c0, c1, c2, c3, c2 / 3, c5, c6, c7);
index 789078e..3ccbf81 100644 (file)
@@ -1,10 +1,10 @@
-if ((2 * floord(P2, 2) == P2 && 2 * floord(P1, 2) == P1 && P2 <= 3 && P2 >= 0 && P1 <= 3 && P1 >= 0) || (2 * floord(P2, 2) == P2 && 2 * floord(P1 - 1, 2) + 1 == P1 && P2 <= 3 && P2 >= 0 && P1 <= 3 && P1 >= 0) || (2 * floord(P2 - 1, 2) + 1 == P2 && 2 * floord(P1, 2) == P1 && P2 <= 3 && P2 >= 0 && P1 <= 3 && P1 >= 0) || (2 * floord(P2 - 1, 2) + 1 == P2 && 2 * floord(P1 - 1, 2) + 1 == P1 && P2 <= 3 && P2 >= 0 && P1 <= 3 && P1 >= 0))
+if (P2 <= 3 && P2 >= 0 && P1 <= 3 && P1 >= 0)
   for (int c0 = P1 - 1; c0 <= 3; c0 += 1)
-    if ((2 * floord(c0, 2) == c0 && P2 % 2 == 0 && 2 * floord(P1 - 1, 2) + 1 == P1) || (2 * floord(c0, 2) == c0 && 2 * floord(P2 - 1, 2) + 1 == P2 && 2 * floord(P1 - 1, 2) + 1 == P1) || (2 * floord(c0 - 1, 2) + 1 == c0 && P2 % 2 == 0 && P1 % 2 == 0) || (2 * floord(c0 - 1, 2) + 1 == c0 && 2 * floord(P2 - 1, 2) + 1 == P2 && P1 % 2 == 0))
+    if (P1 + 2 * floord(-P1 + c0 - 1, 2) + 1 == c0)
       for (int c2 = 0; c2 <= -((P1 + 4) / 4) + 8; c2 += 1)
-        if ((-2 * ((-P2 + 4) / 4) + 2 * (P2 / 4) + 2 == P2 && 2 * floord(P2 - 1, 2) + 2 == P2 && P2 <= 6 && 18 * floord(9 * P1 + 17 * c0 + 14 * c2 + 3, 18) + 1 >= 9 * P1 + 17 * c0 + 14 * c2) || (2 * floord(P2 - 1, 2) + 1 == P2 && 18 * floord(9 * P1 + 17 * c0 + 14 * c2 + 3, 18) + 1 >= 9 * P1 + 17 * c0 + 14 * c2 && P2 + 1 >= 0 && (-P2 + 4) % 4 >= 1))
+        if ((5 * c0 + 2 * c2 + 5) % 9 <= 2)
           for (int c3 = 0; c3 <= -((P2 + 4) / 4) + 8; c3 += 1)
-            if ((5 * P2 + 2 * c3) % 9 <= 3 && 9 * ((4 * P2 + 3) / 9 / 2) + 7 >= 2 * P2 && 2 * P2 + 1 >= 9 * ((4 * P2 + 3) / 9 / 2))
+            if ((5 * P2 + 2 * c3) % 9 <= 3)
               if (c0 + 1 == P1 && (5 * P1 + 2 * c2) % 9 <= 2 && P1 >= 1) {
                 s0(P1 - 1, P2, c2, c3, ((5 * P1 + 2 * c2) % 9) + 1, (-4 * P2 + 2 * c3 + 9) % 9);
               } else if (c2 % 4 == 0 && c0 == 3 && P1 == 0)
index 3ea48af..2bddda2 100644 (file)
@@ -10,6 +10,6 @@
   }
   for (int c1 = 0; c1 < n; c1 += 8)
     for (int c2 = 0; c2 < n % 8; c2 += 1)
-      for (int c3 = 0; c3 <= min(7, n - c1 - 1); c3 += 1)
+      for (int c3 = 0; c3 <= min(n - c1 - 1, 7); c3 += 1)
         A(-((n - 1) % 8) + n + c2 - 1, c1 + c3);
 }
index c09a7ef..6412784 100644 (file)
@@ -1,2 +1,2 @@
 if (2 * (63 * t1 % 64) + t1 <= 134)
-  S(2 * (63 * t1 % 64) + t1);
+  S(-(2 * ((t1 - 1) % 64)) + t1 + 126);
diff --git a/test_inputs/codegen/stride6.c b/test_inputs/codegen/stride6.c
new file mode 100644 (file)
index 0000000..a7f6082
--- /dev/null
@@ -0,0 +1,4 @@
+for (int c1 = -1024; c1 <= 0; c1 += 32)
+  for (int c2 = max(-((niter - c1) % 32) + niter - c1 - 32, -((niter - 1) % 32) + niter - 1); c2 <= min(niter + 1022, niter - c1 - 1); c2 += 32)
+    for (int c5 = max(max(niter - c1 - c2 - 32, -c1 - 1023), 0); c5 <= min(min(-c1, niter - c1 - c2 - 1), 31); c5 += 1)
+      S_4(niter - 1, -c1 - c5);
diff --git a/test_inputs/codegen/stride6.in b/test_inputs/codegen/stride6.in
new file mode 100644 (file)
index 0000000..86ca54a
--- /dev/null
@@ -0,0 +1,3 @@
+[niter] -> { S_4[-1 + niter, i] -> [o0, o1, o2, o3, o4, o5, o6, o7, 4] : exists (e0 = [(o0)/32], e1 = [(o1)/32], e2 = [(o2)/32], e3 = [(o3)/32], e4 = [(-31i + o5)/32], e5 = [(-i - o4 + o6)/32], e6 = [(-o4 + o7)/32], e7 = [(-1 + niter - o4)/32]: 32e0 = o0 and 32e1 = o1 and 32e2 = o2 and 32e3 = o3 and 32e4 = -31i + o5 and 32e5 = -i - o4 + o6 and 32e6 = -o4 + o7 and 32e7 = -1 + niter - o4 and o0 <= -1 + niter and o0 >= -32 + niter and o1 <= -i and o1 >= -31 - i and o2 <= -1 + niter + i and o2 >= -32 + niter + i and o3 <= 1023 + niter and o3 >= 992 + niter and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and o7 >= 0 and o7 <= 31 and i <= 1023 and i >= 0 and niter >= 1) }
+[niter] -> {  : niter <= 8192 and niter >= 1 }
+[niter] -> {  }
index 9bf1884..8bed4a2 100644 (file)
@@ -3,8 +3,8 @@
   if (t1 % 3 == 0 && t2 >= 1 && t2 <= 2)
     write_shared_A(3, (-t1 + 12) / 3, t2 + 32);
   {
-    int c3 = t2 <= 1 || (t2 >= 2 && ((3 * t1 + t2 + 3) % 4) + 1 >= t2) ? t2 + 32 : t2;
-    if (c3 == t2 + 32 || (c3 == t2 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) >= 5 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) <= 8))
+    int c3 = ((t1 + 3) % 4) + 1 >= t2 && t2 >= 2 && t2 <= 33 ? t2 + 32 : ((t2 + 30) % 32) + 2;
+    if (c3 == t2 + 32 || (c3 == t2 && ((-t1 + 8) % 4) + t2 >= ((t2 + 1) % 2) + 5))
       write_shared_A(3, ((t1 + 3) % 4) + 5, c3);
   }
   if (t2 >= t1 + 1 && t2 <= 4 && t1 >= 1)
@@ -13,8 +13,8 @@
   if (t1 % 3 == 0 && t2 >= 1 && t2 <= 2)
     write_shared_A(4, (-t1 + 12) / 3, t2 + 32);
   {
-    int c3 = t2 <= 1 || (t2 >= 2 && ((3 * t1 + t2 + 3) % 4) + 1 >= t2) ? t2 + 32 : t2;
-    if (c3 == t2 + 32 || (c3 == t2 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) >= 5 && t1 + 4 * floord(-((t2 + 1) % 2) - t1 + t2 + 3, 4) <= 8))
+    int c3 = ((t1 + 3) % 4) + 1 >= t2 && t2 >= 2 && t2 <= 33 ? t2 + 32 : ((t2 + 30) % 32) + 2;
+    if (c3 == t2 + 32 || (c3 == t2 && ((-t1 + 8) % 4) + t2 >= ((t2 + 1) % 2) + 5))
       write_shared_A(4, ((t1 + 3) % 4) + 5, c3);
   }
   if (t2 >= t1 + 1 && t2 <= 4 && t1 >= 1)