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 \
isl_scan.h \
isl_schedule.c \
isl_schedule_private.h \
+ isl_set_list.c \
isl_sort.c \
isl_sort.h \
isl_space.c \
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;
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);
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) {
isl_int_clear(t);
+ isl_printer_free(p);
+
if (!ok)
vpb->error = 1;
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 \
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
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"
__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,
__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);
__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,
__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">.
__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(
__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
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
__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.
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>
__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);
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
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.
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
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
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
#include <isl/list.h>
#include <isl/multi.h>
#include <isl/union_set_type.h>
+#include <isl/vec.h>
#if defined(__cplusplus)
extern "C" {
__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);
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(
__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,
__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);
#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;
struct isl_multi_pw_aff;
typedef struct isl_multi_pw_aff isl_multi_pw_aff;
+#if defined(__cplusplus)
+}
+#endif
+
#endif
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);
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);
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);
#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)
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);
* 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)))
#define ISL_ID_H
#include <isl/ctx.h>
+#include <isl/list.h>
#include <isl/printer.h>
#if defined(__cplusplus)
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,
#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)
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); \
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)
}
__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,
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);
__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);
#define ISL_MAP_TYPE_H
#include <isl/ctx.h>
+#include <isl/list.h>
#if defined(__cplusplus)
extern "C" {
#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
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);
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);
#ifndef ISL_MULTI_H
#define ISL_MULTI_H
+#include <isl/space.h>
#include <isl/list.h>
#if defined(__cplusplus)
#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)
}
__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(
__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(
/*
* 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)
{
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);
__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,
&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)
{
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)
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"
*
* 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,
* 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);
}
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);
#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;
+}
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;
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;
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(
/*
* 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>
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,
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)
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);
}
}
+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;
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;
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:
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:
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;
}
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;
}
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;
}
}
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;
}
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;
}
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,
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))
++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);
#include <isl_ast_private.h>
-#include <isl_list_private.h>
#undef BASE
#define BASE ast_expr
/* 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)
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)
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.
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)
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)
#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".
*
__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);
#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.
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",
* 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;
}
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);
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);
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));
}
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);
}
/* 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.
*/
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;
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));
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,
* 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);
graft = refine_generic_split(graft, list, domain, build);
graft = add_stride_guard(graft, build);
- isl_constraint_list_free(list);
return graft;
}
* 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.
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);
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
*
* 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
__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);
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
__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.
*
* "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]
* 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>
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);
}
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.
*/
__isl_keep isl_ast_build *build)
{
int univ;
- isl_ast_node *node;
- isl_ast_expr *expr;
if (!graft)
goto error;
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);
/* 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)
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);
/* 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,
__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(
/*
* 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)
{
* 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;
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;
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)
{
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(
/*
* 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
*
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
* | |
* | |
* |___|
+ *
+ * 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
* 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.
* ____ _____
* / || / |
* / || / |
* \ || \ |
* \___|| \____|
*/
-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;
/* 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;
* => 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
* => 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
* 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
* 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.
*
/* 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))
#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;
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);
#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)
{
opt_allocated = 1;
}
- ctx = isl_calloc_type(NULL, struct isl_ctx);
+ ctx = __isl_calloc_type(struct isl_ctx);
if (!ctx)
goto error;
/*
* 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>
/* 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
*
* 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;
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);
#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,
#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.
__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;
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, '='))
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);
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);
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.
*/
+++ /dev/null
-/*
- * 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>
+++ /dev/null
-#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
/*
* 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
*
* 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
#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)
{
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;
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);
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)
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);
}
/*
* 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
*
#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>
#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)
{
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]);
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;
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);
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;
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)
{
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)
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
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.
* 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)
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);
}
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:
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);
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;
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,
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)
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;
}
*
* 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
* 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;
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".
{
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);
+}
#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>
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.
*
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,
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.
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]))
*/
#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)
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)
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;
{
int r;
+ if (n == 0)
+ return mat;
+
mat = isl_mat_cow(mat);
if (!mat)
return NULL;
*
* 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;
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));
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
*
* 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)
* 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
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;
+}
+#include <isl/space.h>
+
#define xCAT(A,B) A ## B
#define CAT(A,B) xCAT(A,B)
#undef EL
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")
"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
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)
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)
int schedule_fuse;
int tile_scale_tile_loops;
+ int tile_shift_point_loops;
char *ast_iterator_type;
int ast_build_separation_bounds;
int ast_build_scale_strides;
int ast_build_allow_else;
+ int ast_build_allow_or;
};
#endif
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)
/*
* 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>
#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>
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,
* 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,
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;
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.
free(active);
+ list = sort_band_list(list, parent);
+
return list;
}
--- /dev/null
+#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>
*/
#include <stdlib.h>
+#include <string.h>
#include <isl_space_private.h>
#include <isl_id_private.h>
#include <isl_reordering.h>
+#ifndef ISL_SPACE_PRIVATE
+#define ISL_SPACE_PRIVATE
+
#include <isl/space.h>
#include <isl/hash.h>
#include <isl/id.h>
__isl_give isl_space *isl_space_extend_domain_with_range(
__isl_take isl_space *domain, __isl_take isl_space *model);
+
+#endif
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;
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)
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)
{
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",
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);
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,
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(
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);
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".
*
* 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;
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);
"[n] -> { [i] : i <= n }") < 0)
return -1;
+ if (test_parse_map_equal(ctx, "{ [*] }", "{ [a] }") < 0)
+ return -1;
+
return 0;
}
{
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");
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;
}
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 "
"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 "
"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 "
"(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;
}
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;
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 {
"{ 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;
}
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;
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)
return -1;
if (test_ast_gen4(ctx) < 0)
return -1;
+ if (test_ast_gen5(ctx) < 0)
+ return -1;
return 0;
}
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 },
{ "factorize", &test_factorize },
{ "subset", &test_subset },
{ "subtract", &test_subtract },
+ { "lexmin", &test_lexmin },
};
int main()
test_convex_hull(ctx);
test_gist(ctx);
test_closure(ctx);
- test_lexmin(ctx);
isl_ctx_free(ctx);
return 0;
error:
#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>
{
isl_union_map *umap;
+ dim = isl_space_params(dim);
if (!dim)
return NULL;
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;
+}
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;
-# ===========================================================================
-# http://www.nongnu.org/autoconf-archive/ax_create_pkgconfig_info.html
-# ===========================================================================
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_create_pkgconfig_info.html
+# ============================================================================
#
# SYNOPSIS
#
# $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.
#
# 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
# 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
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)
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);
}
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);
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);
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);
-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)
}
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);
}
if (2 * (63 * t1 % 64) + t1 <= 134)
- S(2 * (63 * t1 % 64) + t1);
+ S(-(2 * ((t1 - 1) % 64)) + t1 + 126);
--- /dev/null
+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);
--- /dev/null
+[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] -> { }
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)
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)