diff options
author | Tobias Grosser <tobias@grosser.es> | 2015-02-16 19:33:40 +0000 |
---|---|---|
committer | Tobias Grosser <tobias@grosser.es> | 2015-02-16 19:33:40 +0000 |
commit | 1fa7b972c02efa8e80706995f1c6326e68205c47 (patch) | |
tree | f14008a5a312836fae4811487a69b9458e6afbd1 /polly/lib/External/isl | |
parent | 97a59fb464c7330037ce487f8fb6a079c7a52200 (diff) | |
download | bcm5719-llvm-1fa7b972c02efa8e80706995f1c6326e68205c47.tar.gz bcm5719-llvm-1fa7b972c02efa8e80706995f1c6326e68205c47.zip |
Update to isl 99d53692ba
This commit imports the latest isl version into lib/External/isl. The changes
relavant for Polly are:
1) Schedule trees [1] have been introduced as a more structured way to
describe schedules. Polly does not yet use them, but we may switch to them
in the near future.
2) Another set of coalescing changes [2] simplifies some data dependences and
removes a couple of code generation artifacts.
We now understand that the following sets can be merged:
{ Stmt_S1[i0, i1] -> Stmt_S2[i0 + i1] :
i0 >= 0 and i1 <= 1023 - i0 and i1 >= 1
Stmt_S1[i0, 0] -> Stmt_S2[i0] : i0 <= 1023 and i0 >= 1}
into:
{ Stmt_S1[i0, i1] -> Stmt_S2[i0 + i1] : i1 <= 1023 - i0 and i1 >= 0 and
i1 >= 1 - i0 and i0 >= 0 }
Changes of this kind reduce unnecessary specialization during code
generation.
- for (int c3 = 0; c3 <= 1023; c3 += 1) {
- if (c3 % 2 == 0) {
- Stmt_for_body3(c1, c3);
- } else
- Stmt_for_body3(c1, c3);
- }
+ for (int c3 = 0; c3 <= 1023; c3 += 1)
+ Stmt_for_body3(c1, c3);
[1] http://impact.gforge.inria.fr/impact2014/papers/impact2014-verdoolaege.pdf
[2] http://impact.gforge.inria.fr/impact2015/papers/impact2015-verdoolaege.pdf
llvm-svn: 229423
Diffstat (limited to 'polly/lib/External/isl')
94 files changed, 14791 insertions, 2777 deletions
diff --git a/polly/lib/External/isl/Makefile.am b/polly/lib/External/isl/Makefile.am index f975d6a2499..ca68b4caa5b 100644 --- a/polly/lib/External/isl/Makefile.am +++ b/polly/lib/External/isl/Makefile.am @@ -107,6 +107,7 @@ libisl_la_SOURCES = \ isl_lp.c \ isl_lp_private.h \ isl_map.c \ + isl_map_list.c \ isl_map_simplify.c \ isl_map_subtract.c \ isl_map_private.h \ @@ -137,6 +138,13 @@ libisl_la_SOURCES = \ isl_scan.c \ isl_scan.h \ isl_schedule.c \ + isl_schedule_band.c \ + isl_schedule_band.h \ + isl_schedule_node.c \ + isl_schedule_node_private.h \ + isl_schedule_read.c \ + isl_schedule_tree.c \ + isl_schedule_tree.h \ isl_schedule_private.h \ isl_scheduler.c \ isl_set_list.c \ @@ -162,7 +170,8 @@ libisl_la_SOURCES = \ isl_vec.c \ isl_version.c \ isl_vertices_private.h \ - isl_vertices.c + isl_vertices.c \ + isl_yaml.h libisl_la_LIBADD = @MP_LIBS@ libisl_la_LDFLAGS = -version-info @versioninfo@ \ @MP_LDFLAGS@ @@ -246,6 +255,8 @@ pkginclude_HEADERS = \ include/isl/polynomial_type.h \ include/isl/printer.h \ include/isl/schedule.h \ + include/isl/schedule_node.h \ + include/isl/schedule_type.h \ include/isl/set.h \ include/isl/set_type.h \ include/isl/space.h \ @@ -282,8 +293,15 @@ EXTRA_DIST = \ isl_list_templ.c \ isl_list_templ.h \ isl_map_lexopt_templ.c \ + isl_multi_macro.h \ isl_multi_templ.c \ isl_multi_templ.h \ + isl_multi_apply_templ.c \ + isl_multi_apply_set.c \ + isl_multi_apply_union_set.c \ + isl_multi_floor.c \ + isl_multi_gist.c \ + isl_multi_intersect.c \ print_templ.c \ isl_power_templ.c \ isl_pw_templ.c \ diff --git a/polly/lib/External/isl/bound.c b/polly/lib/External/isl/bound.c index 4aaaf13e5ce..73075a1f393 100644 --- a/polly/lib/External/isl/bound.c +++ b/polly/lib/External/isl/bound.c @@ -242,7 +242,7 @@ int main(int argc, char **argv) isl_ctx *ctx; isl_pw_qpolynomial_fold *copy; isl_pw_qpolynomial_fold *pwf; - struct isl_stream *s; + isl_stream *s; struct isl_obj obj; struct bound_options *options; int exact; diff --git a/polly/lib/External/isl/cat.c b/polly/lib/External/isl/cat.c index 63131420592..4f871331f18 100644 --- a/polly/lib/External/isl/cat.c +++ b/polly/lib/External/isl/cat.c @@ -13,15 +13,24 @@ struct isl_arg_choice cat_format[] = { {0} }; +struct isl_arg_choice cat_yaml_style[] = { + { "block", ISL_YAML_STYLE_BLOCK }, + { "flow", ISL_YAML_STYLE_FLOW }, + { 0 } +}; + struct cat_options { struct isl_options *isl; unsigned format; + unsigned yaml_style; }; ISL_ARGS_START(struct cat_options, cat_options_args) ISL_ARG_CHILD(struct cat_options, isl, "isl", &isl_options_args, "isl options") ISL_ARG_CHOICE(struct cat_options, format, 0, "format", \ cat_format, ISL_FORMAT_ISL, "output format") +ISL_ARG_CHOICE(struct cat_options, yaml_style, 0, "yaml-style", \ + cat_yaml_style, ISL_YAML_STYLE_BLOCK, "output YAML style") ISL_ARGS_END ISL_ARG_DEF(cat_options, struct cat_options, cat_options_args) @@ -29,7 +38,7 @@ ISL_ARG_DEF(cat_options, struct cat_options, cat_options_args) int main(int argc, char **argv) { struct isl_ctx *ctx; - struct isl_stream *s; + isl_stream *s; struct isl_obj obj; struct cat_options *options; isl_printer *p; @@ -46,6 +55,7 @@ int main(int argc, char **argv) p = isl_printer_to_file(ctx, stdout); p = isl_printer_set_output_format(p, options->format); + p = isl_printer_set_yaml_style(p, options->yaml_style); p = obj.type->print(p, obj.v); p = isl_printer_end_line(p); isl_printer_free(p); diff --git a/polly/lib/External/isl/closure.c b/polly/lib/External/isl/closure.c index a0faa15820a..c76fb298fda 100644 --- a/polly/lib/External/isl/closure.c +++ b/polly/lib/External/isl/closure.c @@ -7,6 +7,7 @@ int main(int argc, char **argv) struct isl_ctx *ctx; struct isl_map *map; struct isl_options *options; + isl_printer *p; int exact; options = isl_options_new_with_defaults(); @@ -15,19 +16,23 @@ int main(int argc, char **argv) ctx = isl_ctx_alloc_with_options(&isl_options_args, options); + p = isl_printer_to_file(ctx, stdout); + map = isl_map_read_from_file(ctx, stdin); map = isl_map_transitive_closure(map, &exact); if (!exact) - printf("# NOT exact\n"); - isl_map_print(map, stdout, 0, ISL_FORMAT_ISL); - printf("\n"); + p = isl_printer_print_str(p, "# NOT exact\n"); + p = isl_printer_print_map(p, map); + p = isl_printer_end_line(p); map = isl_map_compute_divs(map); map = isl_map_coalesce(map); - printf("# coalesced\n"); - isl_map_print(map, stdout, 0, ISL_FORMAT_ISL); - printf("\n"); + p = isl_printer_print_str(p, "# coalesced\n"); + p = isl_printer_print_map(p, map); + p = isl_printer_end_line(p); isl_map_free(map); + isl_printer_free(p); + isl_ctx_free(ctx); return 0; diff --git a/polly/lib/External/isl/doc/user.pod b/polly/lib/External/isl/doc/user.pod index f5c0c4dfe42..84fd469b666 100644 --- a/polly/lib/External/isl/doc/user.pod +++ b/polly/lib/External/isl/doc/user.pod @@ -492,12 +492,16 @@ in which the object was created. __isl_keep isl_pw_multi_aff *pma); isl_ctx *isl_multi_pw_aff_get_ctx( __isl_keep isl_multi_pw_aff *mpa); + isl_ctx *isl_union_pw_aff_get_ctx( + __isl_keep isl_union_pw_aff *upa); isl_ctx *isl_union_pw_multi_aff_get_ctx( __isl_keep isl_union_pw_multi_aff *upma); + isl_ctx *isl_multi_union_pw_aff_get_ctx( + __isl_keep isl_multi_union_pw_aff *mupa); #include <isl/id_to_ast_expr.h> isl_ctx *isl_id_to_ast_expr_get_ctx( - __isl_keep id_to_ast_expr *id2expr); + __isl_keep isl_id_to_ast_expr *id2expr); #include <isl/point.h> isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt); @@ -519,9 +523,15 @@ in which the object was created. __isl_keep isl_restriction *restr); #include <isl/schedule.h> + isl_ctx *isl_schedule_get_ctx( + __isl_keep isl_schedule *sched); isl_ctx *isl_schedule_constraints_get_ctx( __isl_keep isl_schedule_constraints *sc); + #include <isl/schedule_node.h> + isl_ctx *isl_schedule_node_get_ctx( + __isl_keep isl_schedule_node *node); + #include <isl/band.h> isl_ctx *isl_band_get_ctx(__isl_keep isl_band *band); @@ -954,12 +964,20 @@ of the original object. __isl_keep isl_pw_multi_aff *pma); __isl_give isl_space *isl_pw_multi_aff_get_space( __isl_keep isl_pw_multi_aff *pma); + __isl_give isl_space *isl_union_pw_aff_get_space( + __isl_keep isl_union_pw_aff *upa); __isl_give isl_space *isl_union_pw_multi_aff_get_space( __isl_keep isl_union_pw_multi_aff *upma); __isl_give isl_space *isl_multi_pw_aff_get_domain_space( __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_union_pw_aff_get_domain_space( + __isl_keep isl_multi_union_pw_aff *mupa); + __isl_give isl_space * + isl_multi_union_pw_aff_get_space( + __isl_keep isl_multi_union_pw_aff *mupa); #include <isl/point.h> __isl_give isl_space *isl_point_get_space( @@ -1018,9 +1036,15 @@ C<isl_dim_out> (only for relations), C<isl_dim_set> unsigned isl_multi_pw_aff_dim( __isl_keep isl_multi_pw_aff *mpa, enum isl_dim_type type); + unsigned isl_union_pw_aff_dim( + __isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type); unsigned isl_union_pw_multi_aff_dim( __isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type); + unsigned isl_multi_union_pw_aff_dim( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); #include <isl/polynomial.h> unsigned isl_union_pw_qpolynomial_dim( @@ -1164,6 +1188,11 @@ operations and may not be preserved across those operations. __isl_take isl_multi_pw_aff *mpa, enum isl_dim_type type, unsigned pos, __isl_take isl_id *id); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_dim_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos, + __isl_take isl_id *id); __isl_give isl_id *isl_multi_aff_get_dim_id( __isl_keep isl_multi_aff *ma, enum isl_dim_type type, unsigned pos); @@ -1178,6 +1207,9 @@ operations and may not be preserved across those operations. __isl_give isl_id *isl_multi_pw_aff_get_dim_id( __isl_keep isl_multi_pw_aff *mpa, enum isl_dim_type type, unsigned pos); + __isl_give isl_id *isl_multi_union_pw_aff_get_dim_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos); __isl_give isl_aff *isl_aff_set_dim_name( __isl_take isl_aff *aff, enum isl_dim_type type, unsigned pos, const char *s); @@ -1188,6 +1220,20 @@ operations and may not be preserved across those operations. 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_union_pw_aff * + isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_set_dim_name( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_dim_name( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned pos, const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff, enum isl_dim_type type, unsigned pos); const char *isl_pw_aff_get_dim_name( @@ -1212,6 +1258,16 @@ operations and may not be preserved across those operations. __isl_take isl_pw_qpolynomial_fold *pwf, enum isl_dim_type type, unsigned pos, const char *s); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_set_dim_name( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned pos, + const char *s); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned pos, + const char *s); Note that C<isl_space_get_name> returns a pointer to some internal data structure, so the result can only be used while the @@ -1272,6 +1328,9 @@ its position can be obtained from the following functions. int isl_multi_pw_aff_find_dim_by_id( __isl_keep isl_multi_pw_aff *mpa, enum isl_dim_type type, __isl_keep isl_id *id); + int isl_multi_union_pw_aff_find_dim_by_id( + __isl_keep isl_union_multi_pw_aff *mupa, + enum isl_dim_type type, __isl_keep isl_id *id); int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, const char *name); int isl_multi_aff_find_dim_by_name( @@ -1285,9 +1344,15 @@ its position can be obtained from the following functions. int isl_pw_multi_aff_find_dim_by_name( __isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type, const char *name); + int isl_union_pw_aff_find_dim_by_name( + __isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type, const char *name); int isl_union_pw_multi_aff_find_dim_by_name( __isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type, const char *name); + int isl_multi_union_pw_aff_find_dim_by_name( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, const char *name); #include <isl/polynomial.h> int isl_pw_qpolynomial_find_dim_by_name( @@ -1410,6 +1475,10 @@ using the following functions. __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, __isl_take isl_id *id); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_tuple_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, __isl_take isl_id *id); __isl_give isl_multi_aff *isl_multi_aff_reset_tuple_id( __isl_take isl_multi_aff *ma, enum isl_dim_type type); @@ -1424,6 +1493,10 @@ using the following functions. isl_pw_multi_aff_reset_tuple_id( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_reset_tuple_id( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); int isl_multi_aff_has_tuple_id(__isl_keep isl_multi_aff *ma, enum isl_dim_type type); __isl_give isl_id *isl_multi_aff_get_tuple_id( @@ -1446,6 +1519,12 @@ using the following functions. __isl_give isl_id *isl_multi_pw_aff_get_tuple_id( __isl_keep isl_multi_pw_aff *mpa, enum isl_dim_type type); + int isl_multi_union_pw_aff_has_tuple_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); + __isl_give isl_id *isl_multi_union_pw_aff_get_tuple_id( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); __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); @@ -1453,6 +1532,10 @@ using the following functions. 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_union_pw_aff * + isl_multi_union_pw_aff_set_tuple_name( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, const char *s); const char *isl_multi_aff_get_tuple_name( __isl_keep isl_multi_aff *multi, enum isl_dim_type type); @@ -1462,6 +1545,9 @@ using the following functions. const char *isl_pw_multi_aff_get_tuple_name( __isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type); + const char *isl_multi_union_pw_aff_get_tuple_name( + __isl_keep isl_multi_union_pw_aff *mupa, + enum isl_dim_type type); The C<type> argument needs to be one of C<isl_dim_in>, C<isl_dim_out> or C<isl_dim_set>. As with C<isl_space_get_name>, @@ -1500,8 +1586,34 @@ of all the corresponding identifiers, use the following function. #include <isl/aff.h> __isl_give isl_multi_aff *isl_multi_aff_reset_user( __isl_take isl_multi_aff *ma); + __isl_give isl_pw_aff *isl_pw_aff_reset_user( + __isl_take isl_pw_aff *pa); __isl_give isl_multi_pw_aff *isl_multi_pw_aff_reset_user( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_reset_user( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_reset_user( + __isl_take isl_union_pw_multi_aff *upma); + + #include <isl/polynomial.h> + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_reset_user( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_reset_user( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_reset_user( + __isl_take isl_pw_qpolynomial_fold *pwf); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_reset_user( + __isl_take isl_union_pw_qpolynomial_fold *upwf); Spaces can be nested. In particular, the domain of a set or the domain or range of a relation can be a nested relation. @@ -1851,13 +1963,21 @@ or a list of affine expressions __isl_take isl_multi_pw_aff *mpa); __isl_give isl_map *isl_map_from_multi_pw_aff( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); __isl_give isl_union_map * isl_union_map_from_union_pw_multi_aff( __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_map * + isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); The C<domain_space> argument describes the domain of the resulting basic relation. It is required because the C<list> may consist of zero affine expressions. +The C<mupa> passed to C<isl_union_map_from_multi_union_pw_aff> +is not allowed to be zero-dimensional. The domain of the result +is the shared domain of the union piecewise affine elements. =head2 Inspecting Sets and Relations @@ -2442,9 +2562,12 @@ a set space, the corresponding multiple expression also has a set space. Objects of the value type do not have an associated space. The space of a multiple value is therefore always a set space. +Similarly, the space of a multiple union piecewise +affine expression is always a set space. The multiple expression types defined by C<isl> -are C<isl_multi_val>, C<isl_multi_aff> and C<isl_multi_pw_aff>. +are C<isl_multi_val>, C<isl_multi_aff>, C<isl_multi_pw_aff>, +C<isl_multi_union_pw_aff>. A multiple expression with the value zero for each output (or set) dimension can be created @@ -2459,6 +2582,13 @@ using the following functions. __isl_take isl_space *space); __isl_give isl_multi_pw_aff *isl_multi_pw_aff_zero( __isl_take isl_space *space); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_zero( + __isl_take isl_space *space); + +Since there is no canonical way of representing a zero +value of type C<isl_union_pw_aff>, the space passed +to C<isl_multi_union_pw_aff_zero> needs to be zero-dimensional. An identity function can be created using the following functions. The space needs to be that of a relation @@ -2488,13 +2618,19 @@ projection operations in L</"Unary Operations">. A multiple expression can be created from a single base expression using the following functions. The space of the created multiple expression is the same -as that of the base expression. +as that of the base expression, except for +C<isl_multi_union_pw_aff_from_union_pw_aff> where the input +lives in a parameter space and the output lives +in a single-dimensional set space. #include <isl/aff.h> __isl_give isl_multi_aff *isl_multi_aff_from_aff( __isl_take isl_aff *aff); __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff( __isl_take isl_pw_aff *pa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); A multiple expression can be created from a list of base expression in a specified space. @@ -2512,6 +2648,10 @@ then this space also needs to be a set space. __isl_give isl_multi_aff *isl_multi_aff_from_aff_list( __isl_take isl_space *space, __isl_take isl_aff_list *list); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_aff_list( + __isl_take isl_space *space, + __isl_take isl_union_pw_aff_list *list); As a convenience, a multiple piecewise expression can also be created from a multiple expression. @@ -2523,6 +2663,17 @@ universe cell. isl_multi_pw_aff_from_multi_aff( __isl_take isl_multi_aff *ma); +Similarly, a multiple union expression can be +created from a multiple expression. + + #include <isl/aff.h> + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); + A multiple quasi-affine expression can be created from a multiple value with a given domain space using the following function. @@ -2533,6 +2684,22 @@ function. __isl_take isl_space *space, __isl_take isl_multi_val *mv); +Similarly, +a multiple union piecewise affine expression can be created from +a multiple value with a given domain or +a multiple affine expression with a given domain +using the following functions. + + #include <isl/aff.h> + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_multi_aff *ma); + Multiple expressions can be copied and freed using the following functions. @@ -2551,6 +2718,12 @@ the following functions. __isl_keep isl_multi_pw_aff *mpa); __isl_null isl_multi_pw_aff *isl_multi_pw_aff_free( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_copy( + __isl_keep isl_multi_union_pw_aff *mupa); + __isl_null isl_multi_union_pw_aff * + isl_multi_union_pw_aff_free( + __isl_take isl_multi_union_pw_aff *mupa); The base expression at a given position of a multiple expression can be extracted using the following functions. @@ -2564,6 +2737,9 @@ expression can be extracted using the following functions. __isl_keep isl_multi_aff *multi, int pos); __isl_give isl_pw_aff *isl_multi_pw_aff_get_pw_aff( __isl_keep isl_multi_pw_aff *mpa, int pos); + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_get_union_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, int pos); It can be replaced using the following functions. @@ -2576,6 +2752,48 @@ It can be replaced using the following functions. __isl_give isl_multi_aff *isl_multi_aff_set_aff( __isl_take isl_multi_aff *multi, int pos, __isl_take isl_aff *aff); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_set_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, int pos, + __isl_take isl_union_pw_aff *upa); + +As a convenience, a sequence of base expressions that have +their domains in a given space can be extracted from a sequence +of union expressions using the following function. + + #include <isl/aff.h> + __isl_give isl_multi_pw_aff * + isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, + __isl_take isl_space *space); + +Note that there is a difference between C<isl_multi_union_pw_aff> +and C<isl_union_pw_multi_aff> objects. The first is a sequence +of unions of piecewise expressions, while the second is a union +of piecewise sequences. In particular, multiple affine expressions +in an C<isl_union_pw_multi_aff> may live in different spaces, +while there is only a single multiple expression in +an C<isl_multi_union_pw_aff>, which can therefore only live +in a single space. This means that not every +C<isl_union_pw_multi_aff> can be converted to +an C<isl_multi_union_pw_aff>. Conversely, a zero-dimensional +C<isl_multi_union_pw_aff> carries no information +about any possible domain and therefore cannot be converted +to an C<isl_union_pw_multi_aff>. Moreover, the elements +of an C<isl_multi_union_pw_aff> may be defined over different domains, +while each multiple expression inside an C<isl_union_pw_multi_aff> +has a single domain. The conversion of an C<isl_union_pw_multi_aff> +of dimension greater than one may therefore not be exact. +The following functions can +be used to perform these conversions when they are possible. + + #include <isl/aff.h> + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); =head3 Piecewise Expressions @@ -2663,6 +2881,8 @@ then create a piecewise expression over a universe domain. __isl_take isl_space *space); __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_range_map( + __isl_take isl_space *space); __isl_give isl_pw_multi_aff * isl_pw_multi_aff_project_out_map( __isl_take isl_space *space, @@ -2822,12 +3042,14 @@ over different domains. The space of a union expression is that of the shared parameter space. The union expression types defined by C<isl> -are C<isl_union_pw_multi_aff>, C<isl_union_pw_qpolynomial> and -C<isl_union_pw_qpolynomial_fold>. +are C<isl_union_pw_aff>, C<isl_union_pw_multi_aff>, +C<isl_union_pw_qpolynomial> and C<isl_union_pw_qpolynomial_fold>. An empty union expression can be created using the following functions. #include <isl/aff.h> + __isl_give isl_union_pw_aff *isl_union_pw_aff_empty( + __isl_take isl_space *space); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_empty( __isl_take isl_space *space); @@ -2841,6 +3063,12 @@ A union expression containing a single base expression can be created using the following functions. #include <isl/aff.h> + __isl_give isl_union_pw_aff * + isl_union_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_from_pw_multi_aff( __isl_take isl_pw_multi_aff *pma); @@ -2850,19 +3078,43 @@ can be created using the following functions. isl_union_pw_qpolynomial_from_pw_qpolynomial( __isl_take isl_pw_qpolynomial *pwqp); -The following function creates a base expression on each -of the sets in the union set and collects the results. +The following functions create a base expression on each +of the sets in the union set and collect the results. #include <isl/aff.h> __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_aff * + isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_val *v); + __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_multi_val_on_domain( __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv); +An C<isl_union_pw_aff> that is equal to a (parametric) affine +expression on a given domain can be created using the following +function. + + #include <isl/aff.h> + __isl_give isl_union_pw_aff * + isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, + __isl_take isl_aff *aff); + A base expression can be added to a union expression using the following functions. #include <isl/aff.h> + __isl_give isl_union_pw_aff * + isl_union_pw_aff_add_pw_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_pw_aff *pa); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_add_pw_multi_aff( __isl_take isl_union_pw_multi_aff *upma, @@ -2878,6 +3130,10 @@ Union expressions can be copied and freed using the following functions. #include <isl/aff.h> + __isl_give isl_union_pw_aff *isl_union_pw_aff_copy( + __isl_keep isl_union_pw_aff *upa); + __isl_null isl_union_pw_aff *isl_union_pw_aff_free( + __isl_take isl_union_pw_aff *upa); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_copy( __isl_keep isl_union_pw_multi_aff *upma); @@ -2903,16 +3159,28 @@ To iterate over the base expressions in a union expression, use the following functions. #include <isl/aff.h> + int isl_union_pw_aff_n_pw_aff( + __isl_keep isl_union_pw_aff *upa); + int isl_union_pw_aff_foreach_pw_aff( + __isl_keep isl_union_pw_aff *upa, + int (*fn)(__isl_take isl_pw_aff *ma, void *user), + void *user); + int isl_union_pw_multi_aff_n_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma); int isl_union_pw_multi_aff_foreach_pw_multi_aff( __isl_keep isl_union_pw_multi_aff *upma, int (*fn)(__isl_take isl_pw_multi_aff *pma, void *user), void *user); #include <isl/polynomial.h> + int isl_union_pw_qpolynomial_n_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp); int isl_union_pw_qpolynomial_foreach_pw_qpolynomial( __isl_keep isl_union_pw_qpolynomial *upwqp, int (*fn)(__isl_take isl_pw_qpolynomial *pwqp, void *user), void *user); + int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); int isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( __isl_keep isl_union_pw_qpolynomial_fold *upwf, int (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf, @@ -2922,6 +3190,9 @@ To extract the base expression in a given space from a union, use the following functions. #include <isl/aff.h> + __isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff( + __isl_keep isl_union_pw_aff *upa, + __isl_take isl_space *space); __isl_give isl_pw_multi_aff * isl_union_pw_multi_aff_extract_pw_multi_aff( __isl_keep isl_union_pw_multi_aff *upma, @@ -3000,6 +3271,8 @@ Objects can be read from input using the following functions. #include <isl/val.h> __isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str); + __isl_give isl_multi_val *isl_multi_val_read_from_str( + isl_ctx *ctx, const char *str); #include <isl/set.h> __isl_give isl_basic_set *isl_basic_set_read_from_file( @@ -3047,6 +3320,9 @@ Objects can be read from input using the following functions. __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_read_from_str( isl_ctx *ctx, const char *str); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); #include <isl/polynomial.h> __isl_give isl_union_pw_qpolynomial * @@ -3076,6 +3352,7 @@ The printer can be inspected using the following functions. __isl_keep isl_printer *printer); int isl_printer_get_output_format( __isl_keep isl_printer *p); + int isl_printer_get_yaml_style(__isl_keep isl_printer *p); The behavior of the printer can be modified in various ways @@ -3091,6 +3368,8 @@ The behavior of the printer can be modified in various ways __isl_take isl_printer *p, const char *prefix); __isl_give isl_printer *isl_printer_set_suffix( __isl_take isl_printer *p, const char *suffix); + __isl_give isl_printer *isl_printer_set_yaml_style( + __isl_take isl_printer *p, int yaml_style); The C<output_format> may be either C<ISL_FORMAT_ISL>, C<ISL_FORMAT_OMEGA>, C<ISL_FORMAT_POLYLIB>, C<ISL_FORMAT_EXT_POLYLIB> or C<ISL_FORMAT_LATEX> @@ -3104,6 +3383,9 @@ appear between those of the set variables and those of the parameters. The function C<isl_printer_indent> increases the indentation by the specified amount (which may be negative). +The YAML style may be either C<ISL_YAML_STYLE_BLOCK> or +C<ISL_YAML_STYLE_FLOW> and when we are printing something +in YAML format. To actually print something, use @@ -3161,9 +3443,16 @@ To actually print something, use __isl_give isl_printer *isl_printer_print_multi_pw_aff( __isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa); + __isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_union_pw_aff *upa); __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_printer * + isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, + __isl_keep isl_multi_union_pw_aff *mupa); #include <isl/polynomial.h> __isl_give isl_printer *isl_printer_print_qpolynomial( @@ -3196,6 +3485,34 @@ is supported. In case of printing in C<ISL_FORMAT_C>, the user may want to set the names of all dimensions first. +C<isl> also provides limited support for printing YAML documents, +just enough for the internal use for printing such documents. + + #include <isl/printer.h> + __isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_yaml_next( + __isl_take isl_printer *p); + +A document is started by a call to either +C<isl_printer_yaml_start_mapping> or C<isl_printer_yaml_start_sequence>. +Anything printed to the printer after such a call belong to the +first key of the mapping or the first element in the sequence. +The function C<isl_printer_yaml_next> moves to the value if +we are currently printing a mapping key, the next key if we +are printing a value or the next element if we are printing +an element in a sequence. +Nested mappings and sequences are initiated by the same +C<isl_printer_yaml_start_mapping> or C<isl_printer_yaml_start_sequence>. +Each call to these functions needs to have a corresponding call to +C<isl_printer_yaml_end_mapping> or C<isl_printer_yaml_end_sequence>. + When called on a file printer, the following function flushes the file. When called on a string printer, the buffer is cleared. @@ -3234,8 +3551,12 @@ in isl format. #include <isl/aff.h> __isl_give char *isl_multi_aff_to_str( __isl_keep isl_multi_aff *aff); + __isl_give char *isl_union_pw_aff_to_str( + __isl_keep isl_union_pw_aff *upa); __isl_give char *isl_union_pw_multi_aff_to_str( __isl_keep isl_union_pw_multi_aff *upma); + __isl_give char *isl_multi_union_pw_aff_to_str( + __isl_keep isl_multi_union_pw_aff *mupa); =head2 Properties @@ -3431,6 +3752,8 @@ The following functions check whether the space of the given __isl_keep isl_multi_aff *ma); int isl_multi_pw_aff_range_is_wrapping( __isl_keep isl_multi_pw_aff *mpa); + int isl_multi_union_pw_aff_range_is_wrapping( + __isl_keep isl_multi_union_pw_aff *mupa); The input to C<isl_space_is_wrapping> should be the space of a set, while that of @@ -3541,9 +3864,15 @@ return true if the objects are not the same. int isl_multi_pw_aff_is_equal( __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2); + int isl_union_pw_aff_plain_is_equal( + __isl_keep isl_union_pw_aff *upa1, + __isl_keep isl_union_pw_aff *upa2); int isl_union_pw_multi_aff_plain_is_equal( __isl_keep isl_union_pw_multi_aff *upma1, __isl_keep isl_union_pw_multi_aff *upma2); + int isl_multi_union_pw_aff_plain_is_equal( + __isl_keep isl_multi_union_pw_aff *mupa1, + __isl_keep isl_multi_union_pw_aff *mupa2); #include <isl/polynomial.h> int isl_union_pw_qpolynomial_plain_is_equal( @@ -3555,6 +3884,7 @@ return true if the objects are not the same. =item * Disjointness + #include <isl/set.h> int isl_basic_set_is_disjoint( __isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2); @@ -3562,12 +3892,24 @@ return true if the objects are not the same. __isl_keep isl_set *set2); int isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2); + + #include <isl/map.h> int isl_basic_map_is_disjoint( __isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2); int isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2); + #include <isl/union_set.h> + int isl_union_set_is_disjoint( + __isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); + + #include <isl/union_map.h> + int isl_union_map_is_disjoint( + __isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); + =item * Subset int isl_basic_set_is_subset( @@ -3726,9 +4068,16 @@ earlier dimensions before those that involve later dimensions. __isl_take isl_map *map); #include <isl/union_set.h> + __isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, + unsigned first, unsigned n); __isl_give isl_set *isl_union_set_params( __isl_take isl_union_set *uset); +The function C<isl_union_set_project_out> can only project out +parameters. + #include <isl/union_map.h> __isl_give isl_union_map *isl_union_map_project_out( __isl_take isl_union_map *umap, @@ -3755,11 +4104,19 @@ parameters. __isl_take isl_pw_multi_aff *pma); __isl_give isl_set *isl_multi_pw_aff_domain( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_set *isl_union_pw_aff_domain( + __isl_take isl_union_pw_aff *upa); __isl_give isl_union_set *isl_union_pw_multi_aff_domain( __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_set * + isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa); __isl_give isl_set *isl_pw_aff_params( __isl_take isl_pw_aff *pwa); +The function C<isl_multi_union_pw_aff_domain> requires its +input to have at least one set dimension. + #include <isl/polynomial.h> __isl_give isl_qpolynomial * isl_qpolynomial_project_domain_on_params( @@ -3796,6 +4153,9 @@ parameters. #include <isl/union_map.h> __isl_give isl_union_map *isl_union_map_domain_map( __isl_take isl_union_map *umap); + __isl_give isl_union_pw_multi_aff * + isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap); __isl_give isl_union_map *isl_union_map_range_map( __isl_take isl_union_map *umap); __isl_give isl_union_map * @@ -3880,6 +4240,9 @@ flat anonymous space. __isl_take isl_pw_aff *pwa); __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_range( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_range( + __isl_take isl_multi_union_pw_aff *mupa); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain( __isl_take isl_set *set); __isl_give isl_union_pw_multi_aff * @@ -4017,12 +4380,20 @@ dimensions satisfy the given ordering. __isl_take isl_aff *aff); __isl_give isl_basic_set *isl_aff_neg_basic_set( __isl_take isl_aff *aff); + __isl_give isl_set *isl_pw_aff_pos_set( + __isl_take isl_pw_aff *pa); __isl_give isl_set *isl_pw_aff_nonneg_set( __isl_take isl_pw_aff *pwaff); __isl_give isl_set *isl_pw_aff_zero_set( __isl_take isl_pw_aff *pwaff); __isl_give isl_set *isl_pw_aff_non_zero_set( __isl_take isl_pw_aff *pwaff); + __isl_give isl_union_set * + isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_set * + isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa); The function C<isl_aff_neg_basic_set> returns a basic set containing those elements in the domain space @@ -4030,6 +4401,9 @@ of C<aff> where C<aff> is negative. The function C<isl_pw_aff_nonneg_set> returns a set containing those elements in the domain of C<pwaff> where C<pwaff> is non-negative. +The function C<isl_multi_union_pw_aff_zero_union_set> +returns a union set containing those elements +in the domains of its elements where they are all zero. =item * Identity @@ -4037,6 +4411,9 @@ of C<pwaff> where C<pwaff> is non-negative. __isl_take isl_set *set); __isl_give isl_union_map *isl_union_set_identity( __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset); Construct an identity relation on the given (union) set. @@ -4055,7 +4432,11 @@ and the C<isl_map> is single-valued. In case of a conversion from an C<isl_union_map> to an C<isl_union_pw_multi_aff>, these properties need to hold in each domain space. +A conversion to a C<isl_multi_union_pw_aff> additionally +requires that the input is non-empty and involves only a single +range space. + #include <isl/aff.h> __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( @@ -4068,6 +4449,10 @@ in each domain space. isl_union_pw_multi_aff_from_union_map( __isl_take isl_union_map *umap); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap); + =item * Deltas __isl_give isl_basic_set *isl_basic_map_deltas( @@ -4116,6 +4501,8 @@ basic set or relation. __isl_take isl_pw_multi_aff *pma); __isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce( + __isl_take isl_union_pw_aff *upa); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_coalesce( __isl_take isl_union_pw_multi_aff *upma); @@ -4162,15 +4549,28 @@ equalities. =item * Removing redundant constraints + #include <isl/set.h> __isl_give isl_basic_set *isl_basic_set_remove_redundancies( __isl_take isl_basic_set *bset); __isl_give isl_set *isl_set_remove_redundancies( __isl_take isl_set *set); + + #include <isl/union_set.h> + __isl_give isl_union_set * + isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset); + + #include <isl/map.h> __isl_give isl_basic_map *isl_basic_map_remove_redundancies( __isl_take isl_basic_map *bmap); __isl_give isl_map *isl_map_remove_redundancies( __isl_take isl_map *map); + #include <isl/union_map.h> + __isl_give isl_union_map * + isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap); + =item * Convex hull __isl_give isl_basic_set *isl_set_convex_hull( @@ -4200,6 +4600,10 @@ variables, then the result of these operations is currently undefined. __isl_take isl_map *map); __isl_give isl_basic_map *isl_map_simple_hull( __isl_take isl_map *map); + __isl_give isl_basic_map * + isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, + __isl_take isl_map_list *list); #include <isl/union_map.h> __isl_give isl_union_map *isl_union_map_simple_hull( @@ -4211,7 +4615,8 @@ In particular, the output is described by translates of the constraints describing the basic sets or relations in the input. In case of C<isl_set_unshifted_simple_hull>, only the original constraints are used, without any translation. -In case of C<isl_set_unshifted_simple_hull_from_set_list>, the +In case of C<isl_set_unshifted_simple_hull_from_set_list> and +C<isl_map_unshifted_simple_hull_from_map_list>, the constraints are taken from the elements of the second argument. =begin latex @@ -4437,6 +4842,10 @@ the overapproximation), then you will get an error message. __isl_give isl_space *isl_space_unwrap( __isl_take isl_space *space); + #include <isl/local_space.h> + __isl_give isl_local_space *isl_local_space_wrap( + __isl_take isl_local_space *ls); + #include <isl/set.h> __isl_give isl_basic_map *isl_basic_set_unwrap( __isl_take isl_basic_set *bset); @@ -4509,6 +4918,9 @@ then the name of the space is also removed. __isl_give isl_multi_pw_aff * isl_multi_pw_aff_flatten_range( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_flatten_range( + __isl_take isl_multi_union_pw_aff *mupa); #include <isl/map.h> __isl_give isl_map *isl_set_flatten_map( @@ -4648,10 +5060,18 @@ All parameters need to be named. __isl_give isl_pw_multi_aff *isl_pw_multi_aff_align_params( __isl_take isl_pw_multi_aff *pma, __isl_take isl_space *model); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_align_params( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_space *model); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_align_params( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *model); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_align_params( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_space *model); #include <isl/polynomial.h> __isl_give isl_qpolynomial *isl_qpolynomial_align_params( @@ -4660,11 +5080,29 @@ All parameters need to be named. =item * Unary Arithmethic Operations + #include <isl/val.h> + __isl_give isl_multi_val *isl_multi_val_neg( + __isl_take isl_multi_val *mv); + #include <isl/aff.h> __isl_give isl_aff *isl_aff_neg( __isl_take isl_aff *aff); + __isl_give isl_multi_aff *isl_multi_aff_neg( + __isl_take isl_multi_aff *ma); __isl_give isl_pw_aff *isl_pw_aff_neg( __isl_take isl_pw_aff *pwaff); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_neg( + __isl_take isl_pw_multi_aff *pma); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_neg( + __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_union_pw_aff *isl_union_pw_aff_neg( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_neg( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_neg( + __isl_take isl_multi_union_pw_aff *mupa); __isl_give isl_aff *isl_aff_ceil( __isl_take isl_aff *aff); __isl_give isl_pw_aff *isl_pw_aff_ceil( @@ -4675,6 +5113,11 @@ All parameters need to be named. __isl_take isl_multi_aff *ma); __isl_give isl_pw_aff *isl_pw_aff_floor( __isl_take isl_pw_aff *pwaff); + __isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_floor( + __isl_take isl_multi_union_pw_aff *mupa); #include <isl/aff.h> __isl_give isl_pw_aff *isl_pw_aff_list_min( @@ -4846,6 +5289,19 @@ are not sufficient. __isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_dims( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_drop_dims( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_drop_dims( + __isl_take isl_multi_union_pw_aff *mupa, + enum isl_dim_type type, unsigned first, + unsigned n); __isl_give isl_aff *isl_aff_move_dims( __isl_take isl_aff *aff, enum isl_dim_type dst_type, unsigned dst_pos, @@ -4867,6 +5323,20 @@ are not sufficient. enum isl_dim_type src_type, unsigned src_pos, unsigned n); + #include <isl/polynomial.h> + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_drop_dims( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, + unsigned first, unsigned n); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_drop_dims( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, + unsigned first, unsigned n); + +The operations on union expressions can only manipulate parameters. + =back =head2 Binary Operations @@ -4912,6 +5382,8 @@ the same (number of) parameters. __isl_give isl_basic_map *isl_basic_map_intersect( __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); + __isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list); __isl_give isl_map *isl_map_intersect_params( __isl_take isl_map *map, __isl_take isl_set *params); @@ -4958,10 +5430,17 @@ the same (number of) parameters. __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_aff *isl_union_pw_aff_intersect_domain( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *uset); __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_union_pw_aff * + isl_multi_union_pw_aff_intersect_domain( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_set *uset); __isl_give isl_pw_aff *isl_pw_aff_intersect_params( __isl_take isl_pw_aff *pa, __isl_take isl_set *set); @@ -4972,10 +5451,20 @@ the same (number of) parameters. __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_union_pw_aff * + isl_union_pw_aff_intersect_params( + __isl_take isl_union_pw_aff *upa, __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_intersect_params( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_set *set); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_intersect_params( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_set *params); + isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_set *set); #include <isl/polynomial.h> __isl_give isl_pw_qpolynomial * @@ -5013,33 +5502,48 @@ for either argument is only allowed if the other argument is a parametric set as well. The list passed to C<isl_basic_set_list_intersect> needs to have at least one element and all elements need to live in the same space. +The function C<isl_multi_union_pw_aff_intersect_range> +restricts the input function to those shared domain elements +that map to the specified range. =item * Union + #include <isl/set.h> __isl_give isl_set *isl_basic_set_union( __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2); - __isl_give isl_map *isl_basic_map_union( - __isl_take isl_basic_map *bmap1, - __isl_take isl_basic_map *bmap2); __isl_give isl_set *isl_set_union( __isl_take isl_set *set1, __isl_take isl_set *set2); + + #include <isl/map.h> + __isl_give isl_map *isl_basic_map_union( + __isl_take isl_basic_map *bmap1, + __isl_take isl_basic_map *bmap2); __isl_give isl_map *isl_map_union( __isl_take isl_map *map1, __isl_take isl_map *map2); + + #include <isl/union_set.h> __isl_give isl_union_set *isl_union_set_union( __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2); + __isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list); + + #include <isl/union_map.h> __isl_give isl_union_map *isl_union_map_union( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); =item * Set difference + #include <isl/set.h> __isl_give isl_set *isl_set_subtract( __isl_take isl_set *set1, __isl_take isl_set *set2); + + #include <isl/map.h> __isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1, __isl_take isl_map *map2); @@ -5049,9 +5553,13 @@ at least one element and all elements need to live in the same space. __isl_give isl_map *isl_map_subtract_range( __isl_take isl_map *map, __isl_take isl_set *dom); + + #include <isl/union_set.h> __isl_give isl_union_set *isl_union_set_subtract( __isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2); + + #include <isl/union_map.h> __isl_give isl_union_map *isl_union_map_subtract( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); @@ -5062,6 +5570,41 @@ at least one element and all elements need to live in the same space. __isl_take isl_union_map *umap, __isl_take isl_union_set *dom); + #include <isl/aff.h> + __isl_give isl_pw_aff *isl_pw_aff_subtract_domain( + __isl_take isl_pw_aff *pa, + __isl_take isl_set *set); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_subtract_domain( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_set *set); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_subtract_domain( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_subtract_domain( + __isl_take isl_union_pw_multi_aff *upma, + __isl_take isl_set *set); + + #include <isl/polynomial.h> + __isl_give isl_pw_qpolynomial * + isl_pw_qpolynomial_subtract_domain( + __isl_take isl_pw_qpolynomial *pwpq, + __isl_take isl_set *set); + __isl_give isl_pw_qpolynomial_fold * + isl_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, + __isl_take isl_set *set); + __isl_give isl_union_pw_qpolynomial * + isl_union_pw_qpolynomial_subtract_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); + __isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); + =item * Application #include <isl/space.h> @@ -5100,6 +5643,33 @@ at least one element and all elements need to live in the same space. __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); + #include <isl/aff.h> + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_aff *aff); + __isl_give isl_union_pw_aff * + isl_multi_union_pw_aff_apply_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_aff *pa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_aff *ma); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma); + +The result of C<isl_multi_union_pw_aff_apply_aff> is defined +over the shared domain of the elements of the input. The dimension is +required to be greater than zero. +The C<isl_multi_union_pw_aff> argument of +C<isl_multi_union_pw_aff_apply_multi_aff> is allowed to be zero-dimensional, +but only if the range of the C<isl_multi_aff> argument +is also zero-dimensional. +Similarly for C<isl_multi_union_pw_aff_apply_pw_multi_aff>. + #include <isl/polynomial.h> __isl_give isl_pw_qpolynomial_fold * isl_set_apply_pw_qpolynomial_fold( @@ -5262,6 +5832,18 @@ into the set description or into the domain/range of the map. isl_multi_pw_aff_pullback_multi_pw_aff( __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_union_pw_aff * + isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_pw_multi_aff * + isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma); These functions precompose the first expression by the second function. In other words, the second function is plugged @@ -5335,6 +5917,47 @@ equal to C<ma2>. The functions operating on C<isl_pw_aff_list> apply the corresponding C<isl_pw_aff> function to each pair of elements in the two lists. + #include <isl/aff.h> + __isl_give isl_map *isl_pw_aff_eq_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_map *isl_pw_aff_lt_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_map *isl_pw_aff_gt_map( + __isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + + __isl_give isl_map *isl_multi_pw_aff_eq_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + +These functions return a map between domain elements of the arguments +where the function values satisfy the given relation. + + #include <isl/union_map.h> + __isl_give isl_union_map * + isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_map * + isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_map * + isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + +These functions select the subset of elements in the union map +that have an equal or lexicographically smaller function value. + =item * Cartesian Product #include <isl/space.h> @@ -5430,6 +6053,10 @@ two input spaces. __isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_product( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); The above functions compute the cross product of the given sets, relations or functions. The domains and ranges of the results @@ -5464,6 +6091,10 @@ instead. #include <isl/union_map.h> __isl_give isl_union_map * + isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, + __isl_take isl_union_map *umap2); + __isl_give isl_union_map * isl_union_map_flat_range_product( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); @@ -5489,6 +6120,10 @@ instead. 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_multi_union_pw_aff * + isl_multi_union_pw_aff_flat_range_product( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); #include <isl/space.h> __isl_give isl_space *isl_space_factor_domain( @@ -5561,6 +6196,12 @@ from the result using the following functions. __isl_give isl_multi_pw_aff * isl_multi_pw_aff_range_factor_range( __isl_take isl_multi_pw_aff *mpa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_factor_domain( + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_factor_range( + __isl_take isl_multi_union_pw_aff *mupa); The splice functions are a generalization of the flat product functions, where the second argument may be inserted at any position inside @@ -5587,6 +6228,11 @@ the first argument rather than being placed at the end. __isl_take isl_multi_pw_aff *mpa1, unsigned in_pos, unsigned out_pos, __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_range_splice( + __isl_take isl_multi_union_pw_aff *mupa1, + unsigned pos, + __isl_take isl_multi_union_pw_aff *mupa2); =item * Simplification @@ -5619,6 +6265,9 @@ to simplify the expression associated to each cell. __isl_give isl_basic_map *isl_basic_map_gist( __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context); + __isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, + __isl_take isl_basic_set *context); __isl_give isl_map *isl_map_gist(__isl_take isl_map *map, __isl_take isl_map *context); __isl_give isl_map *isl_map_gist_params( @@ -5683,6 +6332,12 @@ to simplify the expression associated to each cell. __isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist( __isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set); + __isl_give isl_union_pw_aff *isl_union_pw_aff_gist( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_set *context); + __isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_set *context); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_gist_params( __isl_take isl_union_pw_multi_aff *upma, @@ -5691,6 +6346,14 @@ to simplify the expression associated to each cell. isl_union_pw_multi_aff_gist( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_union_set *context); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_gist_params( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_set *context); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_gist( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_union_set *context); #include <isl/polynomial.h> __isl_give isl_qpolynomial *isl_qpolynomial_gist_params( @@ -5738,6 +6401,11 @@ to simplify the expression associated to each cell. =item * Binary Arithmethic Operations + #include <isl/val.h> + __isl_give isl_multi_val *isl_multi_val_sub( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); + #include <isl/aff.h> __isl_give isl_aff *isl_aff_add( __isl_take isl_aff *aff1, @@ -5751,6 +6419,9 @@ to simplify the expression associated to each cell. __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_union_pw_aff *isl_union_pw_aff_add( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); __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); @@ -5769,12 +6440,22 @@ to simplify the expression associated to each cell. __isl_give isl_pw_aff *isl_pw_aff_sub( __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_sub( + __isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); __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_aff *isl_union_pw_aff_sub( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); __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_multi_union_pw_aff * + isl_multi_union_pw_aff_sub( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); C<isl_aff_sub> subtracts the second argument from the first. @@ -5818,10 +6499,17 @@ C<isl_aff_sub> subtracts the second argument from the first. __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_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, + __isl_take isl_union_pw_aff *upa2); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_union_add( __isl_take isl_union_pw_multi_aff *upma1, __isl_take isl_union_pw_multi_aff *upma2); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); __isl_give isl_pw_aff *isl_pw_aff_union_min( __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); @@ -5858,6 +6546,9 @@ only defined on the shared definition domain of the arguments. __isl_give isl_pw_aff *isl_pw_aff_mod_val( __isl_take isl_pw_aff *pa, __isl_take isl_val *mod); + __isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *f); __isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, __isl_take isl_val *v); __isl_give isl_multi_aff *isl_multi_aff_scale_val( @@ -5872,9 +6563,16 @@ only defined on the shared definition domain of the arguments. __isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v); __isl_give isl_union_pw_multi_aff * + __isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *f); isl_union_pw_multi_aff_scale_val( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_val *v); __isl_give isl_aff *isl_aff_scale_down_ui( __isl_take isl_aff *aff, unsigned f); __isl_give isl_aff *isl_aff_scale_down_val( @@ -5891,10 +6589,17 @@ only defined on the shared definition domain of the arguments. __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_val( __isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v); + __isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_val *v); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_scale_down_val( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_down_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_val *v); #include <isl/polynomial.h> __isl_give isl_qpolynomial *isl_qpolynomial_scale_val( @@ -5946,6 +6651,9 @@ only defined on the shared definition domain of the arguments. __isl_take isl_val *v); #include <isl/val.h> + __isl_give isl_multi_val *isl_multi_val_mod_multi_val( + __isl_take isl_multi_val *mv1, + __isl_take isl_multi_val *mv2); __isl_give isl_multi_val *isl_multi_val_scale_multi_val( __isl_take isl_multi_val *mv1, __isl_take isl_multi_val *mv2); @@ -5955,6 +6663,17 @@ only defined on the shared definition domain of the arguments. __isl_take isl_multi_val *mv2); #include <isl/aff.h> + __isl_give isl_multi_aff *isl_multi_aff_mod_multi_val( + __isl_take isl_multi_aff *ma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_mod_multi_val( + __isl_take isl_multi_union_pw_aff *upma, + __isl_take isl_multi_val *mv); + __isl_give isl_multi_pw_aff * + isl_multi_pw_aff_mod_multi_val( + __isl_take isl_multi_pw_aff *mpa, + __isl_take isl_multi_val *mv); __isl_give isl_multi_aff *isl_multi_aff_scale_multi_val( __isl_take isl_multi_aff *ma, __isl_take isl_multi_val *mv); @@ -5966,6 +6685,10 @@ only defined on the shared definition domain of the arguments. isl_multi_pw_aff_scale_multi_val( __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_multi_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_val *mv); __isl_give isl_union_pw_multi_aff * isl_union_pw_multi_aff_scale_multi_val( __isl_take isl_union_pw_multi_aff *upma, @@ -5978,6 +6701,10 @@ only defined on the shared definition domain of the arguments. isl_multi_pw_aff_scale_down_multi_val( __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_val *mv); + __isl_give isl_multi_union_pw_aff * + isl_multi_union_pw_aff_scale_down_multi_val( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_multi_val *mv); C<isl_multi_aff_scale_multi_val> scales the elements of C<ma> by the corresponding elements of C<mv>. @@ -6187,8 +6914,10 @@ where C<cond> is zero. =head2 Lists Lists are defined over several element types, including -C<isl_val>, C<isl_id>, C<isl_aff>, C<isl_pw_aff>, C<isl_constraint>, -C<isl_basic_set>, C<isl_set>, C<isl_ast_expr> and C<isl_ast_node>. +C<isl_val>, C<isl_id>, C<isl_aff>, C<isl_pw_aff>, C<isl_union_pw_aff>, +C<isl_union_pw_multi_aff>, C<isl_constraint>, +C<isl_basic_set>, C<isl_set>, C<isl_basic_map>, C<isl_map>, C<isl_union_set>, +C<isl_union_map>, C<isl_ast_expr> and C<isl_ast_node>. Here we take lists of C<isl_set>s as an example. Lists can be created, copied, modified and freed using the following functions. @@ -6222,9 +6951,10 @@ Lists can be created, copied, modified and freed using the following functions. __isl_null isl_set_list *isl_set_list_free( __isl_take isl_set_list *list); -C<isl_set_list_alloc> creates an empty list with a capacity for -C<n> elements. C<isl_set_list_from_set> creates a list with a single -element. +C<isl_set_list_alloc> creates an empty list with an initial capacity +for C<n> elements. C<isl_set_list_insert> and C<isl_set_list_add> +add elements to a list, increasing its capacity as needed. +C<isl_set_list_from_set> creates a list with a single element. Lists can be inspected using the following functions. @@ -6269,12 +6999,12 @@ Associative arrays can be created, copied and freed using the following functions. #include <isl/id_to_ast_expr.h> - __isl_give id_to_ast_expr *isl_id_to_ast_expr_alloc( + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_alloc( isl_ctx *ctx, int min_size); - __isl_give id_to_ast_expr *isl_id_to_ast_expr_copy( - __isl_keep id_to_ast_expr *id2expr); - __isl_null id_to_ast_expr *isl_id_to_ast_expr_free( - __isl_take id_to_ast_expr *id2expr); + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_copy( + __isl_keep isl_id_to_ast_expr *id2expr); + __isl_null isl_id_to_ast_expr *isl_id_to_ast_expr_free( + __isl_take isl_id_to_ast_expr *id2expr); The C<min_size> argument to C<isl_id_to_ast_expr_alloc> can be used to specify the expected size of the associative array. @@ -6284,13 +7014,13 @@ Associative arrays can be inspected using the following functions. #include <isl/id_to_ast_expr.h> int isl_id_to_ast_expr_has( - __isl_keep id_to_ast_expr *id2expr, + __isl_keep isl_id_to_ast_expr *id2expr, __isl_keep isl_id *key); __isl_give isl_ast_expr *isl_id_to_ast_expr_get( - __isl_keep id_to_ast_expr *id2expr, + __isl_keep isl_id_to_ast_expr *id2expr, __isl_take isl_id *key); int isl_id_to_ast_expr_foreach( - __isl_keep id_to_ast_expr *id2expr, + __isl_keep isl_id_to_ast_expr *id2expr, int (*fn)(__isl_take isl_id *key, __isl_take isl_ast_expr *val, void *user), void *user); @@ -6298,12 +7028,12 @@ Associative arrays can be inspected using the following functions. They can be modified using the following function. #include <isl/id_to_ast_expr.h> - __isl_give id_to_ast_expr *isl_id_to_ast_expr_set( - __isl_take id_to_ast_expr *id2expr, + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_set( + __isl_take isl_id_to_ast_expr *id2expr, __isl_take isl_id *key, __isl_take isl_ast_expr *val); - __isl_give id_to_ast_expr *isl_id_to_ast_expr_drop( - __isl_take id_to_ast_expr *id2expr, + __isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_drop( + __isl_take isl_id_to_ast_expr *id2expr, __isl_take isl_id *key); Associative arrays can be printed using the following function. @@ -6311,7 +7041,7 @@ Associative arrays can be printed using the following function. #include <isl/id_to_ast_expr.h> __isl_give isl_printer *isl_printer_print_id_to_ast_expr( __isl_take isl_printer *p, - __isl_keep id_to_ast_expr *id2expr); + __isl_keep isl_id_to_ast_expr *id2expr); =head2 Vectors @@ -6476,6 +7206,443 @@ Chambers can be inspected and destroyed using the following functions. This section collects functionality in C<isl> that has been specifically designed for use during polyhedral compilation. +=head2 Schedule Trees + +A schedule tree is a structured representation of a schedule, +assigning a relative order to a set of domain elements. +The relative order expressed by the schedule tree is +defined recursively. In particular, the order between +two domain elements is determined by the node that is closest +to the root that refers to both elements and that orders them apart. +Each node in the tree is of one of several types. +The root node is always of type C<isl_schedule_node_domain> +and it describes the domain elements to which the schedule applies. +The other types of nodes are as follows. + +=over + +=item C<isl_schedule_node_band> + +A band of schedule dimensions. Each schedule dimension is represented +by a union piecewise quasi-affine expression. If this expression +assigns a different value to two domain elements, while all previous +schedule dimensions in the same band assign them the same value, +then the two domain elements are ordered according to these two +different values. + +=item C<isl_schedule_node_filter> + +A filter node does not impose any ordering, but rather intersects +the set of domain elements that the current subtree refers to +with a given union set. The subtree of the filter node only +refers to domain elements in the intersection. +A filter node is typically only used a child of a sequence or +set node. + +=item C<isl_schedule_node_leaf> + +A leaf of the schedule tree. Leaf nodes do not impose any ordering. + +=item C<isl_schedule_node_sequence> + +A sequence node has one or more children, each of which is a filter node. +The filters on these filter nodes form a partition of +the domain elements that the current subtree refers to. +If two domain elements appear in distinct filters then the sequence +node orders them according to the child positions of the corresponding +filter nodes. + +=item C<isl_schedule_node_set> + +A set node is similar to a sequence node, except that +it expresses that domain elements appearing in distinct filters +may have any order. The order of the children of a set node +is therefore also immaterial. + +=back + +A schedule tree is encapsulated in an C<isl_schedule> object. +The simplest such objects, those with a tree consisting of single domain node, +can be created using the following functions with either an empty +domain or a given domain. + + #include <isl/schedule.h> + __isl_give isl_schedule *isl_schedule_empty( + __isl_take isl_space *space); + __isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain); + +The function C<isl_schedule_constraints_compute_schedule> described +in L</"Scheduling"> can also be used to construct schedules. + +C<isl_schedule> objects may be copied and freed using the following functions. + + #include <isl/schedule.h> + __isl_give isl_schedule *isl_schedule_copy( + __isl_keep isl_schedule *sched); + __isl_null isl_schedule *isl_schedule_free( + __isl_take isl_schedule *sched); + +The domain of the schedule, i.e., the domain described by the root node, +can be obtained using the following function. + + #include <isl/schedule.h> + __isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); + +An C<isl_union_map> representation of the schedule can be obtained +from an C<isl_schedule> using the following function. + + #include <isl/schedule.h> + __isl_give isl_union_map *isl_schedule_get_map( + __isl_keep isl_schedule *sched); + +The resulting relation encodes the same relative ordering as +the schedule by mapping the domain elements to a common schedule space. +If the schedule_separate_components option is set, then the order +of the children of a set node is explicitly encoded in the result. + +Schedules can be read from input using the following functions. + + #include <isl/schedule.h> + __isl_give isl_schedule *isl_schedule_read_from_file( + isl_ctx *ctx, FILE *input); + __isl_give isl_schedule *isl_schedule_read_from_str( + isl_ctx *ctx, const char *str); + +A representation of the schedule can be printed using + + #include <isl/schedule.h> + __isl_give isl_printer *isl_printer_print_schedule( + __isl_take isl_printer *p, + __isl_keep isl_schedule *schedule); + +The schedule tree can be traversed through the use of +C<isl_schedule_node> objects that point to a particular +position in the schedule tree. Whenever a C<isl_schedule_node> +is use to modify a node in the schedule tree, the original schedule +tree is left untouched and the modifications are performed to a copy +of the tree. The returned C<isl_schedule_node> then points to +this modified copy of the tree. + +The root of the schedule tree can be obtained using the following function. + + #include <isl/schedule.h> + __isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule); + +A pointer to a newly created schedule tree with a single domain +node can be created using the following function. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_from_domain( + __isl_take isl_union_set *domain); + +Schedule nodes can be copied and freed using the following functions. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node); + __isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node); + +The following properties can be obtained from a schedule node. + + #include <isl/schedule_node.h> + enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node); + enum isl_schedule_node_type + isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node); + +The function C<isl_schedule_node_get_type> returns the type of +the node, while C<isl_schedule_node_get_parent_type> returns +type of the parent of the node, which is required to exist. +The function C<isl_schedule_node_get_schedule> returns a copy +to the schedule to which the node belongs. + +The following functions can be used to move the schedule node +to a different position in the tree or to check if such a position +exists. + + #include <isl/schedule_node.h> + int isl_schedule_node_has_parent( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node); + int isl_schedule_node_n_children( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos); + int isl_schedule_node_has_children( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node); + int isl_schedule_node_has_previous_sibling( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node); + int isl_schedule_node_has_next_sibling( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node); + +It is also possible to query the number of ancestors of a node, +the position of the current node +within the children of its parent or to obtain a copy of a given +child without destroying the current node. + + #include <isl/schedule_node.h> + int isl_schedule_node_get_tree_depth( + __isl_keep isl_schedule_node *node); + int isl_schedule_node_get_child_position( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos); + +All nodes in a schedule tree or +all descendants of a specific node (including the node) can be visited +in depth-first pre-order using the following functions. + + #include <isl/schedule.h> + int isl_schedule_foreach_schedule_node( + __isl_keep isl_schedule *sched, + int (*fn)(__isl_keep isl_schedule_node *node, + void *user), void *user); + + #include <isl/schedule_node.h> + int isl_schedule_node_foreach_descendant( + __isl_keep isl_schedule_node *node, + int (*fn)(__isl_keep isl_schedule_node *node, + void *user), void *user); + +The callback function is slightly different from the usual +callbacks in that it not only indicates success (non-negative result) +or failure (negative result), but also indicates whether the children +of the given node should be visited. In particular, if the callback +returns a positive value, then the children are visited, but if +the callback returns zero, then the children are not visited. + +The following functions allows for a depth-first post-order +traversal of the nodes in a schedule tree or +of the descendants of a specific node (including the node +itself), where the user callback is allowed to modify the +visited node. + + #include <isl/schedule.h> + __isl_give isl_schedule *isl_schedule_map_schedule_node( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, + void *user), void *user); + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_map_descendant( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, + void *user), void *user); + +The traversal continues from the node returned by the callback function. +It is the responsibility of the user to ensure that this does not +lead to an infinite loop. It is safest to always return a pointer +to the same position (same ancestors and child positions) as the input node. + +Several node types have their own functions for querying +(and in some cases setting) some node type specific properties. + + #include <isl/schedule_node.h> + __isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node); + __isl_give isl_multi_union_pw_aff * + isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node); + unsigned isl_schedule_node_band_n_member( + __isl_keep isl_schedule_node *node); + int isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, + int coincident); + int isl_schedule_node_band_get_permutable( + __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable); + +The function C<isl_schedule_node_band_get_space> returns the space +of the partial schedule of the band. +The function C<isl_schedule_node_band_get_partial_schedule_union_map> +returns a representation of the partial schedule of the band node +in the form of an C<isl_union_map>. +The coincident and permutable properties are set by +C<isl_schedule_constraints_compute_schedule> on the schedule tree +it produces. +A scheduling dimension is considered to be ``coincident'' +if it satisfies the coincidence constraints within its band. +That is, if the dependence distances of the coincidence +constraints are all zero in that direction (for fixed +iterations of outer bands). +A band is marked permutable if it was produced using the Pluto-like scheduler. +Note that the scheduler may have to resort to a Feautrier style scheduling +step even if the default scheduler is used. + + #include <isl/schedule_node.h> + __isl_give isl_union_set * + isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node); + + #include <isl/schedule_node.h> + __isl_give isl_union_set * + isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node); + +The following functions can be used to obtain an C<isl_union_pw_multi_aff> +or C<isl_union_map> representation of partial schedules related to the node. + + #include <isl/schedule_node.h> + __isl_give isl_union_pw_multi_aff * + isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node); + __isl_give isl_union_map * + isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node); + +In particular, the functions +C<isl_schedule_node_get_prefix_schedule_union_pw_multi_aff> +and C<isl_schedule_node_get_prefix_schedule_union_map> +return a relative ordering on the domain elements that reach the given +node determined by its ancestors. +The function C<isl_schedule_node_get_subtree_schedule_union_map> +returns a representation of the partial schedule defined by the +subtree rooted at the given node. + +The following function returns the union of universes in the spaces that +contain elements that reach the given node. + + #include <isl/schedule_node.h> + __isl_give isl_union_set * + isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node); + +The following functions can be used to introduce additional nodes +in the schedule tree. The new node is introduced at the point +in the tree where the C<isl_schedule_node> points to and +the results points to the new node. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *schedule); + +This function inserts a new band node with (the greatest integer +part of) the given partial schedule. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set *filter); + +This function inserts a new filter node with the given filter. +If the original node already pointed to a filter node, then the +two filter nodes are merged into one. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + __isl_give isl_schedule_node * + isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + +These functions insert a new sequence or set node with the given +filters as children. + +The partial schedule of a band node can be scaled (down) using +the following functions. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node * + isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *mv); + __isl_give isl_schedule_node * + isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *mv); + +The spaces of the two arguments need to match. +After scaling, the partial schedule is replaced by its greatest +integer part to ensure that the schedule remains integral. + +A band node can be tiled using the following function. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_val *sizes); + + 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_schedule_node_band_tile> function tiles +the band using the given tile sizes inside its schedule. +A new child band node is created to represent the point loops and it is +inserted between the modified band and its children. +The C<tile_scale_tile_loops> option specifies whether the tile +loops iterators should be scaled by the tile sizes. +If the C<tile_shift_point_loops> option is set, then the point loops +are shifted to start at zero. + +A band node can be split into two nested band nodes +using the following function. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos); + +The resulting outer band node contains the first C<pos> dimensions of +the schedule of C<node> while the inner band contains the remaining dimensions. +The schedules of the two band nodes live in anonymous spaces. + +A band node can be moved down to the leaves of the subtree rooted +at the band node using the following function. + + #include <isl/schedule_node.h> + __isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node); + +The result points to the node in the resulting tree that is in the same +position as the node pointed to by C<node> in the original tree. + +A representation of the schedule node can be printed using + + #include <isl/schedule_node.h> + __isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, + __isl_keep isl_schedule_node *node); + =head2 Dependence Analysis C<isl> contains specialized functionality for performing @@ -6694,8 +7861,6 @@ and may be subject to change.> __isl_give isl_schedule * isl_schedule_constraints_compute_schedule( __isl_take isl_schedule_constraints *sc); - __isl_null isl_schedule *isl_schedule_free( - __isl_take isl_schedule *sched); The function C<isl_schedule_constraints_compute_schedule> can be used to compute a schedule that satisfies the given schedule constraints. @@ -6731,6 +7896,10 @@ and manipulated using the following functions. isl_schedule_constraints_on_domain( __isl_take isl_union_set *domain); __isl_give isl_schedule_constraints * + isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, + __isl_take isl_set *context); + __isl_give isl_schedule_constraints * isl_schedule_constraints_set_validity( __isl_take isl_schedule_constraints *sc, __isl_take isl_union_map *validity); @@ -6754,6 +7923,9 @@ and manipulated using the following functions. The initial C<isl_schedule_constraints> object created by C<isl_schedule_constraints_on_domain> does not impose any constraints. That is, it has an empty set of dependences. +The function C<isl_schedule_constraints_set_context> allows the user +to specify additional constraints on the parameters that may +be assumed to hold during the construction of the schedule. The function C<isl_schedule_constraints_set_validity> replaces the validity dependences, mapping domain elements I<i> to domain elements that should be scheduled after I<i>. @@ -6800,17 +7972,9 @@ The use of C<isl_union_set_compute_schedule> is discouraged. __isl_take isl_union_map *validity, __isl_take isl_union_map *proximity); -A mapping from the domains to the scheduled space can be obtained -from an C<isl_schedule> using the following function. - - __isl_give isl_union_map *isl_schedule_get_map( - __isl_keep isl_schedule *sched); - -A representation of the schedule can be printed using - - __isl_give isl_printer *isl_printer_print_schedule( - __isl_take isl_printer *p, - __isl_keep isl_schedule *schedule); +The generated schedule represents a schedule tree. +For more information on schedule trees, see +L</"Schedule Trees">. A representation of the schedule as a forest of bands can be obtained using the following function. @@ -6818,6 +7982,10 @@ using the following function. __isl_give isl_band_list *isl_schedule_get_band_forest( __isl_keep isl_schedule *schedule); +If the input schedule is represented by a schedule tree, then a call +to C<isl_schedule_get_band_forest> replaces the internal schedule tree +representation by a band forest representation. + The individual bands can be visited in depth-first post-order using the following function. @@ -7011,12 +8179,8 @@ and C<ISL_SCHEDULE_ALGORITHM_FEAUTRIER>. =item * schedule_separate_components -If at any point the dependence graph contains any (weakly connected) components, -then these components are scheduled separately. -If this option is not set, then some iterations of the domains -in these components may be scheduled together. -If this option is set, then the components are given consecutive -schedules. +If this option is set then the function C<isl_schedule_get_map> +will treat set nodes in the same way as sequence nodes. =back diff --git a/polly/lib/External/isl/include/isl/aff.h b/polly/lib/External/isl/include/isl/aff.h index 4ed02854d1c..949474e895c 100644 --- a/polly/lib/External/isl/include/isl/aff.h +++ b/polly/lib/External/isl/include/isl/aff.h @@ -200,6 +200,7 @@ __isl_give isl_pw_aff *isl_pw_aff_set_tuple_id(__isl_take isl_pw_aff *pwaff, enum isl_dim_type type, __isl_take isl_id *id); __isl_give isl_pw_aff *isl_pw_aff_reset_tuple_id(__isl_take isl_pw_aff *pa, enum isl_dim_type type); +__isl_give isl_pw_aff *isl_pw_aff_reset_user(__isl_take isl_pw_aff *pa); __isl_give isl_set *isl_pw_aff_params(__isl_take isl_pw_aff *pwa); __isl_give isl_set *isl_pw_aff_domain(__isl_take isl_pw_aff *pwaff); @@ -231,6 +232,8 @@ __isl_give isl_pw_aff *isl_pw_aff_intersect_params(__isl_take isl_pw_aff *pa, __isl_take isl_set *set); __isl_give isl_pw_aff *isl_pw_aff_intersect_domain(__isl_take isl_pw_aff *pa, __isl_take isl_set *set); +__isl_give isl_pw_aff *isl_pw_aff_subtract_domain(__isl_take isl_pw_aff *pa, + __isl_take isl_set *set); __isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false); @@ -271,6 +274,7 @@ int isl_pw_aff_foreach_piece(__isl_keep isl_pw_aff *pwaff, __isl_give isl_set *isl_set_from_pw_aff(__isl_take isl_pw_aff *pwaff); __isl_give isl_map *isl_map_from_pw_aff(__isl_take isl_pw_aff *pwaff); +__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa); __isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff); __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff); __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff); @@ -288,6 +292,13 @@ __isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, __isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); +__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); +__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2); + __isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str); __isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p, __isl_keep isl_pw_aff *pwaff); @@ -310,6 +321,9 @@ __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_DECLARE_MULTI_NEG(aff) +ISL_DECLARE_MULTI_DIMS(aff) +ISL_DECLARE_MULTI_WITH_DOMAIN(aff) __isl_give isl_multi_aff *isl_multi_aff_from_aff(__isl_take isl_aff *aff); __isl_give isl_multi_aff *isl_multi_aff_identity(__isl_take isl_space *space); @@ -326,8 +340,6 @@ __isl_give isl_multi_aff *isl_multi_aff_floor(__isl_take isl_multi_aff *ma); __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_product( __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2); @@ -361,10 +373,15 @@ __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, void isl_multi_aff_dump(__isl_keep isl_multi_aff *maff); ISL_DECLARE_MULTI(pw_aff) +ISL_DECLARE_MULTI_NEG(pw_aff) +ISL_DECLARE_MULTI_DIMS(pw_aff) +ISL_DECLARE_MULTI_WITH_DOMAIN(pw_aff) __isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space); __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_range_map( + __isl_take isl_space *space); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map( __isl_take isl_space *space, enum isl_dim_type type, unsigned first, unsigned n); @@ -405,6 +422,8 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id( enum isl_dim_type type, __isl_take isl_id *id); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_tuple_id( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type); +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user( + __isl_take isl_pw_multi_aff *pma); int isl_pw_multi_aff_find_dim_by_name(__isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type, const char *name); @@ -441,6 +460,9 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_fix_si( __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_pw_multi_aff *isl_pw_multi_aff_neg( + __isl_take isl_pw_multi_aff *pma); + __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( @@ -474,6 +496,8 @@ __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_pw_multi_aff *isl_pw_multi_aff_subtract_domain( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_domain_on_params( __isl_take isl_pw_multi_aff *pma); @@ -513,6 +537,8 @@ void isl_pw_multi_aff_dump(__isl_keep isl_pw_multi_aff *pma); __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_empty( __isl_take isl_space *space); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff); __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_pw_multi_aff( __isl_take isl_pw_multi_aff *pma); __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain( @@ -524,6 +550,12 @@ __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_copy( __isl_null isl_union_pw_multi_aff *isl_union_pw_multi_aff_free( __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset); + +__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos); + __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add_pw_multi_aff( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_pw_multi_aff *pma); @@ -535,10 +567,20 @@ __isl_give isl_space *isl_union_pw_multi_aff_get_space( unsigned isl_union_pw_multi_aff_dim(__isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_set_dim_name( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned pos, const char *s); + int isl_union_pw_multi_aff_find_dim_by_name( __isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type, const char *name); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_drop_dims( + __isl_take isl_union_pw_multi_aff *upma, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_reset_user( + __isl_take isl_union_pw_multi_aff *upma); + __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_coalesce( __isl_take isl_union_pw_multi_aff *upma); __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist_params( @@ -547,9 +589,17 @@ __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_union_set *context); +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __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_align_params( __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *model); +int isl_union_pw_multi_aff_n_pw_multi_aff( + __isl_keep isl_union_pw_multi_aff *upma); + int isl_union_pw_multi_aff_foreach_pw_multi_aff( __isl_keep isl_union_pw_multi_aff *upma, int (*fn)(__isl_take isl_pw_multi_aff *pma, void *user), void *user); @@ -563,6 +613,9 @@ int isl_union_pw_multi_aff_plain_is_equal( __isl_give isl_union_set *isl_union_pw_multi_aff_domain( __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_neg( + __isl_take isl_union_pw_multi_aff *upma); + __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); @@ -589,6 +642,9 @@ __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_params( __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_pw_multi_aff *isl_union_pw_multi_aff_subtract_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); @@ -648,12 +704,208 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff( __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff( __isl_take isl_pw_multi_aff *pma); +__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2); + __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, const char *str); __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); +__isl_give isl_union_pw_aff *isl_union_pw_aff_copy( + __isl_keep isl_union_pw_aff *upa); +__isl_null isl_union_pw_aff *isl_union_pw_aff_free( + __isl_take isl_union_pw_aff *upa); + +isl_ctx *isl_union_pw_aff_get_ctx(__isl_keep isl_union_pw_aff *upa); +__isl_give isl_space *isl_union_pw_aff_get_space( + __isl_keep isl_union_pw_aff *upa); + +unsigned isl_union_pw_aff_dim(__isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type); +__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, enum isl_dim_type type, + unsigned pos, const char *s); + +int isl_union_pw_aff_find_dim_by_name(__isl_keep isl_union_pw_aff *upa, + enum isl_dim_type type, const char *name); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_empty( + __isl_take isl_space *space); +__isl_give isl_union_pw_aff *isl_union_pw_aff_from_pw_aff( + __isl_take isl_pw_aff *pa); +__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_aff *aff); +__isl_give isl_union_pw_aff *isl_union_pw_aff_add_pw_aff( + __isl_take isl_union_pw_aff *upa, __isl_take isl_pw_aff *pa); + +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + +int isl_union_pw_aff_n_pw_aff(__isl_keep isl_union_pw_aff *upa); + +int isl_union_pw_aff_foreach_pw_aff(__isl_keep isl_union_pw_aff *upa, + int (*fn)(__isl_take isl_pw_aff *ma, void *user), void *user); +__isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff( + __isl_keep isl_union_pw_aff *upa, __isl_take isl_space *space); + +int isl_union_pw_aff_plain_is_equal(__isl_keep isl_union_pw_aff *upa1, + __isl_keep isl_union_pw_aff *upa2); + +__isl_give isl_union_set *isl_union_pw_aff_domain( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_neg( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); +__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); +__isl_give isl_union_pw_aff *isl_union_pw_aff_sub( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce( + __isl_take isl_union_pw_aff *upa); +__isl_give isl_union_pw_aff *isl_union_pw_aff_gist( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *context); +__isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_set *context); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *v); +__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *f); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_align_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_space *model); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_params( + __isl_take isl_union_pw_aff *upa, __isl_take isl_set *set); +__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_domain( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset); +__isl_give isl_union_pw_aff *isl_union_pw_aff_subtract_domain( + __isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset); + +__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name( + __isl_take isl_union_pw_aff *upa, + enum isl_dim_type type, unsigned pos, const char *s); + +__isl_give isl_union_set *isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa); + +__isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); + +__isl_give char *isl_union_pw_aff_to_str(__isl_keep isl_union_pw_aff *upa); +__isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa); + +ISL_DECLARE_MULTI(union_pw_aff) +ISL_DECLARE_MULTI_NEG(union_pw_aff) + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_floor( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_domain( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_set *uset); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_params( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *params); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *set); + +__isl_give isl_union_set *isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist( + __isl_take isl_multi_union_pw_aff *aff, + __isl_take isl_union_set *context); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist_params( + __isl_take isl_multi_union_pw_aff *aff, __isl_take isl_set *context); + +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma); +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma); + +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2); + +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa); + +__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space); + +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str); +__isl_give char *isl_multi_union_pw_aff_to_str( + __isl_keep isl_multi_union_pw_aff *mupa); +__isl_give isl_printer *isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa); +void isl_multi_union_pw_aff_dump(__isl_keep isl_multi_union_pw_aff *mupa); + +ISL_DECLARE_LIST_FN(union_pw_aff) +ISL_DECLARE_LIST_FN(union_pw_multi_aff) + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/aff_type.h b/polly/lib/External/isl/include/isl/aff_type.h index ce19f1dfa18..12daf9431e0 100644 --- a/polly/lib/External/isl/include/isl/aff_type.h +++ b/polly/lib/External/isl/include/isl/aff_type.h @@ -17,6 +17,11 @@ typedef struct isl_pw_aff isl_pw_aff; ISL_DECLARE_LIST(pw_aff) +struct isl_union_pw_aff; +typedef struct isl_union_pw_aff isl_union_pw_aff; + +ISL_DECLARE_LIST_TYPE(union_pw_aff) + struct isl_multi_aff; typedef struct isl_multi_aff isl_multi_aff; @@ -26,9 +31,14 @@ typedef struct isl_pw_multi_aff isl_pw_multi_aff; struct isl_union_pw_multi_aff; typedef struct isl_union_pw_multi_aff isl_union_pw_multi_aff; +ISL_DECLARE_LIST_TYPE(union_pw_multi_aff) + struct isl_multi_pw_aff; typedef struct isl_multi_pw_aff isl_multi_pw_aff; +struct isl_multi_union_pw_aff; +typedef struct isl_multi_union_pw_aff isl_multi_union_pw_aff; + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/local_space.h b/polly/lib/External/isl/include/isl/local_space.h index 57ac83f10dd..61d1d74f5dc 100644 --- a/polly/lib/External/isl/include/isl/local_space.h +++ b/polly/lib/External/isl/include/isl/local_space.h @@ -70,6 +70,9 @@ __isl_give isl_local_space *isl_local_space_insert_dims( __isl_give isl_local_space *isl_local_space_intersect( __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2); +__isl_give isl_local_space *isl_local_space_wrap( + __isl_take isl_local_space *ls); + int isl_local_space_is_equal(__isl_keep isl_local_space *ls1, __isl_keep isl_local_space *ls2); diff --git a/polly/lib/External/isl/include/isl/map.h b/polly/lib/External/isl/include/isl/map.h index a31ddfc8e16..9c82ea92c72 100644 --- a/polly/lib/External/isl/include/isl/map.h +++ b/polly/lib/External/isl/include/isl/map.h @@ -147,6 +147,8 @@ __isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map); __isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map); __isl_give isl_basic_map *isl_map_unshifted_simple_hull( __isl_take isl_map *map); +__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, __isl_take isl_map_list *list); __isl_export __isl_give isl_basic_map *isl_basic_map_intersect_domain( @@ -160,6 +162,8 @@ __isl_export __isl_give isl_basic_map *isl_basic_map_intersect( __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list); __isl_export __isl_give isl_map *isl_basic_map_union( __isl_take isl_basic_map *bmap1, @@ -211,11 +215,7 @@ __isl_give isl_map *isl_map_read_from_file(isl_ctx *ctx, FILE *input); __isl_constructor __isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx, const char *str); void isl_basic_map_dump(__isl_keep isl_basic_map *bmap); -void isl_basic_map_print(__isl_keep isl_basic_map *bmap, FILE *out, int indent, - const char *prefix, const char *suffix, unsigned output_format); void isl_map_dump(__isl_keep isl_map *map); -void isl_map_print(__isl_keep isl_map *map, FILE *out, int indent, - unsigned output_format); __isl_give isl_printer *isl_printer_print_basic_map( __isl_take isl_printer *printer, __isl_keep isl_basic_map *bmap); __isl_give char *isl_map_to_str(__isl_keep isl_map *map); @@ -609,6 +609,8 @@ void isl_map_print_internal(__isl_keep isl_map *map, FILE *out, int indent); __isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos); +__isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context); __isl_export __isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context); @@ -688,6 +690,9 @@ __isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff); __isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos); +ISL_DECLARE_LIST_FN(basic_map) +ISL_DECLARE_LIST_FN(map) + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/map_type.h b/polly/lib/External/isl/include/isl/map_type.h index 148dc0d3c70..7c30056f71e 100644 --- a/polly/lib/External/isl/include/isl/map_type.h +++ b/polly/lib/External/isl/include/isl/map_type.h @@ -10,8 +10,10 @@ extern "C" { struct __isl_subclass(isl_map) isl_basic_map; typedef struct isl_basic_map isl_basic_map; +ISL_DECLARE_LIST_TYPE(basic_map) struct __isl_subclass(isl_union_map) isl_map; typedef struct isl_map isl_map; +ISL_DECLARE_LIST_TYPE(map) #ifndef isl_basic_set struct __isl_subclass(isl_set) isl_basic_set; diff --git a/polly/lib/External/isl/include/isl/multi.h b/polly/lib/External/isl/include/isl/multi.h index ddcdc20fabd..ee0d8cd3694 100644 --- a/polly/lib/External/isl/include/isl/multi.h +++ b/polly/lib/External/isl/include/isl/multi.h @@ -60,15 +60,6 @@ __isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_tuple_id( \ __isl_take isl_multi_##BASE *multi, enum isl_dim_type type); \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_user( \ __isl_take isl_multi_##BASE *multi); \ -int isl_multi_##BASE##_involves_dims( \ - __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type, \ - unsigned first, unsigned n); \ -__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); \ @@ -80,9 +71,6 @@ __isl_give isl_multi_##BASE *isl_multi_##BASE##_set_##BASE( \ __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##_flatten_range( \ __isl_take isl_multi_##BASE *multi); \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product( \ @@ -91,9 +79,6 @@ __isl_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product( \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_range_product( \ __isl_take isl_multi_##BASE *multi1, \ __isl_take isl_multi_##BASE *multi2); \ -__isl_give isl_multi_##BASE *isl_multi_##BASE##_product( \ - __isl_take isl_multi_##BASE *multi1, \ - __isl_take isl_multi_##BASE *multi2); \ int isl_multi_##BASE##_range_is_wrapping( \ __isl_keep isl_multi_##BASE *multi); \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_range_factor_domain( \ @@ -110,12 +95,41 @@ __isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_multi_val( \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_down_multi_val( \ __isl_take isl_multi_##BASE *multi, \ __isl_take isl_multi_val *mv); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_mod_multi_val( \ + __isl_take isl_multi_##BASE *multi, \ + __isl_take isl_multi_val *mv); \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_sub( \ + __isl_take isl_multi_##BASE *multi1, \ + __isl_take isl_multi_##BASE *multi2); \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_align_params( \ __isl_take isl_multi_##BASE *multi, \ __isl_take isl_space *model); \ __isl_give isl_multi_##BASE *isl_multi_##BASE##_from_range( \ __isl_take isl_multi_##BASE *multi); +#define ISL_DECLARE_MULTI_NEG(BASE) \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_neg( \ + __isl_take isl_multi_##BASE *multi); + +#define ISL_DECLARE_MULTI_DIMS(BASE) \ +int isl_multi_##BASE##_involves_dims( \ + __isl_keep isl_multi_##BASE *multi, enum isl_dim_type type, \ + unsigned first, unsigned n); \ +__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); + +#define ISL_DECLARE_MULTI_WITH_DOMAIN(BASE) \ +__isl_give isl_multi_##BASE *isl_multi_##BASE##_product( \ + __isl_take isl_multi_##BASE *multi1, \ + __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); + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/obj.h b/polly/lib/External/isl/include/isl/obj.h index 7c796f3473e..07c6bf38c66 100644 --- a/polly/lib/External/isl/include/isl/obj.h +++ b/polly/lib/External/isl/include/isl/obj.h @@ -43,6 +43,8 @@ extern struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable; #define isl_obj_pw_qpolynomial_fold (&isl_obj_pw_qpolynomial_fold_vtable) extern struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable; #define isl_obj_union_pw_qpolynomial_fold (&isl_obj_union_pw_qpolynomial_fold_vtable) +extern struct isl_obj_vtable isl_obj_schedule_vtable; +#define isl_obj_schedule (&isl_obj_schedule_vtable) struct isl_obj { isl_obj_type type; void *v; diff --git a/polly/lib/External/isl/include/isl/polynomial.h b/polly/lib/External/isl/include/isl/polynomial.h index f7b55a55bf7..4ccdcb4f20f 100644 --- a/polly/lib/External/isl/include/isl/polynomial.h +++ b/polly/lib/External/isl/include/isl/polynomial.h @@ -170,11 +170,16 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_set_dim_name( int isl_pw_qpolynomial_find_dim_by_name(__isl_keep isl_pw_qpolynomial *pwqp, enum isl_dim_type type, const char *name); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_user( + __isl_take isl_pw_qpolynomial *pwqp); + __isl_give isl_set *isl_pw_qpolynomial_domain(__isl_take isl_pw_qpolynomial *pwqp); __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_domain( __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_params( __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_subtract_domain( + __isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set); __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_domain_on_params( __isl_take isl_pw_qpolynomial *pwqp); @@ -361,12 +366,17 @@ int isl_pw_qpolynomial_fold_find_dim_by_name( __isl_keep isl_pw_qpolynomial_fold *pwf, enum isl_dim_type type, const char *name); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_user( + __isl_take isl_pw_qpolynomial_fold *pwf); + __isl_give isl_set *isl_pw_qpolynomial_fold_domain( __isl_take isl_pw_qpolynomial_fold *pwf); __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_domain( __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_params( __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); +__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set); __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add( __isl_take isl_pw_qpolynomial_fold *pwf1, @@ -486,14 +496,27 @@ __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_domain( __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_params( __isl_take isl_union_pw_qpolynomial *upwpq, __isl_take isl_set *set); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_subtract_domain( + __isl_take isl_union_pw_qpolynomial *upwpq, + __isl_take isl_union_set *uset); __isl_give isl_space *isl_union_pw_qpolynomial_get_space( __isl_keep isl_union_pw_qpolynomial *upwqp); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_set_dim_name( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned pos, const char *s); + int isl_union_pw_qpolynomial_find_dim_by_name( __isl_keep isl_union_pw_qpolynomial *upwqp, enum isl_dim_type type, const char *name); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_drop_dims( + __isl_take isl_union_pw_qpolynomial *upwqp, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_reset_user( + __isl_take isl_union_pw_qpolynomial *upwqp); + __isl_give isl_val *isl_union_pw_qpolynomial_eval( __isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_point *pnt); @@ -510,6 +533,8 @@ __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_align_params( __isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_space *model); +int isl_union_pw_qpolynomial_n_pw_qpolynomial( + __isl_keep isl_union_pw_qpolynomial *upwqp); int isl_union_pw_qpolynomial_foreach_pw_qpolynomial( __isl_keep isl_union_pw_qpolynomial *upwqp, int (*fn)(__isl_take isl_pw_qpolynomial *pwqp, void *user), void *user); @@ -562,16 +587,33 @@ __isl_give isl_union_pw_qpolynomial_fold * isl_union_pw_qpolynomial_fold_intersect_params( __isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_set *set); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_subtract_domain( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + __isl_take isl_union_set *uset); enum isl_fold isl_union_pw_qpolynomial_fold_get_type( __isl_keep isl_union_pw_qpolynomial_fold *upwf); __isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space( __isl_keep isl_union_pw_qpolynomial_fold *upwf); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_set_dim_name( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned pos, const char *s); + int isl_union_pw_qpolynomial_fold_find_dim_by_name( __isl_keep isl_union_pw_qpolynomial_fold *upwf, enum isl_dim_type type, const char *name); +__isl_give isl_union_pw_qpolynomial_fold * + isl_union_pw_qpolynomial_fold_drop_dims( + __isl_take isl_union_pw_qpolynomial_fold *upwf, + enum isl_dim_type type, unsigned first, unsigned n); +__isl_give isl_union_pw_qpolynomial_fold * +isl_union_pw_qpolynomial_fold_reset_user( + __isl_take isl_union_pw_qpolynomial_fold *upwf); + __isl_give isl_val *isl_union_pw_qpolynomial_fold_eval( __isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_point *pnt); @@ -590,6 +632,8 @@ __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_align_pa __isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_space *model); +int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold( + __isl_keep isl_union_pw_qpolynomial_fold *upwf); int isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold( __isl_keep isl_union_pw_qpolynomial_fold *upwf, int (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf, diff --git a/polly/lib/External/isl/include/isl/printer.h b/polly/lib/External/isl/include/isl/printer.h index f43bfbc5f24..f5b2f43ca5e 100644 --- a/polly/lib/External/isl/include/isl/printer.h +++ b/polly/lib/External/isl/include/isl/printer.h @@ -36,6 +36,12 @@ __isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p, int output_format); int isl_printer_get_output_format(__isl_keep isl_printer *p); +#define ISL_YAML_STYLE_BLOCK 0 +#define ISL_YAML_STYLE_FLOW 1 +__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p, + int yaml_style); +int isl_printer_get_yaml_style(__isl_keep isl_printer *p); + __isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p, const char *prefix); __isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p, @@ -53,6 +59,16 @@ __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i); __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p, const char *s); +__isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p); +__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p); + __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p); #if defined(__cplusplus) diff --git a/polly/lib/External/isl/include/isl/schedule.h b/polly/lib/External/isl/include/isl/schedule.h index 83b89d910c2..045c5f84828 100644 --- a/polly/lib/External/isl/include/isl/schedule.h +++ b/polly/lib/External/isl/include/isl/schedule.h @@ -3,7 +3,9 @@ #include <isl/union_set_type.h> #include <isl/union_map_type.h> +#include <isl/schedule_type.h> #include <isl/band.h> +#include <isl/space.h> #include <isl/list.h> #if defined(__cplusplus) @@ -12,8 +14,6 @@ extern "C" { struct isl_schedule_constraints; typedef struct isl_schedule_constraints isl_schedule_constraints; -struct isl_schedule; -typedef struct isl_schedule isl_schedule; int isl_options_set_schedule_max_coefficient(isl_ctx *ctx, int val); int isl_options_get_schedule_max_coefficient(isl_ctx *ctx); @@ -42,6 +42,8 @@ __isl_give isl_schedule_constraints *isl_schedule_constraints_copy( __isl_keep isl_schedule_constraints *sc); __isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain( __isl_take isl_union_set *domain); +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, __isl_take isl_set *context); __isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity( __isl_take isl_schedule_constraints *sc, __isl_take isl_union_map *validity); @@ -71,14 +73,34 @@ __isl_give isl_schedule *isl_union_set_compute_schedule( __isl_take isl_union_set *domain, __isl_take isl_union_map *validity, __isl_take isl_union_map *proximity); + +__isl_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space); +__isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched); __isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched); __isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched); isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *sched); +__isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule); +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); + +int isl_schedule_foreach_schedule_node(__isl_keep isl_schedule *sched, + int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user); +__isl_give isl_schedule *isl_schedule_map_schedule_node( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, void *user), void *user); + __isl_give isl_band_list *isl_schedule_get_band_forest( __isl_keep isl_schedule *schedule); +__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input); +__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx, + const char *str); __isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p, __isl_keep isl_schedule *schedule); void isl_schedule_dump(__isl_keep isl_schedule *schedule); diff --git a/polly/lib/External/isl/include/isl/schedule_node.h b/polly/lib/External/isl/include/isl/schedule_node.h new file mode 100644 index 00000000000..531314f0aab --- /dev/null +++ b/polly/lib/External/isl/include/isl/schedule_node.h @@ -0,0 +1,123 @@ +#ifndef ISL_SCHEDULE_NODE_H +#define ISL_SCHEDULE_NODE_H + +#include <isl/schedule_type.h> +#include <isl/union_set_type.h> +#include <isl/aff_type.h> +#include <isl/val.h> +#include <isl/space.h> + +#if defined(__cplusplus) +extern "C" { +#endif + +__isl_give isl_schedule_node *isl_schedule_node_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node); +__isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node); + +isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node); +enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node); +enum isl_schedule_node_type isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node); +__isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node); + +int isl_schedule_node_foreach_descendant(__isl_keep isl_schedule_node *node, + int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user); +__isl_give isl_schedule_node *isl_schedule_node_map_descendant( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user), void *user); + +int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node); +int isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node); +int isl_schedule_node_has_children(__isl_keep isl_schedule_node *node); +int isl_schedule_node_has_previous_sibling(__isl_keep isl_schedule_node *node); +int isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node); +int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node); +int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos); + +__isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node); + +__isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node); +__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node); +unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node); +int isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, int coincident); +int isl_schedule_node_band_get_permutable(__isl_keep isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable); + +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); + +__isl_give isl_schedule_node *isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_node *isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos); + +__isl_give isl_union_set *isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_set *isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node); + +__isl_give isl_union_set *isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_pw_multi_aff * +isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node); +__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node); + +__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *schedule); +__isl_give isl_schedule_node *isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter); +__isl_give isl_schedule_node *isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); +__isl_give isl_schedule_node *isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters); + +__isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, __isl_keep isl_schedule_node *node); +void isl_schedule_node_dump(__isl_keep isl_schedule_node *node); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/polly/lib/External/isl/include/isl/schedule_type.h b/polly/lib/External/isl/include/isl/schedule_type.h new file mode 100644 index 00000000000..d9003cdbbb0 --- /dev/null +++ b/polly/lib/External/isl/include/isl/schedule_type.h @@ -0,0 +1,28 @@ +#ifndef ISL_SCHEDULE_TYPE_H +#define ISL_SCHEDULE_TYPE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +enum isl_schedule_node_type { + isl_schedule_node_error = -1, + isl_schedule_node_band, + isl_schedule_node_domain, + isl_schedule_node_filter, + isl_schedule_node_leaf, + isl_schedule_node_sequence, + isl_schedule_node_set +}; + +struct isl_schedule_node; +typedef struct isl_schedule_node isl_schedule_node; + +struct isl_schedule; +typedef struct isl_schedule isl_schedule; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/polly/lib/External/isl/include/isl/set.h b/polly/lib/External/isl/include/isl/set.h index 73b6570621f..36589556e27 100644 --- a/polly/lib/External/isl/include/isl/set.h +++ b/polly/lib/External/isl/include/isl/set.h @@ -158,10 +158,6 @@ __isl_give isl_printer *isl_printer_print_basic_set( __isl_take isl_printer *printer, __isl_keep isl_basic_set *bset); __isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *printer, __isl_keep isl_set *map); -void isl_basic_set_print(__isl_keep isl_basic_set *bset, FILE *out, int indent, - const char *prefix, const char *suffix, unsigned output_format); -void isl_set_print(__isl_keep struct isl_set *set, FILE *out, int indent, - unsigned output_format); __isl_give isl_basic_set *isl_basic_set_fix_si(__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, int value); __isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset, diff --git a/polly/lib/External/isl/include/isl/stream.h b/polly/lib/External/isl/include/isl/stream.h index 42734996780..603ae25ba75 100644 --- a/polly/lib/External/isl/include/isl/stream.h +++ b/polly/lib/External/isl/include/isl/stream.h @@ -15,6 +15,7 @@ #include <isl/aff_type.h> #include <isl/obj.h> #include <isl/val.h> +#include <isl/schedule_type.h> #if defined(__cplusplus) extern "C" { @@ -46,55 +47,47 @@ __isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok); int isl_token_get_type(struct isl_token *tok); void isl_token_free(struct isl_token *tok); -struct isl_stream { - struct isl_ctx *ctx; - FILE *file; - const char *str; - int line; - int col; - int eof; - - char *buffer; - size_t size; - size_t len; - int c; - int un[5]; - int n_un; - - struct isl_token *tokens[5]; - int n_token; - - struct isl_hash_table *keywords; - enum isl_token_type next_type; -}; - -struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file); -struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str); -void isl_stream_free(struct isl_stream *s); - -void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg); - -struct isl_token *isl_stream_next_token(struct isl_stream *s); -struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s); -int isl_stream_next_token_is(struct isl_stream *s, int type); -void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok); -void isl_stream_flush_tokens(struct isl_stream *s); -int isl_stream_eat_if_available(struct isl_stream *s, int type); -char *isl_stream_read_ident_if_available(struct isl_stream *s); -int isl_stream_eat(struct isl_stream *s, int type); -int isl_stream_is_empty(struct isl_stream *s); -int isl_stream_skip_line(struct isl_stream *s); - -enum isl_token_type isl_stream_register_keyword(struct isl_stream *s, +struct isl_stream; +typedef struct isl_stream isl_stream; + +__isl_give isl_stream *isl_stream_new_file(isl_ctx *ctx, FILE *file); +__isl_give isl_stream *isl_stream_new_str(isl_ctx *ctx, const char *str); +void isl_stream_free(__isl_take isl_stream *s); + +isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s); + +void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok, + char *msg); + +struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s); +struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s); +int isl_stream_next_token_is(__isl_keep isl_stream *s, int type); +void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok); +void isl_stream_flush_tokens(__isl_keep isl_stream *s); +int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type); +char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s); +int isl_stream_eat(__isl_keep isl_stream *s, int type); +int isl_stream_is_empty(__isl_keep isl_stream *s); +int isl_stream_skip_line(__isl_keep isl_stream *s); + +enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, const char *name); -struct isl_obj isl_stream_read_obj(struct isl_stream *s); -__isl_give isl_multi_aff *isl_stream_read_multi_aff(struct isl_stream *s); -__isl_give isl_map *isl_stream_read_map(struct isl_stream *s); -__isl_give isl_set *isl_stream_read_set(struct isl_stream *s); +struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s); +__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s); +__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s); +__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s); +__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s); __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial( - struct isl_stream *s); -__isl_give isl_union_map *isl_stream_read_union_map(struct isl_stream *s); + __isl_keep isl_stream *s); +__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s); +__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s); + +int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s); +int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s); +int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s); +int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s); +int isl_stream_yaml_next(__isl_keep isl_stream *s); #if defined(__cplusplus) } diff --git a/polly/lib/External/isl/include/isl/union_map.h b/polly/lib/External/isl/include/isl/union_map.h index 2d4d94cd3b3..5c0bbf553f8 100644 --- a/polly/lib/External/isl/include/isl/union_map.h +++ b/polly/lib/External/isl/include/isl/union_map.h @@ -43,6 +43,8 @@ __isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap); __isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap); __isl_give isl_union_map *isl_union_map_domain_map( __isl_take isl_union_map *umap); +__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap); __isl_give isl_union_map *isl_union_map_range_map( __isl_take isl_union_map *umap); __isl_give isl_union_map *isl_union_set_wrapped_domain_map( @@ -58,6 +60,8 @@ __isl_give isl_union_map *isl_union_map_affine_hull( __isl_export __isl_give isl_union_map *isl_union_map_polyhedral_hull( __isl_take isl_union_map *umap); +__isl_give isl_union_map *isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap); __isl_give isl_union_map *isl_union_map_simple_hull( __isl_take isl_union_map *umap); __isl_export @@ -88,6 +92,8 @@ __isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); __isl_give isl_union_map *isl_union_map_domain_product( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); __isl_give isl_union_map *isl_union_map_range_product( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); __isl_give isl_union_map *isl_union_map_flat_range_product( @@ -186,6 +192,8 @@ int isl_union_map_is_subset(__isl_keep isl_union_map *umap1, __isl_export int isl_union_map_is_equal(__isl_keep isl_union_map *umap1, __isl_keep isl_union_map *umap2); +int isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2); __isl_export int isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1, __isl_keep isl_union_map *umap2); @@ -218,6 +226,16 @@ __isl_give isl_union_map *isl_union_map_lex_gt_union_map( __isl_give isl_union_map *isl_union_map_lex_ge_union_map( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2); +__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa); + __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, FILE *input); __isl_constructor @@ -240,6 +258,8 @@ __isl_give isl_union_map *isl_union_map_align_params( __isl_give isl_union_set *isl_union_set_align_params( __isl_take isl_union_set *uset, __isl_take isl_space *model); +ISL_DECLARE_LIST_FN(union_map) + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/union_map_type.h b/polly/lib/External/isl/include/isl/union_map_type.h index e93f2cc7137..72fdffdf4f1 100644 --- a/polly/lib/External/isl/include/isl/union_map_type.h +++ b/polly/lib/External/isl/include/isl/union_map_type.h @@ -2,6 +2,7 @@ #define ISL_UNION_MAP_TYPE_H #include <isl/ctx.h> +#include <isl/list.h> #if defined(__cplusplus) extern "C" { @@ -9,9 +10,11 @@ extern "C" { struct __isl_export isl_union_map; typedef struct isl_union_map isl_union_map; +ISL_DECLARE_LIST_TYPE(union_map) #ifndef isl_union_set struct __isl_export isl_union_set; typedef struct isl_union_set isl_union_set; +ISL_DECLARE_LIST_TYPE(union_set) #endif #if defined(__cplusplus) diff --git a/polly/lib/External/isl/include/isl/union_set.h b/polly/lib/External/isl/include/isl/union_set.h index 616acb8011c..52985d411a8 100644 --- a/polly/lib/External/isl/include/isl/union_set.h +++ b/polly/lib/External/isl/include/isl/union_set.h @@ -39,6 +39,8 @@ __isl_give isl_union_set *isl_union_set_affine_hull( __isl_export __isl_give isl_union_set *isl_union_set_polyhedral_hull( __isl_take isl_union_set *uset); +__isl_give isl_union_set *isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset); __isl_give isl_union_set *isl_union_set_simple_hull( __isl_take isl_union_set *uset); __isl_export @@ -84,6 +86,10 @@ __isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff( __isl_take isl_union_set *uset, __isl_take isl_union_pw_multi_aff *upma); +__isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, unsigned first, unsigned n); + int isl_union_set_is_params(__isl_keep isl_union_set *uset); __isl_export int isl_union_set_is_empty(__isl_keep isl_union_set *uset); @@ -94,6 +100,8 @@ int isl_union_set_is_subset(__isl_keep isl_union_set *uset1, __isl_export int isl_union_set_is_equal(__isl_keep isl_union_set *uset1, __isl_keep isl_union_set *uset2); +int isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2); __isl_export int isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1, __isl_keep isl_union_set *uset2); @@ -138,6 +146,11 @@ __isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p, __isl_keep isl_union_set *uset); void isl_union_set_dump(__isl_keep isl_union_set *uset); +ISL_DECLARE_LIST_FN(union_set) + +__isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list); + #if defined(__cplusplus) } #endif diff --git a/polly/lib/External/isl/include/isl/val.h b/polly/lib/External/isl/include/isl/val.h index 238f0c282cf..4353c1087a1 100644 --- a/polly/lib/External/isl/include/isl/val.h +++ b/polly/lib/External/isl/include/isl/val.h @@ -19,6 +19,9 @@ struct isl_multi_val; typedef struct isl_multi_val isl_multi_val; ISL_DECLARE_MULTI(val) +ISL_DECLARE_MULTI_NEG(val) +ISL_DECLARE_MULTI_DIMS(val) +ISL_DECLARE_MULTI_WITH_DOMAIN(val) __isl_give isl_val *isl_val_zero(isl_ctx *ctx); __isl_give isl_val *isl_val_one(isl_ctx *ctx); @@ -102,6 +105,8 @@ __isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv, __isl_give isl_multi_val *isl_multi_val_mod_val(__isl_take isl_multi_val *mv, __isl_take isl_val *v); +__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx, + const char *str); __isl_give isl_printer *isl_printer_print_multi_val(__isl_take isl_printer *p, __isl_keep isl_multi_val *mv); void isl_multi_val_dump(__isl_keep isl_multi_val *mv); diff --git a/polly/lib/External/isl/interface/extract_interface.cc b/polly/lib/External/isl/interface/extract_interface.cc index fd83003329e..3663ef760a0 100644 --- a/polly/lib/External/isl/interface/extract_interface.cc +++ b/polly/lib/External/isl/interface/extract_interface.cc @@ -174,6 +174,14 @@ static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) } #endif +/* Clang changed its API from 3.5 to 3.6, we fix this with a simple overloaded + * function here. + */ +struct ClangAPI { + static Job *command(Job *J) { return J; } + static Job *command(Job &J) { return &J; } +}; + /* Create a CompilerInvocation object that stores the command line * arguments constructed by the driver. * The arguments are mainly useful for setting up the system include @@ -191,7 +199,7 @@ static CompilerInvocation *construct_invocation(const char *filename, driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv))); JobList &Jobs = compilation->getJobs(); - Command *cmd = cast<Command>(*Jobs.begin()); + Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin())); if (strcmp(cmd->getCreator().getName(), "clang")) return NULL; diff --git a/polly/lib/External/isl/interface/python.cc b/polly/lib/External/isl/interface/python.cc index bb5f708028c..0b4c0e28e86 100644 --- a/polly/lib/External/isl/interface/python.cc +++ b/polly/lib/External/isl/interface/python.cc @@ -220,8 +220,8 @@ static void print_callback(QualType type, int arg) for (int i = 0; i < n_arg - 1; ++i) { string arg_type; arg_type = type2python(extract_type(fn->getArgType(i))); - printf(" cb_arg%d = %s(ctx=arg0.ctx, ptr=cb_arg%d)\n", - i, arg_type.c_str(), i); + printf(" cb_arg%d = %s(ctx=arg0.ctx, " + "ptr=cb_arg%d)\n", i, arg_type.c_str(), i); } printf(" try:\n"); printf(" arg%d(", arg); @@ -446,7 +446,8 @@ void isl_class::print(map<string, isl_class> &classes, set<string> &done) printf(" libc.free(ptr)\n"); printf(" return res\n"); printf(" def __repr__(self):\n"); - printf(" return 'isl.%s(\"%%s\")' %% str(self)\n", p_name.c_str()); + printf(" return 'isl.%s(\"%%s\")' %% str(self)\n", + p_name.c_str()); for (in = methods.begin(); in != methods.end(); ++in) print_method(*in, subclass, super); diff --git a/polly/lib/External/isl/isl_aff.c b/polly/lib/External/isl/isl_aff.c index 7c785047635..ad3c5296ae1 100644 --- a/polly/lib/External/isl/isl_aff.c +++ b/polly/lib/External/isl/isl_aff.c @@ -2,6 +2,7 @@ * Copyright 2011 INRIA Saclay * Copyright 2011 Sven Verdoolaege * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt * * Use of this software is governed by the MIT license * @@ -9,6 +10,8 @@ * 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 + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France */ #include <isl_ctx_private.h> @@ -37,6 +40,16 @@ #include <isl_list_templ.c> +#undef BASE +#define BASE union_pw_aff + +#include <isl_list_templ.c> + +#undef BASE +#define BASE union_pw_multi_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) { @@ -2097,8 +2110,8 @@ error: /* Exploit the equalities in "eq" to simplify the affine expression * and the expressions of the integer divisions in the local space. */ -static __isl_give isl_aff *isl_aff_substitute_equalities( - __isl_take isl_aff *aff, __isl_take isl_basic_set *eq) +__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, + __isl_take isl_basic_set *eq) { int n_div; @@ -2157,6 +2170,42 @@ __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, } /* Return a basic set containing those elements in the space + * of aff where it is positive. "rational" should not be set. + * + * If "aff" is NaN, then it is not positive. + */ +static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff, + int rational) +{ + isl_constraint *ineq; + isl_basic_set *bset; + isl_val *c; + + if (!aff) + return NULL; + if (isl_aff_is_nan(aff)) { + isl_space *space = isl_aff_get_domain_space(aff); + isl_aff_free(aff); + return isl_basic_set_empty(space); + } + if (rational) + isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, + "rational sets not supported", goto error); + + ineq = isl_inequality_from_aff(aff); + c = isl_constraint_get_constant_val(ineq); + c = isl_val_sub_ui(c, 1); + ineq = isl_constraint_set_constant_val(ineq, c); + + bset = isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_simplify(bset); + return bset; +error: + isl_aff_free(aff); + return NULL; +} + +/* Return a basic set containing those elements in the space * of aff where it is non-negative. * If "rational" is set, then return a rational basic set. * @@ -2522,6 +2571,17 @@ __isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff) #include <isl_pw_templ.c> +#undef UNION +#define UNION isl_union_pw_aff +#undef PART +#define PART isl_pw_aff +#undef PARTS +#define PARTS pw_aff + +#define NO_EVAL + +#include <isl_union_templ.c> + static __isl_give isl_set *align_params_pw_pw_set_and( __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2, __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, @@ -2545,6 +2605,31 @@ error: return NULL; } +/* Align the parameters of the to isl_pw_aff arguments and + * then apply a function "fn" on them that returns an isl_map. + */ +static __isl_give isl_map *align_params_pw_pw_map_and( + __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, + __isl_give isl_map *(*fn)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2)) +{ + if (!pa1 || !pa2) + goto error; + if (isl_space_match(pa1->dim, isl_dim_param, pa2->dim, isl_dim_param)) + return fn(pa1, pa2); + if (!isl_space_has_named_params(pa1->dim) || + !isl_space_has_named_params(pa2->dim)) + isl_die(isl_pw_aff_get_ctx(pa1), isl_error_invalid, + "unaligned unnamed parameters", goto error); + pa1 = isl_pw_aff_align_params(pa1, isl_pw_aff_get_space(pa2)); + pa2 = isl_pw_aff_align_params(pa2, isl_pw_aff_get_space(pa1)); + return fn(pa1, pa2); +error: + isl_pw_aff_free(pa1); + isl_pw_aff_free(pa2); + return NULL; +} + /* Compute a piecewise quasi-affine expression with a domain that * is the union of those of pwaff1 and pwaff2 and such that on each * cell, the quasi-affine expression is the better (according to cmp) @@ -2740,44 +2825,14 @@ error: } /* Return a set containing those elements in the domain - * of pwaff where it is non-negative. - */ -__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) -{ - int i; - isl_set *set; - - if (!pwaff) - return NULL; - - set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff)); - - for (i = 0; i < pwaff->n; ++i) { - isl_basic_set *bset; - isl_set *set_i; - int rational; - - rational = isl_set_has_rational(pwaff->p[i].set); - bset = aff_nonneg_basic_set(isl_aff_copy(pwaff->p[i].aff), - rational); - set_i = isl_set_from_basic_set(bset); - set_i = isl_set_intersect(set_i, isl_set_copy(pwaff->p[i].set)); - set = isl_set_union_disjoint(set, set_i); - } - - isl_pw_aff_free(pwaff); - - return set; -} - -/* Return a set containing those elements in the domain - * of pwaff where it is zero (if complement is 0) or not zero - * (if complement is 1). + * of "pwaff" where it satisfies "fn" (if complement is 0) or + * does not satisfy "fn" (if complement is 1). * * The pieces with a NaN never belong to the result since - * NaN is neither zero nor non-zero. + * NaN does not satisfy any property. */ -static __isl_give isl_set *pw_aff_zero_set(__isl_take isl_pw_aff *pwaff, +static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff, + __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational), int complement) { int i; @@ -2790,21 +2845,20 @@ static __isl_give isl_set *pw_aff_zero_set(__isl_take isl_pw_aff *pwaff, for (i = 0; i < pwaff->n; ++i) { isl_basic_set *bset; - isl_set *set_i, *zero; + isl_set *set_i, *locus; int rational; if (isl_aff_is_nan(pwaff->p[i].aff)) continue; rational = isl_set_has_rational(pwaff->p[i].set); - bset = aff_zero_basic_set(isl_aff_copy(pwaff->p[i].aff), - rational); - zero = isl_set_from_basic_set(bset); + bset = fn(isl_aff_copy(pwaff->p[i].aff), rational); + locus = isl_set_from_basic_set(bset); set_i = isl_set_copy(pwaff->p[i].set); if (complement) - set_i = isl_set_subtract(set_i, zero); + set_i = isl_set_subtract(set_i, locus); else - set_i = isl_set_intersect(set_i, zero); + set_i = isl_set_intersect(set_i, locus); set = isl_set_union_disjoint(set, set_i); } @@ -2814,11 +2868,27 @@ static __isl_give isl_set *pw_aff_zero_set(__isl_take isl_pw_aff *pwaff, } /* Return a set containing those elements in the domain + * of "pa" where it is positive. + */ +__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa) +{ + return pw_aff_locus(pa, &aff_pos_basic_set, 0); +} + +/* Return a set containing those elements in the domain + * of pwaff where it is non-negative. + */ +__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) +{ + return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0); +} + +/* Return a set containing those elements in the domain * of pwaff where it is zero. */ __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) { - return pw_aff_zero_set(pwaff, 0); + return pw_aff_locus(pwaff, &aff_zero_basic_set, 0); } /* Return a set containing those elements in the domain @@ -2826,7 +2896,7 @@ __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) */ __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff) { - return pw_aff_zero_set(pwaff, 1); + return pw_aff_locus(pwaff, &aff_zero_basic_set, 1); } /* Return a set containing those elements in the shared domain @@ -2921,6 +2991,97 @@ __isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1, return isl_pw_aff_gt_set(pwaff2, pwaff1); } +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are ordered in the same way as "order", + * which returns a set in the shared domain of its two arguments. + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + * + * Let "pa1" and "pa2" be defined on domains A and B respectively. + * We first pull back the two functions such that they are defined on + * the domain [A -> B]. Then we apply "order", resulting in a set + * in the space [A -> B]. Finally, we unwrap this set to obtain + * a map in the space A -> B. + */ +static __isl_give isl_map *isl_pw_aff_order_map_aligned( + __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, + __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2)) +{ + isl_space *space1, *space2; + isl_multi_aff *ma; + isl_set *set; + + space1 = isl_space_domain(isl_pw_aff_get_space(pa1)); + space2 = isl_space_domain(isl_pw_aff_get_space(pa2)); + space1 = isl_space_map_from_domain_and_range(space1, space2); + ma = isl_multi_aff_domain_map(isl_space_copy(space1)); + pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma); + ma = isl_multi_aff_range_map(space1); + pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma); + set = order(pa1, pa2); + + return isl_set_unwrap(set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are equal. + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_eq_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_eq_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function values are equal. + */ +__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_eq_map_aligned); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is less than the function value of "pa2". + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_lt_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_lt_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is less than the function value of "pa2". + */ +__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_lt_map_aligned); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is greater than the function value + * of "pa2". + * The parameters of "pa1" and "pa2" are assumed to have been aligned. + */ +static __isl_give isl_map *isl_pw_aff_gt_map_aligned(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_gt_set); +} + +/* Return a map containing pairs of elements in the domains of "pa1" and "pa2" + * where the function value of "pa1" is greater than the function value + * of "pa2". + */ +__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2) +{ + return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_gt_map_aligned); +} + /* Return a set containing those elements in the shared domain * of the elements of list1 and list2 where each element in list1 * has the relation specified by "fn" with each element in list2. @@ -3576,13 +3737,16 @@ error: #undef BASE #define BASE aff -#define NO_INTERSECT_DOMAIN +#undef DOMBASE +#define DOMBASE set #define NO_DOMAIN #include <isl_multi_templ.c> +#include <isl_multi_apply_set.c> +#include <isl_multi_floor.c> +#include <isl_multi_gist.c> #undef NO_DOMAIN -#undef NO_INTERSECT_DOMAIN /* Remove any internal structure of the domain of "ma". * If there is any such internal structure in the input, @@ -3687,6 +3851,15 @@ error: return NULL; } +/* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy + * of the space to its range. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( + __isl_take isl_space *space) +{ + return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space)); +} + /* Given the space of a set and a range of set dimensions, * construct an isl_multi_aff that projects out those dimensions. */ @@ -3796,25 +3969,6 @@ __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *ma1, &isl_multi_aff_add_aligned); } -/* Subtract "ma2" from "ma1" and return the result. - * - * The parameters of "ma1" and "ma2" are assumed to have been aligned. - */ -static __isl_give isl_multi_aff *isl_multi_aff_sub_aligned( - __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2) -{ - return isl_multi_aff_bin_op(ma1, ma2, &isl_aff_sub); -} - -/* 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_align_params_multi_multi_and(ma1, ma2, - &isl_multi_aff_sub_aligned); -} - /* Exploit the equalities in "eq" to simplify the affine expressions. */ static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities( @@ -3841,25 +3995,6 @@ error: return NULL; } -/* Given f, return floor(f). - */ -__isl_give isl_multi_aff *isl_multi_aff_floor(__isl_take isl_multi_aff *ma) -{ - int i; - - ma = isl_multi_aff_cow(ma); - if (!ma) - return NULL; - - for (i = 0; i < ma->n; ++i) { - ma->p[i] = isl_aff_floor(ma->p[i]); - if (!ma->p[i]) - return isl_multi_aff_free(ma); - } - - return ma; -} - __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff, isl_int f) { @@ -3939,7 +4074,7 @@ __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, #undef DEFAULT_IS_ZERO #define DEFAULT_IS_ZERO 0 -#define NO_NEG +#define NO_SUB #define NO_EVAL #define NO_OPT #define NO_INVOLVES_DIMS @@ -3949,13 +4084,14 @@ __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, #include <isl_pw_templ.c> +#undef NO_SUB + #undef UNION #define UNION isl_union_pw_multi_aff #undef PART #define PART isl_pw_multi_aff #undef PARTS #define PARTS pw_multi_aff -#define ALIGN_DOMAIN #define NO_EVAL @@ -4149,6 +4285,16 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( return isl_pw_multi_aff_union_add_(pma1, pma2); } +/* Compute the sum of "upa1" and "upa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( + __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2) +{ + return isl_union_pw_aff_union_add_(upa1, upa2); +} + /* Compute the sum of "upma1" and "upma2" on the union of their domains, * with the actual sum on the shared domain and * the defined expression on the symmetric difference of the domains. @@ -4885,6 +5031,20 @@ static int pw_multi_aff_from_map(__isl_take isl_map *map, void *user) return *upma ? 0 : -1; } +/* Create an isl_union_pw_multi_aff with the given isl_aff on a universe + * domain. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( + __isl_take isl_aff *aff) +{ + isl_multi_aff *ma; + isl_pw_multi_aff *pma; + + ma = isl_multi_aff_from_aff(aff); + pma = isl_pw_multi_aff_from_multi_aff(ma); + return isl_union_pw_multi_aff_from_pw_multi_aff(pma); +} + /* 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. @@ -5859,8 +6019,13 @@ error: #undef BASE #define BASE pw_aff +#undef DOMBASE +#define DOMBASE set #include <isl_multi_templ.c> +#include <isl_multi_apply_set.c> +#include <isl_multi_gist.c> +#include <isl_multi_intersect.c> /* Scale the elements of "pma" by the corresponding elements of "mv". */ @@ -6618,6 +6783,189 @@ __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff( &isl_multi_pw_aff_pullback_multi_pw_aff_aligned); } +/* Align the parameters of "mpa1" and "mpa2", check that the ranges + * of "mpa1" and "mpa2" live in the same space, construct map space + * between the domain spaces of "mpa1" and "mpa2" and call "order" + * with this map space as extract argument. + */ +static __isl_give isl_map *isl_multi_pw_aff_order_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, + __isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1, + __isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space)) +{ + int match; + isl_space *space1, *space2; + isl_map *res; + + mpa1 = isl_multi_pw_aff_align_params(mpa1, + isl_multi_pw_aff_get_space(mpa2)); + mpa2 = isl_multi_pw_aff_align_params(mpa2, + isl_multi_pw_aff_get_space(mpa1)); + if (!mpa1 || !mpa2) + goto error; + match = isl_space_tuple_is_equal(mpa1->space, isl_dim_out, + mpa2->space, isl_dim_out); + if (match < 0) + goto error; + if (!match) + isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid, + "range spaces don't match", goto error); + space1 = isl_space_domain(isl_multi_pw_aff_get_space(mpa1)); + space2 = isl_space_domain(isl_multi_pw_aff_get_space(mpa2)); + space1 = isl_space_map_from_domain_and_range(space1, space2); + + res = order(mpa1, mpa2, space1); + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return res; +error: + isl_multi_pw_aff_free(mpa1); + isl_multi_pw_aff_free(mpa2); + return NULL; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values are equal. "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" and "mpa2" are equal when each of the pairs of elements + * in the sequences are equal. + */ +static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space( + __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + int i, n; + isl_map *res; + + res = isl_map_universe(space); + + n = isl_multi_pw_aff_dim(mpa1, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa1, *pa2; + isl_map *map; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = isl_pw_aff_eq_map(pa1, pa2); + res = isl_map_intersect(res, map); + } + + return res; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values are equal. + */ +__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_eq_map_on_space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function values of "mpa1" is lexicographically satisfies "base" + * compared to that of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" lexicographically satisfies "base" compared to "mpa2" + * if its i-th element satisfies "base" when compared to + * the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, + __isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1, + __isl_take isl_pw_aff *pa2), + __isl_take isl_space *space) +{ + int i, n; + isl_map *res, *rest; + + res = isl_map_empty(isl_space_copy(space)); + rest = isl_map_universe(space); + + n = isl_multi_pw_aff_dim(mpa1, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa1, *pa2; + isl_map *map; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = base(pa1, pa2); + map = isl_map_intersect(map, isl_map_copy(rest)); + res = isl_map_union(res, map); + + if (i == n - 1) + continue; + + pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i); + pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i); + map = isl_pw_aff_eq_map(pa1, pa2); + rest = isl_map_intersect(rest, map); + } + + isl_map_free(rest); + return res; +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically less than that + * of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" is less than "mpa2" if its i-th element is smaller + * than the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map_on_space( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2, + &isl_pw_aff_lt_map, space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically less than that + * of "mpa2". + */ +__isl_give isl_map *isl_multi_pw_aff_lex_lt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_lex_lt_map_on_space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically greater than that + * of "mpa2". "space" is the space of the result. + * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. + * + * "mpa1" is greater than "mpa2" if its i-th element is greater + * than the i-th element of "mpa2" while all previous elements are + * pairwise equal. + */ +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map_on_space( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, + __isl_take isl_space *space) +{ + return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2, + &isl_pw_aff_gt_map, space); +} + +/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" + * where the function value of "mpa1" is lexicographically greater than that + * of "mpa2". + */ +__isl_give isl_map *isl_multi_pw_aff_lex_gt_map( + __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) +{ + return isl_multi_pw_aff_order_map(mpa1, mpa2, + &isl_multi_pw_aff_lex_gt_map_on_space); +} + /* Compare two isl_affs. * * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater" @@ -6807,3 +7155,1546 @@ __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain( isl_multi_val_free(mv); return data.res; } + +/* Compute the pullback of data->pma by the function represented by "pma2", + * provided the spaces match, and add the results to data->res. + */ +static int pullback_entry(void **entry, void *user) +{ + struct isl_union_pw_multi_aff_bin_data *data = user; + isl_pw_multi_aff *pma2 = *entry; + + if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in, + pma2->dim, isl_dim_out)) + return 0; + + pma2 = isl_pw_multi_aff_pullback_pw_multi_aff( + isl_pw_multi_aff_copy(data->pma), + isl_pw_multi_aff_copy(pma2)); + + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2); + if (!data->res) + return -1; + + return 0; +} + +/* Compute the pullback of "upma1" by the function represented by "upma2". + */ +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma1, + __isl_take isl_union_pw_multi_aff *upma2) +{ + return bin_op(upma1, upma2, &pullback_entry); +} + +/* Check that the domain space of "upa" matches "space". + * + * Return 0 on success and -1 on error. + * + * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and + * can in principle never fail since the space "space" is that + * of the isl_multi_union_pw_aff and is a set space such that + * there is no domain space to match. + * + * We check the parameters and double-check that "space" is + * indeed that of a set. + */ +static int isl_union_pw_aff_check_match_domain_space( + __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space) +{ + isl_space *upa_space; + int match; + + if (!upa || !space) + return -1; + + match = isl_space_is_set(space); + if (match < 0) + return -1; + if (!match) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting set space", return -1); + + upa_space = isl_union_pw_aff_get_space(upa); + match = isl_space_match(space, isl_dim_param, upa_space, isl_dim_param); + if (match < 0) + goto error; + if (!match) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "parameters don't match", goto error); + + isl_space_free(upa_space); + return 0; +error: + isl_space_free(upa_space); + return -1; +} + +/* Do the parameters of "upa" match those of "space"? + */ +static int isl_union_pw_aff_matching_params(__isl_keep isl_union_pw_aff *upa, + __isl_keep isl_space *space) +{ + isl_space *upa_space; + int match; + + if (!upa || !space) + return -1; + + upa_space = isl_union_pw_aff_get_space(upa); + + match = isl_space_match(space, isl_dim_param, upa_space, isl_dim_param); + + isl_space_free(upa_space); + return match; +} + +/* Internal data structure for isl_union_pw_aff_reset_domain_space. + * space represents the new parameters. + * res collects the results. + */ +struct isl_union_pw_aff_reset_params_data { + isl_space *space; + isl_union_pw_aff *res; +}; + +/* Replace the parameters of "pa" by data->space and + * add the result to data->res. + */ +static int reset_params(__isl_take isl_pw_aff *pa, void *user) +{ + struct isl_union_pw_aff_reset_params_data *data = user; + isl_space *space; + + space = isl_pw_aff_get_space(pa); + space = isl_space_replace(space, isl_dim_param, data->space); + pa = isl_pw_aff_reset_space(pa, space); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? 0 : -1; +} + +/* Replace the domain space of "upa" by "space". + * Since a union expression does not have a (single) domain space, + * "space" is necessarily a parameter space. + * + * Since the order and the names of the parameters determine + * the hash value, we need to create a new hash table. + */ +static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space( + __isl_take isl_union_pw_aff *upa, __isl_take isl_space *space) +{ + struct isl_union_pw_aff_reset_params_data data = { space }; + int match; + + match = isl_union_pw_aff_matching_params(upa, space); + if (match < 0) + upa = isl_union_pw_aff_free(upa); + else if (match) { + isl_space_free(space); + return upa; + } + + data.res = isl_union_pw_aff_empty(isl_space_copy(space)); + if (isl_union_pw_aff_foreach_pw_aff(upa, &reset_params, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + isl_union_pw_aff_free(upa); + isl_space_free(space); + return data.res; +} + +/* Replace the entry of isl_union_pw_aff to which "entry" points + * by its floor. + */ +static int floor_entry(void **entry, void *user) +{ + isl_pw_aff **pa = (isl_pw_aff **) entry; + + *pa = isl_pw_aff_floor(*pa); + if (!*pa) + return -1; + + return 0; +} + +/* Given f, return floor(f). + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_floor( + __isl_take isl_union_pw_aff *upa) +{ + isl_ctx *ctx; + + upa = isl_union_pw_aff_cow(upa); + if (!upa) + return NULL; + + ctx = isl_union_pw_aff_get_ctx(upa); + if (isl_hash_table_foreach(ctx, &upa->table, &floor_entry, NULL) < 0) + upa = isl_union_pw_aff_free(upa); + + return upa; +} + +/* Compute + * + * upa mod m = upa - m * floor(upa/m) + * + * with m an integer value. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( + __isl_take isl_union_pw_aff *upa, __isl_take isl_val *m) +{ + isl_union_pw_aff *res; + + if (!upa || !m) + goto error; + + if (!isl_val_is_int(m)) + isl_die(isl_val_get_ctx(m), isl_error_invalid, + "expecting integer modulo", goto error); + if (!isl_val_is_pos(m)) + isl_die(isl_val_get_ctx(m), isl_error_invalid, + "expecting positive modulo", goto error); + + res = isl_union_pw_aff_copy(upa); + upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(m)); + upa = isl_union_pw_aff_floor(upa); + upa = isl_union_pw_aff_scale_val(upa, m); + res = isl_union_pw_aff_sub(res, upa); + + return res; +error: + isl_val_free(m); + isl_union_pw_aff_free(upa); + return NULL; +} + +/* Internal data structure for isl_union_pw_aff_aff_on_domain. + * "aff" is the symbolic value that the resulting isl_union_pw_aff + * needs to attain. + * "res" collects the results. + */ +struct isl_union_pw_aff_aff_on_domain_data { + isl_aff *aff; + isl_union_pw_aff *res; +}; + +/* Construct a piecewise affine expression that is equal to data->aff + * on "domain" and add the result to data->res. + */ +static int pw_aff_aff_on_domain(__isl_take isl_set *domain, void *user) +{ + struct isl_union_pw_aff_aff_on_domain_data *data = user; + isl_pw_aff *pa; + isl_aff *aff; + int dim; + + aff = isl_aff_copy(data->aff); + dim = isl_set_dim(domain, isl_dim_set); + aff = isl_aff_add_dims(aff, isl_dim_in, dim); + aff = isl_aff_reset_domain_space(aff, isl_set_get_space(domain)); + pa = isl_pw_aff_alloc(domain, aff); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? 0 : -1; +} + +/* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff. + * pos is the output position that needs to be extracted. + * res collects the results. + */ +struct isl_union_pw_multi_aff_get_union_pw_aff_data { + int pos; + isl_union_pw_aff *res; +}; + +/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma" + * (assuming it has such a dimension) and add it to data->res. + */ +static int get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user; + int n_out; + isl_pw_aff *pa; + + if (!pma) + return -1; + + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (data->pos >= n_out) { + isl_pw_multi_aff_free(pma); + return 0; + } + + pa = isl_pw_multi_aff_get_pw_aff(pma, data->pos); + isl_pw_multi_aff_free(pma); + + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? 0 : -1; +} + +/* Extract an isl_union_pw_aff corresponding to + * output dimension "pos" of "upma". + */ +__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff( + __isl_keep isl_union_pw_multi_aff *upma, int pos) +{ + struct isl_union_pw_multi_aff_get_union_pw_aff_data data; + isl_space *space; + + if (!upma) + return NULL; + + if (pos < 0) + isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, + "cannot extract at negative position", return NULL); + + space = isl_union_pw_multi_aff_get_space(upma); + data.res = isl_union_pw_aff_empty(space); + data.pos = pos; + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &get_union_pw_aff, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + return data.res; +} + +/* Return a union piecewise affine expression + * that is equal to "aff" on "domain". + * + * Construct an isl_pw_aff on each of the sets in "domain" and + * collect the results. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_aff *aff) +{ + struct isl_union_pw_aff_aff_on_domain_data data; + isl_space *space; + + if (!domain || !aff) + goto error; + if (!isl_local_space_is_params(aff->ls)) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "expecting parametric expression", goto error); + + space = isl_union_set_get_space(domain); + data.res = isl_union_pw_aff_empty(space); + data.aff = aff; + if (isl_union_set_foreach_set(domain, &pw_aff_aff_on_domain, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + isl_union_set_free(domain); + isl_aff_free(aff); + return data.res; +error: + isl_union_set_free(domain); + isl_aff_free(aff); + return NULL; +} + +/* Internal data structure for isl_union_pw_aff_val_on_domain. + * "v" is the value that the resulting isl_union_pw_aff needs to attain. + * "res" collects the results. + */ +struct isl_union_pw_aff_val_on_domain_data { + isl_val *v; + isl_union_pw_aff *res; +}; + +/* Construct a piecewise affine expression that is equal to data->v + * on "domain" and add the result to data->res. + */ +static int pw_aff_val_on_domain(__isl_take isl_set *domain, void *user) +{ + struct isl_union_pw_aff_val_on_domain_data *data = user; + isl_pw_aff *pa; + isl_val *v; + + v = isl_val_copy(data->v); + pa = isl_pw_aff_val_on_domain(domain, v); + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? 0 : -1; +} + +/* Return a union piecewise affine expression + * that is equal to "v" on "domain". + * + * Construct an isl_pw_aff on each of the sets in "domain" and + * collect the results. + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_val *v) +{ + struct isl_union_pw_aff_val_on_domain_data data; + isl_space *space; + + space = isl_union_set_get_space(domain); + data.res = isl_union_pw_aff_empty(space); + data.v = v; + if (isl_union_set_foreach_set(domain, &pw_aff_val_on_domain, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + isl_union_set_free(domain); + isl_val_free(v); + return data.res; +} + +/* Construct a piecewise multi affine expression + * that is equal to "pa" and add it to upma. + */ +static int pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa, void *user) +{ + isl_union_pw_multi_aff **upma = user; + isl_pw_multi_aff *pma; + + pma = isl_pw_multi_aff_from_pw_aff(pa); + *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma); + + return *upma ? 0 : -1; +} + +/* Construct and return a union piecewise multi affine expression + * that is equal to the given union piecewise affine expression. + */ +__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa) +{ + isl_space *space; + isl_union_pw_multi_aff *upma; + + if (!upa) + return NULL; + + space = isl_union_pw_aff_get_space(upa); + upma = isl_union_pw_multi_aff_empty(space); + + if (isl_union_pw_aff_foreach_pw_aff(upa, + &pw_multi_aff_from_pw_aff_entry, &upma) < 0) + upma = isl_union_pw_multi_aff_free(upma); + + isl_union_pw_aff_free(upa); + return upma; +} + +/* Compute the set of elements in the domain of "pa" where it is zero and + * add this set to "uset". + */ +static int zero_union_set(__isl_take isl_pw_aff *pa, void *user) +{ + isl_union_set **uset = (isl_union_set **)user; + + *uset = isl_union_set_add_set(*uset, isl_pw_aff_zero_set(pa)); + + return *uset ? 0 : -1; +} + +/* Return a union set containing those elements in the domain + * of "upa" where it is zero. + */ +__isl_give isl_union_set *isl_union_pw_aff_zero_union_set( + __isl_take isl_union_pw_aff *upa) +{ + isl_union_set *zero; + + zero = isl_union_set_empty(isl_union_pw_aff_get_space(upa)); + if (isl_union_pw_aff_foreach_pw_aff(upa, &zero_union_set, &zero) < 0) + zero = isl_union_set_free(zero); + + isl_union_pw_aff_free(upa); + return zero; +} + +/* Convert "pa" to an isl_map and add it to *umap. + */ +static int map_from_pw_aff_entry(__isl_take isl_pw_aff *pa, void *user) +{ + isl_union_map **umap = user; + isl_map *map; + + map = isl_map_from_pw_aff(pa); + *umap = isl_union_map_add_map(*umap, map); + + return *umap ? 0 : -1; +} + +/* Construct a union map mapping the domain of the union + * piecewise affine expression to its range, with the single output dimension + * equated to the corresponding affine expressions on their cells. + */ +__isl_give isl_union_map *isl_union_map_from_union_pw_aff( + __isl_take isl_union_pw_aff *upa) +{ + isl_space *space; + isl_union_map *umap; + + if (!upa) + return NULL; + + space = isl_union_pw_aff_get_space(upa); + umap = isl_union_map_empty(space); + + if (isl_union_pw_aff_foreach_pw_aff(upa, &map_from_pw_aff_entry, + &umap) < 0) + umap = isl_union_map_free(umap); + + isl_union_pw_aff_free(upa); + return umap; +} + +/* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff. + * upma is the function that is plugged in. + * pa is the current part of the function in which upma is plugged in. + * res collects the results. + */ +struct isl_union_pw_aff_pullback_upma_data { + isl_union_pw_multi_aff *upma; + isl_pw_aff *pa; + isl_union_pw_aff *res; +}; + +/* Check if "pma" can be plugged into data->pa. + * If so, perform the pullback and add the result to data->res. + */ +static int pa_pb_pma(void **entry, void *user) +{ + struct isl_union_pw_aff_pullback_upma_data *data = user; + isl_pw_multi_aff *pma = *entry; + isl_pw_aff *pa; + + if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in, + pma->dim, isl_dim_out)) + return 0; + + pma = isl_pw_multi_aff_copy(pma); + pa = isl_pw_aff_copy(data->pa); + pa = isl_pw_aff_pullback_pw_multi_aff(pa, pma); + + data->res = isl_union_pw_aff_add_pw_aff(data->res, pa); + + return data->res ? 0 : -1; +} + +/* Check if any of the elements of data->upma can be plugged into pa, + * add if so add the result to data->res. + */ +static int upa_pb_upma(void **entry, void *user) +{ + struct isl_union_pw_aff_pullback_upma_data *data = user; + isl_ctx *ctx; + isl_pw_aff *pa = *entry; + + data->pa = pa; + ctx = isl_union_pw_multi_aff_get_ctx(data->upma); + if (isl_hash_table_foreach(ctx, &data->upma->table, + &pa_pb_pma, data) < 0) + return -1; + + return 0; +} + +/* Compute the pullback of "upa" by the function represented by "upma". + * In other words, plug in "upma" in "upa". The result contains + * expressions defined over the domain space of "upma". + * + * Run over all pairs of elements in "upa" and "upma", perform + * the pullback when appropriate and collect the results. + * If the hash value were based on the domain space rather than + * the function space, then we could run through all elements + * of "upma" and directly pick out the corresponding element of "upa". + */ +__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_union_pw_aff *upa, + __isl_take isl_union_pw_multi_aff *upma) +{ + struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL }; + isl_ctx *ctx; + isl_space *space; + + space = isl_union_pw_multi_aff_get_space(upma); + upa = isl_union_pw_aff_align_params(upa, space); + space = isl_union_pw_aff_get_space(upa); + upma = isl_union_pw_multi_aff_align_params(upma, space); + + if (!upa || !upma) + goto error; + + ctx = isl_union_pw_aff_get_ctx(upa); + data.upma = upma; + space = isl_union_pw_aff_get_space(upa); + data.res = isl_union_pw_aff_alloc(space, upa->table.n); + if (isl_hash_table_foreach(ctx, &upa->table, &upa_pb_upma, &data) < 0) + data.res = isl_union_pw_aff_free(data.res); + + isl_union_pw_aff_free(upa); + isl_union_pw_multi_aff_free(upma); + return data.res; +error: + isl_union_pw_aff_free(upa); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +#undef BASE +#define BASE union_pw_aff +#undef DOMBASE +#define DOMBASE union_set + +#define NO_MOVE_DIMS +#define NO_DIMS +#define NO_DOMAIN +#define NO_PRODUCT +#define NO_SPLICE +#define NO_ZERO +#define NO_IDENTITY +#define NO_GIST + +#include <isl_multi_templ.c> +#include <isl_multi_apply_set.c> +#include <isl_multi_apply_union_set.c> +#include <isl_multi_floor.c> +#include <isl_multi_gist.c> +#include <isl_multi_intersect.c> + +/* Construct a multiple union piecewise affine expression + * in the given space with value zero in each of the output dimensions. + * + * Since there is no canonical zero value for + * a union piecewise affine expression, we can only construct + * zero-dimensional "zero" value. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero( + __isl_take isl_space *space) +{ + if (!space) + return NULL; + + if (!isl_space_is_set(space)) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting set space", goto error); + if (isl_space_dim(space , isl_dim_out) != 0) + isl_die(isl_space_get_ctx(space), isl_error_invalid, + "expecting 0D space", goto error); + + return isl_multi_union_pw_aff_alloc(space); +error: + isl_space_free(space); + return NULL; +} + +/* Compute the sum of "mupa1" and "mupa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + * + * We simply iterate over the elements in both arguments and + * call isl_union_pw_aff_union_add on each of them. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_union_add_aligned( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2) +{ + return isl_multi_union_pw_aff_bin_op(mupa1, mupa2, + &isl_union_pw_aff_union_add); +} + +/* Compute the sum of "mupa1" and "mupa2" on the union of their domains, + * with the actual sum on the shared domain and + * the defined expression on the symmetric difference of the domains. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add( + __isl_take isl_multi_union_pw_aff *mupa1, + __isl_take isl_multi_union_pw_aff *mupa2) +{ + return isl_multi_union_pw_aff_align_params_multi_multi_and(mupa1, mupa2, + &isl_multi_union_pw_aff_union_add_aligned); +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given multi affine expression. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + isl_multi_pw_aff *mpa; + + mpa = isl_multi_pw_aff_from_multi_aff(ma); + return isl_multi_union_pw_aff_from_multi_pw_aff(mpa); +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given multi piecewise affine expression. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( + __isl_take isl_multi_pw_aff *mpa) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!mpa) + return NULL; + + space = isl_multi_pw_aff_get_space(mpa); + space = isl_space_range(space); + mupa = isl_multi_union_pw_aff_alloc(space); + + n = isl_multi_pw_aff_dim(mpa, isl_dim_out); + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + isl_union_pw_aff *upa; + + pa = isl_multi_pw_aff_get_pw_aff(mpa, i); + upa = isl_union_pw_aff_from_pw_aff(pa); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_multi_pw_aff_free(mpa); + + return mupa; +} + +/* Extract the range space of "pma" and assign it to *space. + * If *space has already been set (through a previous call to this function), + * then check that the range space is the same. + */ +static int extract_space(__isl_take isl_pw_multi_aff *pma, void *user) +{ + isl_space **space = user; + isl_space *pma_space; + int equal; + + pma_space = isl_space_range(isl_pw_multi_aff_get_space(pma)); + isl_pw_multi_aff_free(pma); + + if (!pma_space) + return -1; + if (!*space) { + *space = pma_space; + return 0; + } + + equal = isl_space_is_equal(pma_space, *space); + isl_space_free(pma_space); + + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_space_get_ctx(*space), isl_error_invalid, + "range spaces not the same", return -1); + return 0; +} + +/* Construct and return a multi union piecewise affine expression + * that is equal to the given union piecewise multi affine expression. + * + * In order to be able to perform the conversion, the input + * needs to be non-empty and may only involve a single range space. + */ +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_from_union_pw_multi_aff( + __isl_take isl_union_pw_multi_aff *upma) +{ + isl_space *space = NULL; + isl_multi_union_pw_aff *mupa; + int i, n; + + if (!upma) + return NULL; + if (isl_union_pw_multi_aff_n_pw_multi_aff(upma) == 0) + isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, + "cannot extract range space from empty input", + goto error); + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, &extract_space, + &space) < 0) + goto error; + + if (!space) + goto error; + + n = isl_space_dim(space, isl_dim_set); + mupa = isl_multi_union_pw_aff_alloc(space); + + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, i); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_pw_multi_aff_free(upma); + return mupa; +error: + isl_space_free(space); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Try and create an isl_multi_union_pw_aff that is equivalent + * to the given isl_union_map. + * The isl_union_map is required to be single-valued in each space. + * Moreover, it cannot be empty and all range spaces need to be the same. + * Otherwise, an error is produced. + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map( + __isl_take isl_union_map *umap) +{ + isl_union_pw_multi_aff *upma; + + upma = isl_union_pw_multi_aff_from_union_map(umap); + return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma); +} + +/* Return a multiple union piecewise affine expression + * that is equal to "mv" on "domain", assuming "domain" and "mv" + * have been aligned. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_multi_val_on_domain_aligned( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!domain || !mv) + goto error; + + n = isl_multi_val_dim(mv, isl_dim_set); + space = isl_multi_val_get_space(mv); + mupa = isl_multi_union_pw_aff_alloc(space); + for (i = 0; i < n; ++i) { + isl_val *v; + isl_union_pw_aff *upa; + + v = isl_multi_val_get_val(mv, i); + upa = isl_union_pw_aff_val_on_domain(isl_union_set_copy(domain), + v); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_set_free(domain); + isl_multi_val_free(mv); + return mupa; +error: + isl_union_set_free(domain); + isl_multi_val_free(mv); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "mv" on "domain". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) +{ + if (!domain || !mv) + goto error; + if (isl_space_match(domain->dim, isl_dim_param, + mv->space, isl_dim_param)) + return isl_multi_union_pw_aff_multi_val_on_domain_aligned( + domain, mv); + domain = isl_union_set_align_params(domain, + isl_multi_val_get_space(mv)); + mv = isl_multi_val_align_params(mv, isl_union_set_get_space(domain)); + return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv); +error: + isl_union_set_free(domain); + isl_multi_val_free(mv); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "ma" on "domain", assuming "domain" and "ma" + * have been aligned. + */ +static __isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_multi_aff_on_domain_aligned( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma) +{ + int i, n; + isl_space *space; + isl_multi_union_pw_aff *mupa; + + if (!domain || !ma) + goto error; + + n = isl_multi_aff_dim(ma, isl_dim_set); + space = isl_multi_aff_get_space(ma); + mupa = isl_multi_union_pw_aff_alloc(space); + for (i = 0; i < n; ++i) { + isl_aff *aff; + isl_union_pw_aff *upa; + + aff = isl_multi_aff_get_aff(ma, i); + upa = isl_union_pw_aff_aff_on_domain(isl_union_set_copy(domain), + aff); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return mupa; +error: + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return NULL; +} + +/* Return a multiple union piecewise affine expression + * that is equal to "ma" on "domain". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain( + __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma) +{ + if (!domain || !ma) + goto error; + if (isl_space_match(domain->dim, isl_dim_param, + ma->space, isl_dim_param)) + return isl_multi_union_pw_aff_multi_aff_on_domain_aligned( + domain, ma); + domain = isl_union_set_align_params(domain, + isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, isl_union_set_get_space(domain)); + return isl_multi_union_pw_aff_multi_aff_on_domain_aligned(domain, ma); +error: + isl_union_set_free(domain); + isl_multi_aff_free(ma); + return NULL; +} + +/* Return a union set containing those elements in the domains + * of the elements of "mupa" where they are all zero. + */ +__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_union_pw_aff *upa; + isl_union_set *zero; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine zero set " + "of zero-dimensional function", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + zero = isl_union_pw_aff_zero_union_set(upa); + + for (i = 1; i < n; ++i) { + isl_union_set *zero_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + zero_i = isl_union_pw_aff_zero_union_set(upa); + + zero = isl_union_set_intersect(zero, zero_i); + } + + isl_multi_union_pw_aff_free(mupa); + return zero; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Construct a union map mapping the shared domain + * of the union piecewise affine expressions to the range of "mupa" + * with each dimension in the range equated to the + * corresponding union piecewise affine expression. + * + * The input cannot be zero-dimensional as there is + * no way to extract a domain from a zero-dimensional isl_multi_union_pw_aff. + */ +__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_space *space; + isl_union_map *umap; + isl_union_pw_aff *upa; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + umap = isl_union_map_from_union_pw_aff(upa); + + for (i = 1; i < n; ++i) { + isl_union_map *umap_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + umap_i = isl_union_map_from_union_pw_aff(upa); + umap = isl_union_map_flat_range_product(umap, umap_i); + } + + space = isl_multi_union_pw_aff_get_space(mupa); + umap = isl_union_map_reset_range_space(umap, space); + + isl_multi_union_pw_aff_free(mupa); + return umap; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Internal data structure for isl_union_pw_multi_aff_reset_range_space. + * "range" is the space from which to set the range space. + * "res" collects the results. + */ +struct isl_union_pw_multi_aff_reset_range_space_data { + isl_space *range; + isl_union_pw_multi_aff *res; +}; + +/* Replace the range space of "pma" by the range space of data->range and + * add the result to data->res. + */ +static int reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user) +{ + struct isl_union_pw_multi_aff_reset_range_space_data *data = user; + isl_space *space; + + space = isl_pw_multi_aff_get_space(pma); + space = isl_space_domain(space); + space = isl_space_extend_domain_with_range(space, + isl_space_copy(data->range)); + pma = isl_pw_multi_aff_reset_space(pma, space); + data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma); + + return data->res ? 0 : -1; +} + +/* Replace the range space of all the piecewise affine expressions in "upma" by + * the range space of "space". + * + * This assumes that all these expressions have the same output dimension. + * + * Since the spaces of the expressions change, so do their hash values. + * We therefore need to create a new isl_union_pw_multi_aff. + * Note that the hash value is currently computed based on the entire + * space even though there can only be a single expression with a given + * domain space. + */ +static __isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_reset_range_space( + __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space) +{ + struct isl_union_pw_multi_aff_reset_range_space_data data = { space }; + isl_space *space_upma; + + space_upma = isl_union_pw_multi_aff_get_space(upma); + data.res = isl_union_pw_multi_aff_empty(space_upma); + if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, + &reset_range_space, &data) < 0) + data.res = isl_union_pw_multi_aff_free(data.res); + + isl_space_free(space); + isl_union_pw_multi_aff_free(upma); + return data.res; +} + +/* Construct and return a union piecewise multi affine expression + * that is equal to the given multi union piecewise affine expression. + * + * In order to be able to perform the conversion, the input + * needs to have a least one output dimension. + */ +__isl_give isl_union_pw_multi_aff * +isl_union_pw_multi_aff_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_space *space; + isl_union_pw_multi_aff *upma; + isl_union_pw_aff *upa; + + if (!mupa) + return NULL; + + space = isl_multi_union_pw_aff_get_space(mupa); + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + upma = isl_union_pw_multi_aff_from_union_pw_aff(upa); + + for (i = 1; i < n; ++i) { + isl_union_pw_multi_aff *upma_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa); + upma = isl_union_pw_multi_aff_flat_range_product(upma, upma_i); + } + + upma = isl_union_pw_multi_aff_reset_range_space(upma, space); + + isl_multi_union_pw_aff_free(mupa); + return upma; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Intersect the range of "mupa" with "range". + * That is, keep only those domain elements that have a function value + * in "range". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range) +{ + isl_union_pw_multi_aff *upma; + isl_union_set *domain; + isl_space *space; + int n; + int match; + + if (!mupa || !range) + goto error; + + space = isl_set_get_space(range); + match = isl_space_tuple_is_equal(mupa->space, isl_dim_set, + space, isl_dim_set); + isl_space_free(space); + if (match < 0) + goto error; + if (!match) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "space don't match", goto error); + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot intersect range of zero-dimensional " + "isl_multi_union_pw_aff", goto error); + + upma = isl_union_pw_multi_aff_from_multi_union_pw_aff( + isl_multi_union_pw_aff_copy(mupa)); + domain = isl_union_set_from_set(range); + domain = isl_union_set_preimage_union_pw_multi_aff(domain, upma); + mupa = isl_multi_union_pw_aff_intersect_domain(mupa, domain); + + return mupa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_set_free(range); + return NULL; +} + +/* Return the shared domain of the elements of "mupa". + */ +__isl_give isl_union_set *isl_multi_union_pw_aff_domain( + __isl_take isl_multi_union_pw_aff *mupa) +{ + int i, n; + isl_union_pw_aff *upa; + isl_union_set *dom; + + if (!mupa) + return NULL; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + if (n == 0) + isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, + "cannot determine domain", goto error); + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0); + dom = isl_union_pw_aff_domain(upa); + for (i = 1; i < n; ++i) { + isl_union_set *dom_i; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + dom_i = isl_union_pw_aff_domain(upa); + dom = isl_union_set_intersect(dom, dom_i); + } + + isl_multi_union_pw_aff_free(mupa); + return dom; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Apply "aff" to "mupa". The space of "mupa" is equal to the domain of "aff". + * In particular, the spaces have been aligned. + * The result is defined over the shared domain of the elements of "mupa" + * + * We first extract the parametric constant part of "aff" and + * define that over the shared domain. + * Then we iterate over all input dimensions of "aff" and add the corresponding + * multiples of the elements of "mupa". + * Finally, we consider the integer divisions, calling the function + * recursively to obtain an isl_union_pw_aff corresponding to the + * integer division argument. + */ +static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) +{ + int i, n_in, n_div; + isl_union_pw_aff *upa; + isl_union_set *uset; + isl_val *v; + isl_aff *cst; + + n_in = isl_aff_dim(aff, isl_dim_in); + n_div = isl_aff_dim(aff, isl_dim_div); + + uset = isl_multi_union_pw_aff_domain(isl_multi_union_pw_aff_copy(mupa)); + cst = isl_aff_copy(aff); + cst = isl_aff_drop_dims(cst, isl_dim_div, 0, n_div); + cst = isl_aff_drop_dims(cst, isl_dim_in, 0, n_in); + cst = isl_aff_project_domain_on_params(cst); + upa = isl_union_pw_aff_aff_on_domain(uset, cst); + + for (i = 0; i < n_in; ++i) { + isl_union_pw_aff *upa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1)) + continue; + v = isl_aff_get_coefficient_val(aff, isl_dim_in, i); + upa_i = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upa_i = isl_union_pw_aff_scale_val(upa_i, v); + upa = isl_union_pw_aff_add(upa, upa_i); + } + + for (i = 0; i < n_div; ++i) { + isl_aff *div; + isl_union_pw_aff *upa_i; + + if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1)) + continue; + div = isl_aff_get_div(aff, i); + upa_i = multi_union_pw_aff_apply_aff( + isl_multi_union_pw_aff_copy(mupa), div); + upa_i = isl_union_pw_aff_floor(upa_i); + v = isl_aff_get_coefficient_val(aff, isl_dim_div, i); + upa_i = isl_union_pw_aff_scale_val(upa_i, v); + upa = isl_union_pw_aff_add(upa, upa_i); + } + + isl_multi_union_pw_aff_free(mupa); + isl_aff_free(aff); + + return upa; +} + +/* Apply "aff" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "aff". + * Furthermore, the dimension of this space needs to be greater than zero. + * The result is defined over the shared domain of the elements of "mupa" + * + * We perform these checks and then hand over control to + * multi_union_pw_aff_apply_aff. + */ +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) +{ + isl_space *space1, *space2; + int equal; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_aff_get_space(aff)); + aff = isl_aff_align_params(aff, isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !aff) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_aff_get_domain_space(aff); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "spaces don't match", goto error); + if (isl_aff_dim(aff, isl_dim_in) == 0) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "cannot determine domains", goto error); + + return multi_union_pw_aff_apply_aff(mupa, aff); +error: + isl_multi_union_pw_aff_free(mupa); + isl_aff_free(aff); + return NULL; +} + +/* Apply "ma" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "ma". + * Furthermore, the dimension of this space needs to be greater than zero, + * unless the dimension of the target space of "ma" is also zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma) +{ + isl_space *space1, *space2; + isl_multi_union_pw_aff *res; + int equal; + int i, n_out; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_multi_aff_get_space(ma)); + ma = isl_multi_aff_align_params(ma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !ma) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_multi_aff_get_domain_space(ma); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid, + "spaces don't match", goto error); + n_out = isl_multi_aff_dim(ma, isl_dim_out); + if (isl_multi_aff_dim(ma, isl_dim_in) == 0 && n_out != 0) + isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid, + "cannot determine domains", goto error); + + space1 = isl_space_range(isl_multi_aff_get_space(ma)); + res = isl_multi_union_pw_aff_alloc(space1); + + for (i = 0; i < n_out; ++i) { + isl_aff *aff; + isl_union_pw_aff *upa; + + aff = isl_multi_aff_get_aff(ma, i); + upa = multi_union_pw_aff_apply_aff( + isl_multi_union_pw_aff_copy(mupa), aff); + res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa); + } + + isl_multi_aff_free(ma); + isl_multi_union_pw_aff_free(mupa); + return res; +error: + isl_multi_union_pw_aff_free(mupa); + isl_multi_aff_free(ma); + return NULL; +} + +/* Apply "pa" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "pa". + * Furthermore, the dimension of this space needs to be greater than zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa) +{ + int i; + int equal; + isl_space *space, *space2; + isl_union_pw_aff *upa; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_pw_aff_get_space(pa)); + pa = isl_pw_aff_align_params(pa, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !pa) + goto error; + + space = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_pw_aff_get_domain_space(pa); + equal = isl_space_is_equal(space, space2); + isl_space_free(space); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "spaces don't match", goto error); + if (isl_pw_aff_dim(pa, isl_dim_in) == 0) + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "cannot determine domains", goto error); + + space = isl_space_params(isl_multi_union_pw_aff_get_space(mupa)); + upa = isl_union_pw_aff_empty(space); + + for (i = 0; i < pa->n; ++i) { + isl_aff *aff; + isl_set *domain; + isl_multi_union_pw_aff *mupa_i; + isl_union_pw_aff *upa_i; + + mupa_i = isl_multi_union_pw_aff_copy(mupa); + domain = isl_set_copy(pa->p[i].set); + mupa_i = isl_multi_union_pw_aff_intersect_range(mupa_i, domain); + aff = isl_aff_copy(pa->p[i].aff); + upa_i = multi_union_pw_aff_apply_aff(mupa_i, aff); + upa = isl_union_pw_aff_union_add(upa, upa_i); + } + + isl_multi_union_pw_aff_free(mupa); + isl_pw_aff_free(pa); + return upa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_pw_aff_free(pa); + return NULL; +} + +/* Apply "pma" to "mupa". The space of "mupa" needs to be compatible + * with the domain of "pma". + * Furthermore, the dimension of this space needs to be greater than zero, + * unless the dimension of the target space of "pma" is also zero. + * The result is defined over the shared domain of the elements of "mupa" + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_pw_multi_aff *pma) +{ + isl_space *space1, *space2; + isl_multi_union_pw_aff *res; + int equal; + int i, n_out; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_pw_multi_aff_get_space(pma)); + pma = isl_pw_multi_aff_align_params(pma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !pma) + goto error; + + space1 = isl_multi_union_pw_aff_get_space(mupa); + space2 = isl_pw_multi_aff_get_domain_space(pma); + equal = isl_space_is_equal(space1, space2); + isl_space_free(space1); + isl_space_free(space2); + if (equal < 0) + goto error; + if (!equal) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "spaces don't match", goto error); + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (isl_pw_multi_aff_dim(pma, isl_dim_in) == 0 && n_out != 0) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "cannot determine domains", goto error); + + space1 = isl_space_range(isl_pw_multi_aff_get_space(pma)); + res = isl_multi_union_pw_aff_alloc(space1); + + for (i = 0; i < n_out; ++i) { + isl_pw_aff *pa; + isl_union_pw_aff *upa; + + pa = isl_pw_multi_aff_get_pw_aff(pma, i); + upa = isl_multi_union_pw_aff_apply_pw_aff( + isl_multi_union_pw_aff_copy(mupa), pa); + res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa); + } + + isl_pw_multi_aff_free(pma); + isl_multi_union_pw_aff_free(mupa); + return res; +error: + isl_multi_union_pw_aff_free(mupa); + isl_pw_multi_aff_free(pma); + return NULL; +} + +/* Compute the pullback of "mupa" by the function represented by "upma". + * In other words, plug in "upma" in "mupa". The result contains + * expressions defined over the domain space of "upma". + * + * Run over all elements of "mupa" and plug in "upma" in each of them. + */ +__isl_give isl_multi_union_pw_aff * +isl_multi_union_pw_aff_pullback_union_pw_multi_aff( + __isl_take isl_multi_union_pw_aff *mupa, + __isl_take isl_union_pw_multi_aff *upma) +{ + int i, n; + + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_union_pw_multi_aff_get_space(upma)); + upma = isl_union_pw_multi_aff_align_params(upma, + isl_multi_union_pw_aff_get_space(mupa)); + if (!mupa || !upma) + goto error; + + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa, + isl_union_pw_multi_aff_copy(upma)); + mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa); + } + + isl_union_pw_multi_aff_free(upma); + return mupa; +error: + isl_multi_union_pw_aff_free(mupa); + isl_union_pw_multi_aff_free(upma); + return NULL; +} + +/* Extract the sequence of elements in "mupa" with domain space "space" + * (ignoring parameters). + * + * For the elements of "mupa" that are not defined on the specified space, + * the corresponding element in the result is empty. + */ +__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff( + __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space) +{ + int i, n; + isl_space *space_mpa = NULL; + isl_multi_pw_aff *mpa; + + if (!mupa || !space) + goto error; + + space_mpa = isl_multi_union_pw_aff_get_space(mupa); + if (!isl_space_match(space_mpa, isl_dim_param, space, isl_dim_param)) { + space = isl_space_drop_dims(space, isl_dim_param, + 0, isl_space_dim(space, isl_dim_param)); + space = isl_space_align_params(space, + isl_space_copy(space_mpa)); + if (!space) + goto error; + } + space_mpa = isl_space_map_from_domain_and_range(isl_space_copy(space), + space_mpa); + mpa = isl_multi_pw_aff_alloc(space_mpa); + + space = isl_space_from_domain(space); + space = isl_space_add_dims(space, isl_dim_out, 1); + n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + isl_pw_aff *pa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i); + pa = isl_union_pw_aff_extract_pw_aff(upa, + isl_space_copy(space)); + mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); + isl_union_pw_aff_free(upa); + } + + isl_space_free(space); + return mpa; +error: + isl_space_free(space_mpa); + isl_space_free(space); + return NULL; +} diff --git a/polly/lib/External/isl/isl_aff_private.h b/polly/lib/External/isl/isl_aff_private.h index bb959f4bcb3..2214942736b 100644 --- a/polly/lib/External/isl/isl_aff_private.h +++ b/polly/lib/External/isl/isl_aff_private.h @@ -141,6 +141,8 @@ void isl_seq_preimage(isl_int *dst, isl_int *src, 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_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, + __isl_take isl_basic_set *eq); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos, __isl_keep isl_pw_aff *subs); @@ -155,4 +157,19 @@ int isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa, #include <isl_multi_templ.h> +#undef EL +#define EL isl_union_pw_aff + +#include <isl_list_templ.h> + +#undef BASE +#define BASE union_pw_aff + +#include <isl_multi_templ.h> + +#undef EL +#define EL isl_union_pw_multi_aff + +#include <isl_list_templ.h> + #endif diff --git a/polly/lib/External/isl/isl_affine_hull.c b/polly/lib/External/isl/isl_affine_hull.c index 81352817071..982eeccde90 100644 --- a/polly/lib/External/isl/isl_affine_hull.c +++ b/polly/lib/External/isl/isl_affine_hull.c @@ -1147,6 +1147,19 @@ __isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set) return (isl_set *)isl_map_detect_equalities((isl_map *)set); } +/* Return the superset of "bmap" described by the equalities + * satisfied by "bmap" that are already known. + */ +__isl_give isl_basic_map *isl_basic_map_plain_affine_hull( + __isl_take isl_basic_map *bmap) +{ + bmap = isl_basic_map_cow(bmap); + if (bmap) + isl_basic_map_free_inequality(bmap, bmap->n_ineq); + bmap = isl_basic_map_finalize(bmap); + return bmap; +} + /* After computing the rational affine hull (by detecting the implicit * equalities), we compute the additional equalities satisfied by * the integer points (if any) and add the original equalities back in. @@ -1154,10 +1167,7 @@ __isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set) struct isl_basic_map *isl_basic_map_affine_hull(struct isl_basic_map *bmap) { bmap = isl_basic_map_detect_equalities(bmap); - bmap = isl_basic_map_cow(bmap); - if (bmap) - isl_basic_map_free_inequality(bmap, bmap->n_ineq); - bmap = isl_basic_map_finalize(bmap); + bmap = isl_basic_map_plain_affine_hull(bmap); return bmap; } diff --git a/polly/lib/External/isl/isl_ast_build.c b/polly/lib/External/isl/isl_ast_build.c index 61576bb0a51..4ebb9308bb2 100644 --- a/polly/lib/External/isl/isl_ast_build.c +++ b/polly/lib/External/isl/isl_ast_build.c @@ -1807,7 +1807,7 @@ __isl_give isl_aff *isl_ast_build_get_offset( * value that, moreover, can be described by a single affine expression * in terms of the outer dimensions and parameters? * - * If not, then the correponding affine expression in build->values + * If not, then the corresponding affine expression in build->values * is set to be equal to the same input dimension. * Otherwise, it is set to the requested expression in terms of * outer dimensions and parameters. diff --git a/polly/lib/External/isl/isl_ast_build_expr.c b/polly/lib/External/isl/isl_ast_build_expr.c index 2c3bfa3a6f1..2042ac8fe87 100644 --- a/polly/lib/External/isl/isl_ast_build_expr.c +++ b/polly/lib/External/isl/isl_ast_build_expr.c @@ -1,10 +1,13 @@ /* * Copyright 2012-2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt * * Use of this software is governed by the MIT license * * Written by Sven Verdoolaege, * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France */ #include <isl/ilp.h> @@ -29,11 +32,120 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff, return aff; } +/* Internal data structure used inside isl_ast_expr_add_term. + * The domain of "build" is used to simplify the expressions. + * "build" needs to be set by the caller of isl_ast_expr_add_term. + * "cst" is the constant term of the expression in which the added term + * appears. It may be modified by isl_ast_expr_add_term. + * + * "v" is the coefficient of the term that is being constructed and + * is set internally by isl_ast_expr_add_term. + */ +struct isl_ast_add_term_data { + isl_ast_build *build; + isl_val *cst; + isl_val *v; +}; + +/* Given the numerator "aff" of the argument of an integer division + * with denominator "d", check if it can be made non-negative over + * data->build->domain by stealing part of the constant term of + * the expression in which the integer division appears. + * + * In particular, the outer expression is of the form + * + * v * floor(aff/d) + cst + * + * We already know that "aff" itself may attain negative values. + * Here we check if aff + d*floor(cst/v) is non-negative, such + * that we could rewrite the expression to + * + * v * floor((aff + d*floor(cst/v))/d) + cst - v*floor(cst/v) + * + * Note that aff + d*floor(cst/v) can only possibly be non-negative + * if data->cst and data->v have the same sign. + * Similarly, if floor(cst/v) is zero, then there is no point in + * checking again. + */ +static int is_non_neg_after_stealing(__isl_keep isl_aff *aff, + __isl_keep isl_val *d, struct isl_ast_add_term_data *data) +{ + isl_aff *shifted; + isl_val *shift; + int is_zero; + int non_neg; + + if (isl_val_sgn(data->cst) != isl_val_sgn(data->v)) + return 0; + + shift = isl_val_div(isl_val_copy(data->cst), isl_val_copy(data->v)); + shift = isl_val_floor(shift); + is_zero = isl_val_is_zero(shift); + if (is_zero < 0 || is_zero) { + isl_val_free(shift); + return is_zero < 0 ? -1 : 0; + } + shift = isl_val_mul(shift, isl_val_copy(d)); + shifted = isl_aff_copy(aff); + shifted = isl_aff_add_constant_val(shifted, shift); + non_neg = isl_ast_build_aff_is_nonneg(data->build, shifted); + isl_aff_free(shifted); + + return non_neg; +} + +/* Given the numerator "aff' of the argument of an integer division + * with denominator "d", steal part of the constant term of + * the expression in which the integer division appears to make it + * non-negative over data->build->domain. + * + * In particular, the outer expression is of the form + * + * v * floor(aff/d) + cst + * + * We know that "aff" itself may attain negative values, + * but that aff + d*floor(cst/v) is non-negative. + * Find the minimal positive value that we need to add to "aff" + * to make it positive and adjust data->cst accordingly. + * That is, compute the minimal value "m" of "aff" over + * data->build->domain and take + * + * s = ceil(m/d) + * + * such that + * + * aff + d * s >= 0 + * + * and rewrite the expression to + * + * v * floor((aff + s*d)/d) + (cst - v*s) + */ +static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff, + __isl_keep isl_val *d, struct isl_ast_add_term_data *data) +{ + isl_set *domain; + isl_val *shift, *t; + + domain = isl_ast_build_get_domain(data->build); + shift = isl_set_min_val(domain, aff); + isl_set_free(domain); + + shift = isl_val_neg(shift); + shift = isl_val_div(shift, isl_val_copy(d)); + shift = isl_val_ceil(shift); + + t = isl_val_copy(shift); + t = isl_val_mul(t, isl_val_copy(data->v)); + data->cst = isl_val_sub(data->cst, t); + + shift = isl_val_mul(shift, isl_val_copy(d)); + return isl_aff_add_constant_val(aff, shift); +} + /* Create an isl_ast_expr evaluating the div at position "pos" in "ls". - * The result is simplified in terms of build->domain. + * The result is simplified in terms of data->build->domain. + * This function may change (the sign of) data->v. * - * *change_sign is set by this function if the sign of - * the expression has changed. * "ls" is known to be non-NULL. * * Let the div be of the form floor(e/d). @@ -52,11 +164,20 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff, * * floor(e/d) = -ceil(-e/d) = -floor((-e + d - 1)/d) * - * and still use pdiv_q. + * and still use pdiv_q, while changing the sign of data->v. + * + * Otherwise, we check if + * + * e + d*floor(cst/v) + * + * is non-negative and if so, replace floor(e/d) by + * + * floor((e + s*d)/d) - s + * + * with s the minimal shift that makes the argument non-negative. */ -static __isl_give isl_ast_expr *var_div(int *change_sign, - __isl_keep isl_local_space *ls, - int pos, __isl_keep isl_ast_build *build) +static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data, + __isl_keep isl_local_space *ls, int pos) { isl_ctx *ctx = isl_local_space_get_ctx(ls); isl_aff *aff; @@ -71,18 +192,23 @@ static __isl_give isl_ast_expr *var_div(int *change_sign, type = isl_ast_op_fdiv_q; if (isl_options_get_ast_build_prefer_pdiv(ctx)) { - int non_neg = isl_ast_build_aff_is_nonneg(build, aff); + int non_neg = isl_ast_build_aff_is_nonneg(data->build, aff); if (non_neg >= 0 && !non_neg) { isl_aff *opp = oppose_div_arg(isl_aff_copy(aff), isl_val_copy(d)); - non_neg = isl_ast_build_aff_is_nonneg(build, opp); + non_neg = isl_ast_build_aff_is_nonneg(data->build, opp); if (non_neg >= 0 && non_neg) { - *change_sign = 1; + data->v = isl_val_neg(data->v); isl_aff_free(aff); aff = opp; } else isl_aff_free(opp); } + if (non_neg >= 0 && !non_neg) { + non_neg = is_non_neg_after_stealing(aff, d, data); + if (non_neg >= 0 && non_neg) + aff = steal_from_cst(aff, d, data); + } if (non_neg < 0) aff = isl_aff_free(aff); else if (non_neg) @@ -90,33 +216,30 @@ static __isl_give isl_ast_expr *var_div(int *change_sign, } isl_val_free(d); - num = isl_ast_expr_from_aff(aff, build); + num = isl_ast_expr_from_aff(aff, data->build); return isl_ast_expr_alloc_binary(type, num, den); } /* Create an isl_ast_expr evaluating the specified dimension of "ls". - * The result is simplified in terms of build->domain. - * - * *change_sign is set by this function if the sign of - * the expression has changed. + * The result is simplified in terms of data->build->domain. + * This function may change (the sign of) data->v. * * The isl_ast_expr is constructed based on the type of the dimension. * - divs are constructed by var_div - * - set variables are constructed from the iterator isl_ids in "build" + * - set variables are constructed from the iterator isl_ids in data->build * - parameters are constructed from the isl_ids in "ls" */ -static __isl_give isl_ast_expr *var(int *change_sign, - __isl_keep isl_local_space *ls, - enum isl_dim_type type, int pos, __isl_keep isl_ast_build *build) +static __isl_give isl_ast_expr *var(struct isl_ast_add_term_data *data, + __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos) { isl_ctx *ctx = isl_local_space_get_ctx(ls); isl_id *id; if (type == isl_dim_div) - return var_div(change_sign, ls, pos, build); + return var_div(data, ls, pos); if (type == isl_dim_set) { - id = isl_ast_build_get_iterator_id(build, pos); + id = isl_ast_build_get_iterator_id(data->build, pos); return isl_ast_expr_from_id(id); } @@ -270,6 +393,9 @@ error: /* Add an expression for "*v" times the specified dimension of "ls" * to expr. + * If the dimension is an integer division, then this function + * may modify data->cst in order to make the numerator non-negative. + * The result is simplified in terms of data->build->domain. * * Let e be the expression for the specified dimension, * multiplied by the absolute value of "*v". @@ -291,18 +417,16 @@ error: static __isl_give isl_ast_expr *isl_ast_expr_add_term( __isl_take isl_ast_expr *expr, __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos, - __isl_take isl_val *v, __isl_keep isl_ast_build *build) + __isl_take isl_val *v, struct isl_ast_add_term_data *data) { isl_ast_expr *term; - int change_sign; if (!expr) return NULL; - change_sign = 0; - term = var(&change_sign, ls, type, pos, build); - if (change_sign) - v = isl_val_neg(v); + data->v = v; + term = var(data, ls, type, pos); + v = data->v; if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) { v = isl_val_neg(v); @@ -683,12 +807,12 @@ static int try_extract_mod(struct isl_extract_mod_data *data) { isl_basic_set *hull; isl_val *v1, *v2; - int r; + int r, n; if (!data->build) goto error; - int n = isl_aff_dim(data->div, isl_dim_div); + n = isl_aff_dim(data->div, isl_dim_div); if (isl_aff_involves_dims(data->div, isl_dim_div, 0, n)) return extract_nonneg_mod(data); @@ -948,6 +1072,7 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div }; enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div }; isl_local_space *ls; + struct isl_ast_add_term_data data; if (!aff) return NULL; @@ -962,6 +1087,8 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, ls = isl_aff_get_domain_local_space(aff); + data.build = build; + data.cst = isl_aff_get_constant_val(aff); for (i = 0; i < 3; ++i) { n = isl_aff_dim(aff, t[i]); for (j = 0; j < n; ++j) { @@ -973,12 +1100,11 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, continue; } expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, build); + ls, l[i], j, v, &data); } } - v = isl_aff_get_constant_val(aff); - expr = isl_ast_expr_add_int(expr, v); + expr = isl_ast_expr_add_int(expr, data.cst); isl_local_space_free(ls); isl_aff_free(aff); @@ -987,10 +1113,10 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, /* Add terms to "expr" for each variable in "aff" with a coefficient * with sign equal to "sign". - * The result is simplified in terms of build->domain. + * The result is simplified in terms of data->build->domain. */ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, - __isl_keep isl_aff *aff, int sign, __isl_keep isl_ast_build *build) + __isl_keep isl_aff *aff, int sign, struct isl_ast_add_term_data *data) { int i, j; isl_val *v; @@ -1010,7 +1136,7 @@ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, } v = isl_val_abs(v); expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, build); + ls, l[i], j, v, data); } } @@ -1204,9 +1330,9 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( isl_ast_expr *expr_neg; isl_ast_expr *expr; isl_aff *aff; - isl_val *v; int eq; enum isl_ast_op_type type; + struct isl_ast_add_term_data data; if (!constraint) return NULL; @@ -1232,15 +1358,18 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( aff = extract_modulos(aff, &expr_pos, &expr_neg, build); - expr_pos = add_signed_terms(expr_pos, aff, 1, build); - expr_neg = add_signed_terms(expr_neg, aff, -1, build); - - v = isl_aff_get_constant_val(aff); - if (constant_is_considered_positive(v, expr_pos, expr_neg)) { - expr_pos = isl_ast_expr_add_int(expr_pos, v); + data.build = build; + data.cst = isl_aff_get_constant_val(aff); + expr_pos = add_signed_terms(expr_pos, aff, 1, &data); + data.cst = isl_val_neg(data.cst); + expr_neg = add_signed_terms(expr_neg, aff, -1, &data); + data.cst = isl_val_neg(data.cst); + + if (constant_is_considered_positive(data.cst, expr_pos, expr_neg)) { + expr_pos = isl_ast_expr_add_int(expr_pos, data.cst); } else { - v = isl_val_neg(v); - expr_neg = isl_ast_expr_add_int(expr_neg, v); + data.cst = isl_val_neg(data.cst); + expr_neg = isl_ast_expr_add_int(expr_neg, data.cst); } if (isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int && @@ -1406,7 +1535,7 @@ struct isl_from_pw_aff_data { * If this is the last pair, then data->next is set to evaluate aff * and the domain is ignored. * Otherwise, data->next is set to a select operation that selects - * an isl_ast_expr correponding to "aff" on "set" and to an expression + * an isl_ast_expr corresponding to "aff" on "set" and to an expression * that will be filled in by later calls otherwise. * * In both cases, the constraints of "set" are added to the generated diff --git a/polly/lib/External/isl/isl_ast_codegen.c b/polly/lib/External/isl/isl_ast_codegen.c index 679d2612d69..7159d7a281b 100644 --- a/polly/lib/External/isl/isl_ast_codegen.c +++ b/polly/lib/External/isl/isl_ast_codegen.c @@ -665,36 +665,43 @@ error: * If we have generated a degenerate loop, then add the guard * implied by "bounds" on the outer dimensions, i.e., the guard * that ensures that the single value actually exists. + * Since there may also be guards implied by a combination + * of these constraints, we first combine them before + * deriving the implied constraints. */ static __isl_give isl_set *add_implied_guards(__isl_take isl_set *guard, int degenerate, __isl_keep isl_basic_set *bounds, __isl_keep isl_ast_build *build) { int depth, has_stride; - isl_set *dom; + isl_space *space; + isl_set *dom, *set; depth = isl_ast_build_get_depth(build); has_stride = isl_ast_build_has_stride(build, depth); if (!has_stride && !degenerate) return guard; + space = isl_basic_set_get_space(bounds); + dom = isl_set_universe(space); + if (degenerate) { bounds = isl_basic_set_copy(bounds); bounds = isl_basic_set_drop_constraints_not_involving_dims( bounds, isl_dim_set, depth, 1); - dom = isl_set_from_basic_set(bounds); - dom = isl_set_eliminate(dom, isl_dim_set, depth, 1); - dom = isl_ast_build_compute_gist(build, dom); - guard = isl_set_intersect(guard, dom); + set = isl_set_from_basic_set(bounds); + dom = isl_set_intersect(dom, set); } if (has_stride) { - dom = isl_ast_build_get_stride_constraint(build); - dom = isl_set_eliminate(dom, isl_dim_set, depth, 1); - dom = isl_ast_build_compute_gist(build, dom); - guard = isl_set_intersect(guard, dom); + set = isl_ast_build_get_stride_constraint(build); + dom = isl_set_intersect(dom, set); } + dom = isl_set_eliminate(dom, isl_dim_set, depth, 1); + dom = isl_ast_build_compute_gist(build, dom); + guard = isl_set_intersect(guard, dom); + return guard; } @@ -2228,22 +2235,143 @@ static __isl_give isl_set *separate_schedule_domains( /* Temporary data used during the search for a lower bound for unrolling. * + * "build" is the build in which the unrolling will be performed * "domain" is the original set for which to find a lower bound * "depth" is the dimension for which to find a lower boudn + * "expansion" is the expansion that needs to be applied to "domain" + * in the unrolling that will be performed * * "lower" is the best lower bound found so far. It is NULL if we have not * found any yet. * "n" is the corresponding size. If lower is NULL, then the value of n * is undefined. + * "n_div" is the maximal number of integer divisions in the first + * unrolled iteration (after expansion). It is set to -1 if it hasn't + * been computed yet. */ struct isl_find_unroll_data { + isl_ast_build *build; isl_set *domain; int depth; + isl_basic_map *expansion; isl_aff *lower; int *n; + int n_div; }; +/* Return the constraint + * + * i_"depth" = aff + offset + */ +static __isl_give isl_constraint *at_offset(int depth, __isl_keep isl_aff *aff, + int offset) +{ + aff = isl_aff_copy(aff); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, depth, -1); + aff = isl_aff_add_constant_si(aff, offset); + return isl_equality_from_aff(aff); +} + +/* Update *user to the number of integer divsions in the first element + * of "ma", if it is larger than the current value. + */ +static int update_n_div(__isl_take isl_set *set, __isl_take isl_multi_aff *ma, + void *user) +{ + isl_aff *aff; + int *n = user; + int n_div; + + aff = isl_multi_aff_get_aff(ma, 0); + n_div = isl_aff_dim(aff, isl_dim_div); + isl_aff_free(aff); + isl_multi_aff_free(ma); + isl_set_free(set); + + if (n_div > *n) + *n = n_div; + + return aff ? 0 : -1; +} + +/* Get the number of integer divisions in the expression for the iterator + * value at the first slice in the unrolling based on lower bound "lower", + * taking into account the expansion that needs to be performed on this slice. + */ +static int get_expanded_n_div(struct isl_find_unroll_data *data, + __isl_keep isl_aff *lower) +{ + isl_constraint *c; + isl_set *set; + isl_map *it_map, *expansion; + isl_pw_multi_aff *pma; + int n; + + c = at_offset(data->depth, lower, 0); + set = isl_set_copy(data->domain); + set = isl_set_add_constraint(set, c); + expansion = isl_map_from_basic_map(isl_basic_map_copy(data->expansion)); + set = isl_set_apply(set, expansion); + it_map = isl_ast_build_map_to_iterator(data->build, set); + pma = isl_pw_multi_aff_from_map(it_map); + n = 0; + if (isl_pw_multi_aff_foreach_piece(pma, &update_n_div, &n) < 0) + n = -1; + isl_pw_multi_aff_free(pma); + + return n; +} + +/* Is the lower bound "lower" with corresponding iteration count "n" + * better than the one stored in "data"? + * If there is no upper bound on the iteration count ("n" is infinity) or + * if the count is too large, then we cannot use this lower bound. + * Otherwise, if there was no previous lower bound or + * if the iteration count of the new lower bound is smaller than + * the iteration count of the previous lower bound, then we consider + * the new lower bound to be better. + * If the iteration count is the same, then compare the number + * of integer divisions that would be needed to express + * the iterator value at the first slice in the unrolling + * according to the lower bound. If we end up computing this + * number, then store the lowest value in data->n_div. + */ +static int is_better_lower_bound(struct isl_find_unroll_data *data, + __isl_keep isl_aff *lower, __isl_keep isl_val *n) +{ + int cmp; + int n_div; + + if (!n) + return -1; + if (isl_val_is_infty(n)) + return 0; + if (isl_val_cmp_si(n, INT_MAX) > 0) + return 0; + if (!data->lower) + return 1; + cmp = isl_val_cmp_si(n, *data->n); + if (cmp < 0) + return 1; + if (cmp > 0) + return 0; + if (data->n_div < 0) + data->n_div = get_expanded_n_div(data, data->lower); + if (data->n_div < 0) + return -1; + if (data->n_div == 0) + return 0; + n_div = get_expanded_n_div(data, lower); + if (n_div < 0) + return -1; + if (n_div >= data->n_div) + return 0; + data->n_div = n_div; + + return 1; +} + /* Check if we can use "c" as a lower bound and if it is better than * any previously found lower bound. * @@ -2267,14 +2395,15 @@ struct isl_find_unroll_data { * * meaning that we can use ceil(f(j)/a)) as a lower bound for unrolling. * We just need to check if we have found any lower bound before and - * if the new lower bound is better (smaller n) than the previously found - * lower bounds. + * if the new lower bound is better (smaller n or fewer integer divisions) + * than the previously found lower bounds. */ static int update_unrolling_lower_bound(struct isl_find_unroll_data *data, __isl_keep isl_constraint *c) { isl_aff *aff, *lower; isl_val *max; + int better; if (!isl_constraint_is_lower_bound(c, isl_dim_set, data->depth)) return 0; @@ -2288,27 +2417,19 @@ static int update_unrolling_lower_bound(struct isl_find_unroll_data *data, max = isl_set_max_val(data->domain, aff); isl_aff_free(aff); - if (!max) - goto error; - if (isl_val_is_infty(max)) { + better = is_better_lower_bound(data, lower, max); + if (better < 0 || !better) { isl_val_free(max); isl_aff_free(lower); - return 0; + return better < 0 ? -1 : 0; } - if (isl_val_cmp_si(max, INT_MAX) <= 0 && - (!data->lower || isl_val_cmp_si(max, *data->n) < 0)) { - isl_aff_free(data->lower); - data->lower = lower; - *data->n = isl_val_get_num_si(max); - } else - isl_aff_free(lower); + isl_aff_free(data->lower); + data->lower = lower; + *data->n = isl_val_get_num_si(max); isl_val_free(max); return 1; -error: - isl_aff_free(lower); - return -1; } /* Check if we can use "c" as a lower bound and if it is better than @@ -2334,6 +2455,9 @@ static int constraint_find_unroll(__isl_take isl_constraint *c, void *user) * where d is "depth" and l(i) depends only on earlier dimensions. * Furthermore, try and find a lower bound such that n is as small as possible. * In particular, "n" needs to be finite. + * "build" is the build in which the unrolling will be performed. + * "expansion" is the expansion that needs to be applied to "domain" + * in the unrolling that will be performed. * * Inner dimensions have been eliminated from "domain" by the caller. * @@ -2347,10 +2471,12 @@ static int constraint_find_unroll(__isl_take isl_constraint *c, void *user) * If we cannot find a suitable lower bound, then we consider that * to be an error. */ -static __isl_give isl_aff *find_unroll_lower_bound(__isl_keep isl_set *domain, - int depth, int *n) +static __isl_give isl_aff *find_unroll_lower_bound( + __isl_keep isl_ast_build *build, __isl_keep isl_set *domain, + int depth, __isl_keep isl_basic_map *expansion, int *n) { - struct isl_find_unroll_data data = { domain, depth, NULL, n }; + struct isl_find_unroll_data data = + { build, domain, depth, expansion, NULL, n, -1 }; isl_basic_set *hull; hull = isl_set_simple_hull(isl_set_copy(domain)); @@ -2371,19 +2497,6 @@ error: return isl_aff_free(data.lower); } -/* Return the constraint - * - * i_"depth" = aff + offset - */ -static __isl_give isl_constraint *at_offset(int depth, __isl_keep isl_aff *aff, - int offset) -{ - aff = isl_aff_copy(aff); - aff = isl_aff_add_coefficient_si(aff, isl_dim_in, depth, -1); - aff = isl_aff_add_constant_si(aff, offset); - return isl_equality_from_aff(aff); -} - /* Data structure for storing the results and the intermediate objects * of compute_domains. * @@ -2482,12 +2595,13 @@ static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains, isl_ast_build_free(build); - lower = find_unroll_lower_bound(domain, depth, &n); + bmap = isl_basic_map_from_multi_aff(expansion); + + lower = find_unroll_lower_bound(domains->build, domain, depth, bmap, + &n); if (!lower) class_domain = isl_set_free(class_domain); - bmap = isl_basic_map_from_multi_aff(expansion); - unroll_domain = isl_set_empty(isl_set_get_space(domain)); for (i = 0; class_domain && i < n; ++i) { @@ -3912,6 +4026,7 @@ __isl_give isl_ast_node *isl_ast_build_ast_from_schedule( build = isl_ast_build_copy(build); build = isl_ast_build_set_single_valued(build, 0); schedule = isl_union_map_coalesce(schedule); + schedule = isl_union_map_remove_redundancies(schedule); executed = isl_union_map_reverse(schedule); list = generate_code(executed, isl_ast_build_copy(build), 0); node = isl_ast_node_from_graft_list(list, build); diff --git a/polly/lib/External/isl/isl_coalesce.c b/polly/lib/External/isl/isl_coalesce.c index 2899e03b2d3..2ebe600ff6f 100644 --- a/polly/lib/External/isl/isl_coalesce.c +++ b/polly/lib/External/isl/isl_coalesce.c @@ -2,6 +2,7 @@ * Copyright 2008-2009 Katholieke Universiteit Leuven * Copyright 2010 INRIA Saclay * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt * * Use of this software is governed by the MIT license * @@ -10,6 +11,8 @@ * 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 + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France */ #include "isl_map_private.h" @@ -19,6 +22,7 @@ #include <isl_mat_private.h> #include <isl_local_space_private.h> #include <isl_vec_private.h> +#include <isl_aff_private.h> #define STATUS_ERROR -1 #define STATUS_REDUNDANT 1 @@ -143,83 +147,250 @@ static int all(int *con, unsigned len, int status) return 1; } -static void drop(struct isl_map *map, int i, struct isl_tab **tabs) +/* Internal information associated to a basic map in a map + * that is to be coalesced by isl_map_coalesce. + * + * "bmap" is the basic map itself (or NULL if "removed" is set) + * "tab" is the corresponding tableau (or NULL if "removed" is set) + * "hull_hash" identifies the affine space in which "bmap" lives. + * "removed" is set if this basic map has been removed from the map + * "simplify" is set if this basic map may have some unknown integer + * divisions that were not present in the input basic maps. The basic + * map should then be simplified such that we may be able to find + * a definition among the constraints. + * + * "eq" and "ineq" are only set if we are currently trying to coalesce + * this basic map with another basic map, in which case they represent + * the position of the inequalities of this basic map with respect to + * the other basic map. The number of elements in the "eq" array + * is twice the number of equalities in the "bmap", corresponding + * to the two inequalities that make up each equality. + */ +struct isl_coalesce_info { + isl_basic_map *bmap; + struct isl_tab *tab; + uint32_t hull_hash; + int removed; + int simplify; + int *eq; + int *ineq; +}; + +/* Compute the hash of the (apparent) affine hull of info->bmap (with + * the existentially quantified variables removed) and store it + * in info->hash. + */ +static int coalesce_info_set_hull_hash(struct isl_coalesce_info *info) { - isl_basic_map_free(map->p[i]); - isl_tab_free(tabs[i]); + isl_basic_map *hull; + unsigned n_div; + + hull = isl_basic_map_copy(info->bmap); + hull = isl_basic_map_plain_affine_hull(hull); + n_div = isl_basic_map_dim(hull, isl_dim_div); + hull = isl_basic_map_drop_constraints_involving_dims(hull, + isl_dim_div, 0, n_div); + info->hull_hash = isl_basic_map_get_hash(hull); + isl_basic_map_free(hull); + + return hull ? 0 : -1; +} - if (i != map->n - 1) { - map->p[i] = map->p[map->n - 1]; - tabs[i] = tabs[map->n - 1]; +/* Free all the allocated memory in an array + * of "n" isl_coalesce_info elements. + */ +static void clear_coalesce_info(int n, struct isl_coalesce_info *info) +{ + int i; + + if (!info) + return; + + for (i = 0; i < n; ++i) { + isl_basic_map_free(info[i].bmap); + isl_tab_free(info[i].tab); } - tabs[map->n - 1] = NULL; - map->n--; + + free(info); } -/* Replace the pair of basic maps i and j by the basic map bounded - * by the valid constraints in both basic maps and the constraint - * in extra (if not NULL). +/* Drop the basic map represented by "info". + * That is, clear the memory associated to the entry and + * mark it as having been removed. */ -static int fuse(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j, - __isl_keep isl_mat *extra) +static void drop(struct isl_coalesce_info *info) { - int k, l; - struct isl_basic_map *fused = NULL; - struct isl_tab *fused_tab = NULL; - unsigned total = isl_basic_map_total_dim(map->p[i]); - unsigned extra_rows = extra ? extra->n_row : 0; + info->bmap = isl_basic_map_free(info->bmap); + isl_tab_free(info->tab); + info->tab = NULL; + info->removed = 1; +} - fused = isl_basic_map_alloc_space(isl_space_copy(map->p[i]->dim), - map->p[i]->n_div, - map->p[i]->n_eq + map->p[j]->n_eq, - map->p[i]->n_ineq + map->p[j]->n_ineq + extra_rows); - if (!fused) - goto error; +/* Exchange the information in "info1" with that in "info2". + */ +static void exchange(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2) +{ + struct isl_coalesce_info info; - for (k = 0; k < map->p[i]->n_eq; ++k) { - if (eq_i && (eq_i[2 * k] != STATUS_VALID || - eq_i[2 * k + 1] != STATUS_VALID)) - continue; - l = isl_basic_map_alloc_equality(fused); - if (l < 0) - goto error; - isl_seq_cpy(fused->eq[l], map->p[i]->eq[k], 1 + total); - } + info = *info1; + *info1 = *info2; + *info2 = info; +} - for (k = 0; k < map->p[j]->n_eq; ++k) { - if (eq_j && (eq_j[2 * k] != STATUS_VALID || - eq_j[2 * k + 1] != STATUS_VALID)) - continue; - l = isl_basic_map_alloc_equality(fused); - if (l < 0) - goto error; - isl_seq_cpy(fused->eq[l], map->p[j]->eq[k], 1 + total); +/* This type represents the kind of change that has been performed + * while trying to coalesce two basic maps. + * + * isl_change_none: nothing was changed + * isl_change_drop_first: the first basic map was removed + * isl_change_drop_second: the second basic map was removed + * isl_change_fuse: the two basic maps were replaced by a new basic map. + */ +enum isl_change { + isl_change_error = -1, + isl_change_none = 0, + isl_change_drop_first, + isl_change_drop_second, + isl_change_fuse, +}; + +/* Update "change" based on an interchange of the first and the second + * basic map. That is, interchange isl_change_drop_first and + * isl_change_drop_second. + */ +static enum isl_change invert_change(enum isl_change change) +{ + switch (change) { + case isl_change_error: + return isl_change_error; + case isl_change_none: + return isl_change_none; + case isl_change_drop_first: + return isl_change_drop_second; + case isl_change_drop_second: + return isl_change_drop_first; + case isl_change_fuse: + return isl_change_fuse; } +} - for (k = 0; k < map->p[i]->n_ineq; ++k) { - if (ineq_i[k] != STATUS_VALID) - continue; - l = isl_basic_map_alloc_inequality(fused); - if (l < 0) - goto error; - isl_seq_cpy(fused->ineq[l], map->p[i]->ineq[k], 1 + total); +/* Add the valid constraints of the basic map represented by "info" + * to "bmap". "len" is the size of the constraints. + * If only one of the pair of inequalities that make up an equality + * is valid, then add that inequality. + */ +static __isl_give isl_basic_map *add_valid_constraints( + __isl_take isl_basic_map *bmap, struct isl_coalesce_info *info, + unsigned len) +{ + int k, l; + + if (!bmap) + return NULL; + + for (k = 0; k < info->bmap->n_eq; ++k) { + if (info->eq[2 * k] == STATUS_VALID && + info->eq[2 * k + 1] == STATUS_VALID) { + l = isl_basic_map_alloc_equality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->eq[l], info->bmap->eq[k], len); + } else if (info->eq[2 * k] == STATUS_VALID) { + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_neg(bmap->ineq[l], info->bmap->eq[k], len); + } else if (info->eq[2 * k + 1] == STATUS_VALID) { + l = isl_basic_map_alloc_inequality(bmap); + if (l < 0) + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->ineq[l], info->bmap->eq[k], len); + } } - for (k = 0; k < map->p[j]->n_ineq; ++k) { - if (ineq_j[k] != STATUS_VALID) + for (k = 0; k < info->bmap->n_ineq; ++k) { + if (info->ineq[k] != STATUS_VALID) continue; - l = isl_basic_map_alloc_inequality(fused); + l = isl_basic_map_alloc_inequality(bmap); if (l < 0) - goto error; - isl_seq_cpy(fused->ineq[l], map->p[j]->ineq[k], 1 + total); + return isl_basic_map_free(bmap); + isl_seq_cpy(bmap->ineq[l], info->bmap->ineq[k], len); } - for (k = 0; k < map->p[i]->n_div; ++k) { + return bmap; +} + +/* Is "bmap" defined by a number of (non-redundant) constraints that + * is greater than the number of constraints of basic maps i and j combined? + * Equalities are counted as two inequalities. + */ +static int number_of_constraints_increases(int i, int j, + struct isl_coalesce_info *info, + __isl_keep isl_basic_map *bmap, struct isl_tab *tab) +{ + int k, n_old, n_new; + + n_old = 2 * info[i].bmap->n_eq + info[i].bmap->n_ineq; + n_old += 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq; + + n_new = 2 * bmap->n_eq; + for (k = 0; k < bmap->n_ineq; ++k) + if (!isl_tab_is_redundant(tab, bmap->n_eq + k)) + ++n_new; + + return n_new > n_old; +} + +/* Replace the pair of basic maps i and j by the basic map bounded + * by the valid constraints in both basic maps and the constraints + * in extra (if not NULL). + * Place the fused basic map in the position that is the smallest of i and j. + * + * If "detect_equalities" is set, then look for equalities encoded + * as pairs of inequalities. + * If "check_number" is set, then the original basic maps are only + * replaced if the total number of constraints does not increase. + * While the number of integer divisions in the two basic maps + * is assumed to be the same, the actual definitions may be different. + * We only copy the definition from one of the basic map if it is + * the same as that of the other basic map. Otherwise, we mark + * the integer division as unknown and schedule for the basic map + * to be simplified in an attempt to recover the integer division definition. + */ +static enum isl_change fuse(int i, int j, struct isl_coalesce_info *info, + __isl_keep isl_mat *extra, int detect_equalities, int check_number) +{ + int k, l; + struct isl_basic_map *fused = NULL; + struct isl_tab *fused_tab = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); + unsigned extra_rows = extra ? extra->n_row : 0; + unsigned n_eq, n_ineq; + + if (j < i) + return fuse(j, i, info, extra, detect_equalities, check_number); + + n_eq = info[i].bmap->n_eq + info[j].bmap->n_eq; + n_ineq = info[i].bmap->n_ineq + info[j].bmap->n_ineq; + fused = isl_basic_map_alloc_space(isl_space_copy(info[i].bmap->dim), + info[i].bmap->n_div, n_eq, n_eq + n_ineq + extra_rows); + fused = add_valid_constraints(fused, &info[i], 1 + total); + fused = add_valid_constraints(fused, &info[j], 1 + total); + if (!fused) + goto error; + + for (k = 0; k < info[i].bmap->n_div; ++k) { int l = isl_basic_map_alloc_div(fused); if (l < 0) goto error; - isl_seq_cpy(fused->div[l], map->p[i]->div[k], 1 + 1 + total); + if (isl_seq_eq(info[i].bmap->div[k], info[j].bmap->div[k], + 1 + 1 + total)) { + isl_seq_cpy(fused->div[l], info[i].bmap->div[k], + 1 + 1 + total); + } else { + isl_int_set_si(fused->div[l][0], 0); + info[i].simplify = 1; + } } for (k = 0; k < extra_rows; ++k) { @@ -229,27 +400,37 @@ static int fuse(struct isl_map *map, int i, int j, isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total); } + if (detect_equalities) + fused = isl_basic_map_detect_inequality_pairs(fused, NULL); fused = isl_basic_map_gauss(fused, NULL); ISL_F_SET(fused, ISL_BASIC_MAP_FINAL); - if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) && - ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL)) + if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) && + ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL)) ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL); fused_tab = isl_tab_from_basic_map(fused, 0); if (isl_tab_detect_redundant(fused_tab) < 0) goto error; - isl_basic_map_free(map->p[i]); - map->p[i] = fused; - isl_tab_free(tabs[i]); - tabs[i] = fused_tab; - drop(map, j, tabs); + if (check_number && + number_of_constraints_increases(i, j, info, fused, fused_tab)) { + isl_tab_free(fused_tab); + isl_basic_map_free(fused); + return isl_change_none; + } - return 1; + info[i].simplify |= info[j].simplify; + isl_basic_map_free(info[i].bmap); + info[i].bmap = fused; + isl_tab_free(info[i].tab); + info[i].tab = fused_tab; + drop(&info[j]); + + return isl_change_fuse; error: isl_tab_free(fused_tab); isl_basic_map_free(fused); - return -1; + return isl_change_error; } /* Given a pair of basic maps i and j such that all constraints are either @@ -257,79 +438,99 @@ error: * constraints of i lie entirely within basic map j. * If so, replace the pair by the basic map consisting of the valid * constraints in both basic maps. + * Checking whether the facet lies entirely within basic map j + * is performed by checking whether the constraints of basic map j + * are valid for the facet. These tests are performed on a rational + * tableau to avoid the theoretical possibility that a constraint + * that was considered to be a cut constraint for the entire basic map i + * happens to be considered to be a valid constraint for the facet, + * even though it cuts off the same rational points. * * To see that we are not introducing any extra points, call the * two basic maps A and B and the resulting map U and let x * be an element of U \setminus ( A \cup B ). - * Then there is a pair of cut constraints c_1 and c_2 in A and B such that x - * violates them. Let X be the intersection of U with the opposites - * of these constraints. Then x \in X. - * The facet corresponding to c_1 contains the corresponding facet of A. - * This facet is entirely contained in B, so c_2 is valid on the facet. - * However, since it is also (part of) a facet of X, -c_2 is also valid - * on the facet. This means c_2 is saturated on the facet, so c_1 and - * c_2 must be opposites of each other, but then x could not violate - * both of them. + * A line connecting x with an element of A \cup B meets a facet F + * of either A or B. Assume it is a facet of B and let c_1 be + * the corresponding facet constraint. We have c_1(x) < 0 and + * so c_1 is a cut constraint. This implies that there is some + * (possibly rational) point x' satisfying the constraints of A + * and the opposite of c_1 as otherwise c_1 would have been marked + * valid for A. The line connecting x and x' meets a facet of A + * in a (possibly rational) point that also violates c_1, but this + * is impossible since all cut constraints of B are valid for all + * cut facets of A. + * In case F is a facet of A rather than B, then we can apply the + * above reasoning to find a facet of B separating x from A \cup B first. */ -static int check_facets(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *ineq_i, int *ineq_j) +static enum isl_change check_facets(int i, int j, + struct isl_coalesce_info *info) { int k, l; - struct isl_tab_undo *snap; - unsigned n_eq = map->p[i]->n_eq; + struct isl_tab_undo *snap, *snap2; + unsigned n_eq = info[i].bmap->n_eq; - snap = isl_tab_snap(tabs[i]); + snap = isl_tab_snap(info[i].tab); + if (isl_tab_mark_rational(info[i].tab) < 0) + return isl_change_error; + snap2 = isl_tab_snap(info[i].tab); - for (k = 0; k < map->p[i]->n_ineq; ++k) { - if (ineq_i[k] != STATUS_CUT) + for (k = 0; k < info[i].bmap->n_ineq; ++k) { + if (info[i].ineq[k] != STATUS_CUT) continue; - if (isl_tab_select_facet(tabs[i], n_eq + k) < 0) - return -1; - for (l = 0; l < map->p[j]->n_ineq; ++l) { + if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0) + return isl_change_error; + for (l = 0; l < info[j].bmap->n_ineq; ++l) { int stat; - if (ineq_j[l] != STATUS_CUT) + if (info[j].ineq[l] != STATUS_CUT) continue; - stat = status_in(map->p[j]->ineq[l], tabs[i]); + stat = status_in(info[j].bmap->ineq[l], info[i].tab); if (stat != STATUS_VALID) break; } - if (isl_tab_rollback(tabs[i], snap) < 0) - return -1; - if (l < map->p[j]->n_ineq) + if (isl_tab_rollback(info[i].tab, snap2) < 0) + return isl_change_error; + if (l < info[j].bmap->n_ineq) break; } - if (k < map->p[i]->n_ineq) - /* BAD CUT PAIR */ - return 0; - return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL); + if (k < info[i].bmap->n_ineq) { + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; + return isl_change_none; + } + return fuse(i, j, info, NULL, 0, 0); } -/* Check if basic map "i" contains the basic map represented +/* Check if info->bmap contains the basic map represented * by the tableau "tab". + * For each equality, we check both the constraint itself + * (as an inequality) and its negation. Make sure the + * equality is returned to its original state before returning. */ -static int contains(struct isl_map *map, int i, int *ineq_i, - struct isl_tab *tab) +static int contains(struct isl_coalesce_info *info, struct isl_tab *tab) { - int k, l; + int k; unsigned dim; + isl_basic_map *bmap = info->bmap; - 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; - } + dim = isl_basic_map_total_dim(bmap); + for (k = 0; k < bmap->n_eq; ++k) { + int stat; + isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim); + stat = status_in(bmap->eq[k], tab); + isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim); + if (stat != STATUS_VALID) + return 0; + stat = status_in(bmap->eq[k], tab); + if (stat != STATUS_VALID) + return 0; } - for (k = 0; k < map->p[i]->n_ineq; ++k) { + for (k = 0; k < bmap->n_ineq; ++k) { int stat; - if (ineq_i[k] == STATUS_REDUNDANT) + if (info->ineq[k] == STATUS_REDUNDANT) continue; - stat = status_in(map->p[i]->ineq[k], tab); + stat = status_in(bmap->ineq[k], tab); if (stat != STATUS_VALID) return 0; } @@ -373,53 +574,53 @@ static int contains(struct isl_map *map, int i, int *ineq_i, * | || | | | * |__||_/ |_____/ */ -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) +static enum isl_change is_adj_ineq_extension(int i, int j, + struct isl_coalesce_info *info) { 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]); + unsigned n_eq = info[i].bmap->n_eq; + unsigned total = isl_basic_map_total_dim(info[i].bmap); int r; - if (isl_tab_extend_cons(tabs[i], 1 + map->p[j]->n_ineq) < 0) - return -1; + if (isl_tab_extend_cons(info[i].tab, 1 + info[j].bmap->n_ineq) < 0) + return isl_change_error; - for (k = 0; k < map->p[i]->n_ineq; ++k) - if (ineq_i[k] == STATUS_ADJ_INEQ) + for (k = 0; k < info[i].bmap->n_ineq; ++k) + if (info[i].ineq[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); + if (k >= info[i].bmap->n_ineq) + isl_die(isl_basic_map_get_ctx(info[i].bmap), isl_error_internal, + "info[i].ineq should have exactly one STATUS_ADJ_INEQ", + return isl_change_error); - snap = isl_tab_snap(tabs[i]); + snap = isl_tab_snap(info[i].tab); - if (isl_tab_unrestrict(tabs[i], n_eq + k) < 0) - return -1; + if (isl_tab_unrestrict(info[i].tab, n_eq + k) < 0) + return isl_change_error; - 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); + isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total); + isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1); + r = isl_tab_add_ineq(info[i].tab, info[i].bmap->ineq[k]); + isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total); + isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1); if (r < 0) - return -1; + return isl_change_error; - for (k = 0; k < map->p[j]->n_ineq; ++k) { - if (ineq_j[k] != STATUS_VALID) + for (k = 0; k < info[j].bmap->n_ineq; ++k) { + if (info[j].ineq[k] != STATUS_VALID) continue; - if (isl_tab_add_ineq(tabs[i], map->p[j]->ineq[k]) < 0) - return -1; + if (isl_tab_add_ineq(info[i].tab, info[j].bmap->ineq[k]) < 0) + return isl_change_error; } - if (contains(map, j, ineq_j, tabs[i])) - return fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, NULL); + if (contains(&info[j], info[i].tab)) + return fuse(i, j, info, NULL, 0, 0); - if (isl_tab_rollback(tabs[i], snap) < 0) - return -1; + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; - return 0; + return isl_change_none; } @@ -454,35 +655,33 @@ static int is_adj_ineq_extension(__isl_keep isl_map *map, int i, int j, * 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 *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change check_adj_ineq(int i, int j, + struct isl_coalesce_info *info) { int count_i, count_j; int cut_i, cut_j; - 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); + count_i = count(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ); + count_j = count(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ); if (count_i != 1 && count_j != 1) - return 0; + return isl_change_none; - 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); + cut_i = any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT) || + any(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT); + cut_j = any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT) || + any(info[j].ineq, info[j].bmap->n_ineq, STATUS_CUT); if (!cut_i && !cut_j && count_i == 1 && count_j == 1) - return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL); + return fuse(i, j, info, NULL, 0, 0); if (count_i == 1 && !cut_i) - return is_adj_ineq_extension(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); + return is_adj_ineq_extension(i, j, info); if (count_j == 1 && !cut_j) - return is_adj_ineq_extension(map, j, i, tabs, - eq_j, ineq_j, eq_i, ineq_i); + return is_adj_ineq_extension(j, i, info); - return 0; + return isl_change_none; } /* Basic map "i" has an inequality "k" that is adjacent to some equality @@ -496,6 +695,11 @@ static int check_adj_ineq(struct isl_map *map, int i, int j, * 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 this extension. + * Each integer division that does not have exactly the same + * definition in "i" and "j" is marked unknown and the basic map + * is scheduled to be simplified in an attempt to recover + * the integer division definition. + * Place this extension in the position that is the smallest of i and j. * ____ _____ * / || / | * / || / | @@ -503,38 +707,52 @@ static int check_adj_ineq(struct isl_map *map, int i, int j, * \ || \ | * \___|| \____| */ -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) +static enum isl_change is_adj_eq_extension(int i, int j, int k, + struct isl_coalesce_info *info) { - int changed = 0; + int change = isl_change_none; int super; struct isl_tab_undo *snap, *snap2; - unsigned n_eq = map->p[i]->n_eq; - - if (isl_tab_is_equality(tabs[i], n_eq + k)) - return 0; - - snap = isl_tab_snap(tabs[i]); - tabs[i] = isl_tab_relax(tabs[i], n_eq + k); - snap2 = isl_tab_snap(tabs[i]); - if (isl_tab_select_facet(tabs[i], n_eq + k) < 0) - return -1; - super = contains(map, j, ineq_j, tabs[i]); + unsigned n_eq = info[i].bmap->n_eq; + + if (isl_tab_is_equality(info[i].tab, n_eq + k)) + return isl_change_none; + + snap = isl_tab_snap(info[i].tab); + if (isl_tab_relax(info[i].tab, n_eq + k) < 0) + return isl_change_error; + snap2 = isl_tab_snap(info[i].tab); + if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0) + return isl_change_error; + super = contains(&info[j], info[i].tab); if (super) { - if (isl_tab_rollback(tabs[i], snap2) < 0) - return -1; - map->p[i] = isl_basic_map_cow(map->p[i]); - if (!map->p[i]) - return -1; - isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1); - ISL_F_SET(map->p[i], ISL_BASIC_MAP_FINAL); - drop(map, j, tabs); - changed = 1; + int l; + unsigned total; + + if (isl_tab_rollback(info[i].tab, snap2) < 0) + return isl_change_error; + info[i].bmap = isl_basic_map_cow(info[i].bmap); + if (!info[i].bmap) + return isl_change_error; + total = isl_basic_map_total_dim(info[i].bmap); + for (l = 0; l < info[i].bmap->n_div; ++l) + if (!isl_seq_eq(info[i].bmap->div[l], + info[j].bmap->div[l], 1 + 1 + total)) { + isl_int_set_si(info[i].bmap->div[l][0], 0); + info[i].simplify = 1; + } + isl_int_add_ui(info[i].bmap->ineq[k][0], + info[i].bmap->ineq[k][0], 1); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_FINAL); + drop(&info[j]); + if (j < i) + exchange(&info[i], &info[j]); + change = isl_change_fuse; } else - if (isl_tab_rollback(tabs[i], snap) < 0) - return -1; + if (isl_tab_rollback(info[i].tab, snap) < 0) + return isl_change_error; - return changed; + return change; } /* Data structure that keeps track of the wrapping constraints @@ -551,31 +769,32 @@ struct isl_wraps { }; /* Update wraps->max to be greater than or equal to the coefficients - * in the equalities and inequalities of bmap that can be removed if we end up - * applying wrapping. + * in the equalities and inequalities of info->bmap that can be removed + * if we end up applying wrapping. */ static void wraps_update_max(struct isl_wraps *wraps, - __isl_keep isl_basic_map *bmap, int *eq, int *ineq) + struct isl_coalesce_info *info) { int k; isl_int max_k; - unsigned total = isl_basic_map_total_dim(bmap); + unsigned total = isl_basic_map_total_dim(info->bmap); isl_int_init(max_k); - for (k = 0; k < bmap->n_eq; ++k) { - if (eq[2 * k] == STATUS_VALID && - eq[2 * k + 1] == STATUS_VALID) + for (k = 0; k < info->bmap->n_eq; ++k) { + if (info->eq[2 * k] == STATUS_VALID && + info->eq[2 * k + 1] == STATUS_VALID) continue; - isl_seq_abs_max(bmap->eq[k] + 1, total, &max_k); + isl_seq_abs_max(info->bmap->eq[k] + 1, total, &max_k); if (isl_int_abs_gt(max_k, wraps->max)) isl_int_set(wraps->max, max_k); } - for (k = 0; k < bmap->n_ineq; ++k) { - if (ineq[k] == STATUS_VALID || ineq[k] == STATUS_REDUNDANT) + for (k = 0; k < info->bmap->n_ineq; ++k) { + if (info->ineq[k] == STATUS_VALID || + info->ineq[k] == STATUS_REDUNDANT) continue; - isl_seq_abs_max(bmap->ineq[k] + 1, total, &max_k); + isl_seq_abs_max(info->bmap->ineq[k] + 1, total, &max_k); if (isl_int_abs_gt(max_k, wraps->max)) isl_int_set(wraps->max, max_k); } @@ -590,8 +809,7 @@ static void wraps_update_max(struct isl_wraps *wraps, * applying wrapping. */ static void wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat, - __isl_keep isl_map *map, int i, int j, - int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) + struct isl_coalesce_info *info, int i, int j) { isl_ctx *ctx; @@ -605,8 +823,8 @@ static void wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat, return; isl_int_init(wraps->max); isl_int_set_si(wraps->max, 0); - wraps_update_max(wraps, map->p[i], eq_i, ineq_i); - wraps_update_max(wraps, map->p[j], eq_j, ineq_j); + wraps_update_max(wraps, &info[i]); + wraps_update_max(wraps, &info[j]); } /* Free the contents of the isl_wraps data structure. @@ -637,9 +855,40 @@ static int allow_wrap(struct isl_wraps *wraps, int row) return 1; } -/* For each non-redundant constraint in "bmap" (as determined by "tab"), +/* Wrap "ineq" (or its opposite if "negate" is set) around "bound" + * to include "set" and add the result in position "w" of "wraps". + * "len" is the total number of coefficients in "bound" and "ineq". + * Return 1 on success, 0 on failure and -1 on error. + * Wrapping can fail if the result of wrapping is equal to "bound" + * or if we want to bound the sizes of the coefficients and + * the wrapped constraint does not satisfy this bound. + */ +static int add_wrap(struct isl_wraps *wraps, int w, isl_int *bound, + isl_int *ineq, unsigned len, __isl_keep isl_set *set, int negate) +{ + isl_seq_cpy(wraps->mat->row[w], bound, len); + if (negate) { + isl_seq_neg(wraps->mat->row[w + 1], ineq, len); + ineq = wraps->mat->row[w + 1]; + } + if (!isl_set_wrap_facet(set, wraps->mat->row[w], ineq)) + return -1; + if (isl_seq_eq(wraps->mat->row[w], bound, len)) + return 0; + if (!allow_wrap(wraps, w)) + return 0; + return 1; +} + +/* For each constraint in info->bmap that is not redundant (as determined + * by info->tab) and that is not a valid constraint for the other basic map, * wrap the constraint around "bound" such that it includes the whole * set "set" and append the resulting constraint to "wraps". + * Note that the constraints that are valid for the other basic map + * will be added to the combined basic map by default, so there is + * no need to wrap them. + * The caller wrap_in_facets even relies on this function not wrapping + * any constraints that are already valid. * "wraps" is assumed to have been pre-allocated to the appropriate size. * wraps->n_row is the number of actual wrapped constraints that have * been added. @@ -651,57 +900,52 @@ static int allow_wrap(struct isl_wraps *wraps, int row) * constraints and a newly added wrapping constraint does not * satisfy the bound, then wraps->n_row is also reset to zero. */ -static int add_wraps(struct isl_wraps *wraps, __isl_keep isl_basic_map *bmap, - struct isl_tab *tab, isl_int *bound, __isl_keep isl_set *set) +static int add_wraps(struct isl_wraps *wraps, struct isl_coalesce_info *info, + isl_int *bound, __isl_keep isl_set *set) { - int l; + int l, m; int w; - unsigned total = isl_basic_map_total_dim(bmap); + int added; + isl_basic_map *bmap = info->bmap; + unsigned len = 1 + isl_basic_map_total_dim(bmap); w = wraps->mat->n_row; for (l = 0; l < bmap->n_ineq; ++l) { - if (isl_seq_is_neg(bound, bmap->ineq[l], 1 + total)) + if (info->ineq[l] == STATUS_VALID || + info->ineq[l] == STATUS_REDUNDANT) + continue; + if (isl_seq_is_neg(bound, bmap->ineq[l], len)) continue; - if (isl_seq_eq(bound, bmap->ineq[l], 1 + total)) + if (isl_seq_eq(bound, bmap->ineq[l], len)) continue; - if (isl_tab_is_redundant(tab, bmap->n_eq + l)) + if (isl_tab_is_redundant(info->tab, bmap->n_eq + l)) continue; - isl_seq_cpy(wraps->mat->row[w], bound, 1 + total); - if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->ineq[l])) + added = add_wrap(wraps, w, bound, bmap->ineq[l], len, set, 0); + if (added < 0) return -1; - if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total)) - goto unbounded; - if (!allow_wrap(wraps, w)) + if (!added) goto unbounded; ++w; } for (l = 0; l < bmap->n_eq; ++l) { - if (isl_seq_is_neg(bound, bmap->eq[l], 1 + total)) + if (isl_seq_is_neg(bound, bmap->eq[l], len)) continue; - if (isl_seq_eq(bound, bmap->eq[l], 1 + total)) + if (isl_seq_eq(bound, bmap->eq[l], len)) continue; - isl_seq_cpy(wraps->mat->row[w], bound, 1 + total); - isl_seq_neg(wraps->mat->row[w + 1], bmap->eq[l], 1 + total); - if (!isl_set_wrap_facet(set, wraps->mat->row[w], - wraps->mat->row[w + 1])) - return -1; - if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total)) - goto unbounded; - if (!allow_wrap(wraps, w)) - goto unbounded; - ++w; - - isl_seq_cpy(wraps->mat->row[w], bound, 1 + total); - if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->eq[l])) - return -1; - if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total)) - goto unbounded; - if (!allow_wrap(wraps, w)) - goto unbounded; - ++w; + for (m = 0; m < 2; ++m) { + if (info->eq[2 * l + m] == STATUS_VALID) + continue; + added = add_wrap(wraps, w, bound, bmap->eq[l], len, + set, !m); + if (added < 0) + return -1; + if (!added) + goto unbounded; + ++w; + } } wraps->mat->n_row = w; @@ -734,7 +978,7 @@ static int check_wraps(__isl_keep isl_mat *wraps, int first, return 0; } -/* Return a set that corresponds to the non-redudant constraints +/* Return a set that corresponds to the non-redundant constraints * (as recorded in tab) of bmap. * * It's important to remove the redundant constraints as some @@ -745,34 +989,73 @@ static int check_wraps(__isl_keep isl_mat *wraps, int first, * and should therefore continue to be ignored ever after. * Otherwise, the relaxation might be thwarted by some of * these constraints. + * + * Update the underlying set to ensure that the dimension doesn't change. + * Otherwise the integer divisions could get dropped if the tab + * turns out to be empty. */ static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap, struct isl_tab *tab) { + isl_basic_set *bset; + bmap = isl_basic_map_copy(bmap); - bmap = isl_basic_map_cow(bmap); - bmap = isl_basic_map_update_from_tab(bmap, tab); - return isl_set_from_basic_set(isl_basic_map_underlying_set(bmap)); + bset = isl_basic_map_underlying_set(bmap); + bset = isl_basic_set_cow(bset); + bset = isl_basic_set_update_from_tab(bset, tab); + return isl_set_from_basic_set(bset); } -/* Given a basic set i with a constraint k that is adjacent to either the - * whole of basic set j or a facet of basic set j, check if we can wrap - * both the facet corresponding to k and the facet of j (or the whole of j) - * around their ridges to include the other set. +/* Wrap the constraints of info->bmap that bound the facet defined + * by inequality "k" around (the opposite of) this inequality to + * include "set". "bound" may be used to store the negated inequality. + * Since the wrapped constraints are not guaranteed to contain the whole + * of info->bmap, we check them in check_wraps. + * If any of the wrapped constraints turn out to be invalid, then + * check_wraps will reset wrap->n_row to zero. + */ +static int add_wraps_around_facet(struct isl_wraps *wraps, + struct isl_coalesce_info *info, int k, isl_int *bound, + __isl_keep isl_set *set) +{ + struct isl_tab_undo *snap; + int n; + unsigned total = isl_basic_map_total_dim(info->bmap); + + snap = isl_tab_snap(info->tab); + + if (isl_tab_select_facet(info->tab, info->bmap->n_eq + k) < 0) + return -1; + if (isl_tab_detect_redundant(info->tab) < 0) + return -1; + + isl_seq_neg(bound, info->bmap->ineq[k], 1 + total); + + n = wraps->mat->n_row; + if (add_wraps(wraps, info, bound, set) < 0) + return -1; + + if (isl_tab_rollback(info->tab, snap) < 0) + return -1; + if (check_wraps(wraps->mat, n, info->tab) < 0) + return -1; + + return 0; +} + +/* Given a basic set i with a constraint k that is adjacent to + * basic set j, check if we can wrap + * both the facet corresponding to k (if "wrap_facet" is set) and basic map j + * (always) around their ridges to include the other set. * If so, replace the pair of basic sets by their union. * - * All constraints of i (except k) are assumed to be valid for j. - * - * However, the constraints of j may not be valid for i and so - * we have to check that the wrapping constraints for j are valid for i. - * - * In the case where j has a facet adjacent to i, tab[j] is assumed - * to have been restricted to this facet, so that the non-redundant - * constraints in tab[j] are the ridges of the facet. - * Note that for the purpose of wrapping, it does not matter whether - * we wrap the ridges of i around the whole of j or just around - * the facet since all the other constraints are assumed to be valid for j. - * In practice, we wrap to include the whole of j. + * All constraints of i (except k) are assumed to be valid or + * cut constraints for j. + * Wrapping the cut constraints to include basic map j may result + * in constraints that are no longer valid of basic map i + * we have to check that the resulting wrapping constraints are valid for i. + * If "wrap_facet" is not set, then all constraints of i (except k) + * are assumed to be valid for j. * ____ _____ * / | / \ * / || / | @@ -781,61 +1064,49 @@ static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap, * \___|| \____| * */ -static int can_wrap_in_facet(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) +static enum isl_change can_wrap_in_facet(int i, int j, int k, + struct isl_coalesce_info *info, int wrap_facet) { - int changed = 0; + enum isl_change change = isl_change_none; struct isl_wraps wraps; + isl_ctx *ctx; isl_mat *mat; struct isl_set *set_i = NULL; struct isl_set *set_j = NULL; struct isl_vec *bound = NULL; - unsigned total = isl_basic_map_total_dim(map->p[i]); - struct isl_tab_undo *snap; - int n; - - set_i = set_from_updated_bmap(map->p[i], tabs[i]); - set_j = set_from_updated_bmap(map->p[j], tabs[j]); - mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) + - map->p[i]->n_ineq + map->p[j]->n_ineq, - 1 + total); - wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j); - bound = isl_vec_alloc(map->ctx, 1 + total); + unsigned total = isl_basic_map_total_dim(info[i].bmap); + + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + set_j = set_from_updated_bmap(info[j].bmap, info[j].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) + + info[i].bmap->n_ineq + info[j].bmap->n_ineq, + 1 + total); + wraps_init(&wraps, mat, info, i, j); + bound = isl_vec_alloc(ctx, 1 + total); if (!set_i || !set_j || !wraps.mat || !bound) goto error; - isl_seq_cpy(bound->el, map->p[i]->ineq[k], 1 + total); + isl_seq_cpy(bound->el, info[i].bmap->ineq[k], 1 + total); isl_int_add_ui(bound->el[0], bound->el[0], 1); isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total); wraps.mat->n_row = 1; - if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0) + if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0) goto error; if (!wraps.mat->n_row) goto unbounded; - snap = isl_tab_snap(tabs[i]); - - if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + k) < 0) - goto error; - if (isl_tab_detect_redundant(tabs[i]) < 0) - goto error; - - isl_seq_neg(bound->el, map->p[i]->ineq[k], 1 + total); - - n = wraps.mat->n_row; - if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0) - goto error; - - if (isl_tab_rollback(tabs[i], snap) < 0) - goto error; - if (check_wraps(wraps.mat, n, tabs[i]) < 0) - goto error; - if (!wraps.mat->n_row) - goto unbounded; + if (wrap_facet) { + if (add_wraps_around_facet(&wraps, &info[i], k, + bound->el, set_j) < 0) + goto error; + if (!wraps.mat->n_row) + goto unbounded; + } - changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat); + change = fuse(i, j, info, wraps.mat, 0, 0); unbounded: wraps_free(&wraps); @@ -845,38 +1116,13 @@ unbounded: isl_vec_free(bound); - return changed; + return change; error: wraps_free(&wraps); isl_vec_free(bound); isl_set_free(set_i); isl_set_free(set_j); - return -1; -} - -/* Set the is_redundant property of the "n" constraints in "cuts", - * except "k" to "v". - * This is a fairly tricky operation as it bypasses isl_tab.c. - * The reason we want to temporarily mark some constraints redundant - * is that we want to ignore them in add_wraps. - * - * Initially all cut constraints are non-redundant, but the - * selection of a facet right before the call to this function - * may have made some of them redundant. - * Likewise, the same constraints are marked non-redundant - * in the second call to this function, before they are officially - * made non-redundant again in the subsequent rollback. - */ -static void set_is_redundant(struct isl_tab *tab, unsigned n_eq, - int *cuts, int n, int k, int v) -{ - int l; - - for (l = 0; l < n; ++l) { - if (l == k) - continue; - tab->con[n_eq + cuts[l]].is_redundant = v; - } + return isl_change_error; } /* Given a pair of basic maps i and j such that j sticks out @@ -885,91 +1131,75 @@ static void set_is_redundant(struct isl_tab *tab, unsigned n_eq, * basic maps by a single basic map. * The other constraints of i are assumed to be valid for j. * - * The facets of i corresponding to the cut constraints are - * wrapped around their ridges, except those ridges determined - * by any of the other cut constraints. - * The intersections of cut constraints need to be ignored - * as the result of wrapping one cut constraint around another - * would result in a constraint cutting the union. - * In each case, the facets are wrapped to include the union - * of the two basic maps. - * - * The pieces of j that lie at an offset of exactly one from - * one of the cut constraints of i are wrapped around their edges. - * Here, there is no need to ignore intersections because we - * are wrapping around the union of the two basic maps. + * For each cut constraint t(x) >= 0 of i, we add the relaxed version + * t(x) + 1 >= 0, along with wrapping constraints for all constraints + * of basic map j that bound the part of basic map j that sticks out + * of the cut constraint. + * In particular, we first intersect basic map j with t(x) + 1 = 0. + * If the result is empty, then t(x) >= 0 was actually a valid constraint + * (with respect to the integer points), so we add t(x) >= 0 instead. + * Otherwise, we wrap the constraints of basic map j that are not + * redundant in this intersection and that are not already valid + * for basic map i over basic map i. + * Note that it is sufficient to wrap the constraints to include + * basic map i, because we will only wrap the constraints that do + * not include basic map i already. The wrapped constraint will + * therefore be more relaxed compared to the original constraint. + * Since the original constraint is valid for basic map j, so is + * the wrapped constraint. * * If any wrapping fails, i.e., if we cannot wrap to touch * the union, then we give up. * Otherwise, the pair of basic maps is replaced by their union. */ -static int wrap_in_facets(struct isl_map *map, int i, int j, - int *cuts, int n, struct isl_tab **tabs, - int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change wrap_in_facets(int i, int j, int *cuts, int n, + struct isl_coalesce_info *info) { - int changed = 0; + enum isl_change change = isl_change_none; struct isl_wraps wraps; + isl_ctx *ctx; isl_mat *mat; - isl_set *set = NULL; - isl_vec *bound = NULL; - unsigned total = isl_basic_map_total_dim(map->p[i]); + isl_set *set_i = NULL; + unsigned total = isl_basic_map_total_dim(info[i].bmap); int max_wrap; - int k; - struct isl_tab_undo *snap_i, *snap_j; + int k, w; + struct isl_tab_undo *snap; - if (isl_tab_extend_cons(tabs[j], 1) < 0) + if (isl_tab_extend_cons(info[j].tab, 1) < 0) goto error; - max_wrap = 2 * (map->p[i]->n_eq + map->p[j]->n_eq) + - map->p[i]->n_ineq + map->p[j]->n_ineq; + max_wrap = 1 + 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq; max_wrap *= n; - set = isl_set_union(set_from_updated_bmap(map->p[i], tabs[i]), - set_from_updated_bmap(map->p[j], tabs[j])); - mat = isl_mat_alloc(map->ctx, max_wrap, 1 + total); - wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j); - bound = isl_vec_alloc(map->ctx, 1 + total); - if (!set || !wraps.mat || !bound) + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, max_wrap, 1 + total); + wraps_init(&wraps, mat, info, i, j); + if (!set_i || !wraps.mat) goto error; - snap_i = isl_tab_snap(tabs[i]); - snap_j = isl_tab_snap(tabs[j]); + snap = isl_tab_snap(info[j].tab); wraps.mat->n_row = 0; for (k = 0; k < n; ++k) { - if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + cuts[k]) < 0) - goto error; - if (isl_tab_detect_redundant(tabs[i]) < 0) + w = wraps.mat->n_row++; + isl_seq_cpy(wraps.mat->row[w], + info[i].bmap->ineq[cuts[k]], 1 + total); + isl_int_add_ui(wraps.mat->row[w][0], wraps.mat->row[w][0], 1); + if (isl_tab_add_eq(info[j].tab, wraps.mat->row[w]) < 0) goto error; - set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 1); - - isl_seq_neg(bound->el, map->p[i]->ineq[cuts[k]], 1 + total); - if (!tabs[i]->empty && - add_wraps(&wraps, map->p[i], tabs[i], bound->el, set) < 0) + if (isl_tab_detect_redundant(info[j].tab) < 0) goto error; - set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 0); - if (isl_tab_rollback(tabs[i], snap_i) < 0) + if (info[j].tab->empty) + isl_int_sub_ui(wraps.mat->row[w][0], + wraps.mat->row[w][0], 1); + else if (add_wraps(&wraps, &info[j], + wraps.mat->row[w], set_i) < 0) goto error; - if (tabs[i]->empty) - break; - if (!wraps.mat->n_row) - break; - - isl_seq_cpy(bound->el, map->p[i]->ineq[cuts[k]], 1 + total); - isl_int_add_ui(bound->el[0], bound->el[0], 1); - if (isl_tab_add_eq(tabs[j], bound->el) < 0) - goto error; - if (isl_tab_detect_redundant(tabs[j]) < 0) - goto error; - - if (!tabs[j]->empty && - add_wraps(&wraps, map->p[j], tabs[j], bound->el, set) < 0) - goto error; - - if (isl_tab_rollback(tabs[j], snap_j) < 0) + if (isl_tab_rollback(info[j].tab, snap) < 0) goto error; if (!wraps.mat->n_row) @@ -977,19 +1207,16 @@ static int wrap_in_facets(struct isl_map *map, int i, int j, } if (k == n) - changed = fuse(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j, wraps.mat); + change = fuse(i, j, info, wraps.mat, 0, 1); - isl_vec_free(bound); wraps_free(&wraps); - isl_set_free(set); + isl_set_free(set_i); - return changed; + return change; error: - isl_vec_free(bound); wraps_free(&wraps); - isl_set_free(set); - return -1; + isl_set_free(set_i); + return isl_change_error; } /* Given two basic sets i and j such that i has no cut equalities, @@ -1051,35 +1278,39 @@ error: * | * \______________________________________________________________________ */ -static int can_wrap_in_set(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change can_wrap_in_set(int i, int j, + struct isl_coalesce_info *info) { - int changed = 0; + enum isl_change change = isl_change_none; int k, m; int n; int *cuts = NULL; + isl_ctx *ctx; - if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) || - ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL)) - return 0; + if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) || + ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL)) + return isl_change_none; - n = count(ineq_i, map->p[i]->n_ineq, STATUS_CUT); + n = count(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT); if (n == 0) - return 0; + return isl_change_none; - cuts = isl_alloc_array(map->ctx, int, n); + ctx = isl_basic_map_get_ctx(info[i].bmap); + cuts = isl_alloc_array(ctx, int, n); if (!cuts) - return -1; + return isl_change_error; for (k = 0, m = 0; m < n; ++k) { enum isl_ineq_type type; - if (ineq_i[k] != STATUS_CUT) + if (info[i].ineq[k] != STATUS_CUT) continue; - isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1); - type = isl_tab_ineq_type(tabs[j], map->p[i]->ineq[k]); - isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1); + isl_int_add_ui(info[i].bmap->ineq[k][0], + info[i].bmap->ineq[k][0], 1); + type = isl_tab_ineq_type(info[j].tab, info[i].bmap->ineq[k]); + isl_int_sub_ui(info[i].bmap->ineq[k][0], + info[i].bmap->ineq[k][0], 1); if (type == isl_ineq_error) goto error; if (type != isl_ineq_redundant) @@ -1089,36 +1320,32 @@ static int can_wrap_in_set(struct isl_map *map, int i, int j, } if (m == n) - changed = wrap_in_facets(map, i, j, cuts, n, tabs, - eq_i, ineq_i, eq_j, ineq_j); + change = wrap_in_facets(i, j, cuts, n, info); free(cuts); - return changed; + return change; error: free(cuts); - return -1; + return isl_change_error; } -/* Check if either i or j has a single cut constraint that can +/* Check if either i or j has only cut inequalities that can * be used to wrap in (a facet of) the other basic set. * if so, replace the pair by their union. */ -static int check_wrap(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change check_wrap(int i, int j, struct isl_coalesce_info *info) { - int changed = 0; - - if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT)) - changed = can_wrap_in_set(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); - if (changed) - return changed; - - if (!any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT)) - changed = can_wrap_in_set(map, j, i, tabs, - eq_j, ineq_j, eq_i, ineq_i); - return changed; + enum isl_change change = isl_change_none; + + if (!any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT)) + change = can_wrap_in_set(i, j, info); + if (change != isl_change_none) + return change; + + if (!any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT)) + change = can_wrap_in_set(j, i, info); + return change; } /* At least one of the basic maps has an equality that is adjacent @@ -1129,52 +1356,49 @@ static int check_wrap(struct isl_map *map, int i, int j, * map that has the equality "j". * If "i" has any "cut" (in)equality, then relaxing the inequality * by one would not result in a basic map that contains the other + * basic map. However, it may still be possible to wrap in the other * basic map. */ -static int check_adj_eq(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change check_adj_eq(int i, int j, + struct isl_coalesce_info *info) { - int changed = 0; + enum isl_change change = isl_change_none; int k; + int any_cut; - if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) && - any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ)) + if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ) && + any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_INEQ)) /* ADJ EQ TOO MANY */ - return 0; + return isl_change_none; - if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ)) - return check_adj_eq(map, j, i, tabs, - eq_j, ineq_j, eq_i, ineq_i); + if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ)) + return check_adj_eq(j, i, info); /* j has an equality adjacent to an inequality in i */ - if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT)) - return 0; - if (any(ineq_i, map->p[i]->n_ineq, STATUS_CUT)) - /* ADJ EQ CUT */ - return 0; - if (count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) != 1 || - any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ) || - any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) || - any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ)) + if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT)) + return isl_change_none; + any_cut = any(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT); + if (count(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ) != 1 || + any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_EQ) || + any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ) || + any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ)) /* ADJ EQ TOO MANY */ - return 0; + return isl_change_none; - for (k = 0; k < map->p[i]->n_ineq; ++k) - if (ineq_i[k] == STATUS_ADJ_EQ) + for (k = 0; k < info[i].bmap->n_ineq; ++k) + if (info[i].ineq[k] == STATUS_ADJ_EQ) break; - changed = is_adj_eq_extension(map, i, j, k, tabs, - eq_i, ineq_i, eq_j, ineq_j); - if (changed) - return changed; - - if (count(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ) != 1) - return 0; + if (!any_cut) { + change = is_adj_eq_extension(i, j, k, info); + if (change != isl_change_none) + return change; + } - changed = can_wrap_in_facet(map, i, j, k, tabs, eq_i, ineq_i, eq_j, ineq_j); + change = can_wrap_in_facet(i, j, k, info, any_cut); - return changed; + return change; } /* The two basic maps lie on adjacent hyperplanes. In particular, @@ -1189,60 +1413,54 @@ static int check_adj_eq(struct isl_map *map, int i, int j, * \\ => \\ * \ \| * - * We only allow one equality of "i" to be adjacent to an equality of "j" - * to avoid coalescing - * - * [m, n] -> { [x, y] -> [x, 1 + y] : x >= 1 and y >= 1 and - * x <= 10 and y <= 10; - * [x, y] -> [1 + x, y] : x >= 1 and x <= 20 and - * y >= 5 and y <= 15 } - * - * to - * - * [m, n] -> { [x, y] -> [x2, y2] : x >= 1 and 10y2 <= 20 - x + 10y and - * 4y2 >= 5 + 3y and 5y2 <= 15 + 4y and - * y2 <= 1 + x + y - x2 and y2 >= y and - * y2 >= 1 + x + y - x2 } + * If there is more than one equality of "i" adjacent to an equality of "j", + * then the result will satisfy one or more equalities that are a linear + * combination of these equalities. These will be encoded as pairs + * of inequalities in the wrapping constraints and need to be made + * explicit. */ -static int check_eq_adj_eq(struct isl_map *map, int i, int j, - struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j) +static enum isl_change check_eq_adj_eq(int i, int j, + struct isl_coalesce_info *info) { int k; - int changed = 0; + enum isl_change change = isl_change_none; + int detect_equalities = 0; struct isl_wraps wraps; + isl_ctx *ctx; isl_mat *mat; struct isl_set *set_i = NULL; struct isl_set *set_j = NULL; struct isl_vec *bound = NULL; - unsigned total = isl_basic_map_total_dim(map->p[i]); + unsigned total = isl_basic_map_total_dim(info[i].bmap); - if (count(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ) != 1) - return 0; + if (count(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_EQ) != 1) + detect_equalities = 1; - for (k = 0; k < 2 * map->p[i]->n_eq ; ++k) - if (eq_i[k] == STATUS_ADJ_EQ) + for (k = 0; k < 2 * info[i].bmap->n_eq ; ++k) + if (info[i].eq[k] == STATUS_ADJ_EQ) break; - set_i = set_from_updated_bmap(map->p[i], tabs[i]); - set_j = set_from_updated_bmap(map->p[j], tabs[j]); - mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) + - map->p[i]->n_ineq + map->p[j]->n_ineq, - 1 + total); - wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j); - bound = isl_vec_alloc(map->ctx, 1 + total); + set_i = set_from_updated_bmap(info[i].bmap, info[i].tab); + set_j = set_from_updated_bmap(info[j].bmap, info[j].tab); + ctx = isl_basic_map_get_ctx(info[i].bmap); + mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) + + info[i].bmap->n_ineq + info[j].bmap->n_ineq, + 1 + total); + wraps_init(&wraps, mat, info, i, j); + bound = isl_vec_alloc(ctx, 1 + total); if (!set_i || !set_j || !wraps.mat || !bound) goto error; if (k % 2 == 0) - isl_seq_neg(bound->el, map->p[i]->eq[k / 2], 1 + total); + isl_seq_neg(bound->el, info[i].bmap->eq[k / 2], 1 + total); else - isl_seq_cpy(bound->el, map->p[i]->eq[k / 2], 1 + total); + isl_seq_cpy(bound->el, info[i].bmap->eq[k / 2], 1 + total); isl_int_add_ui(bound->el[0], bound->el[0], 1); isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total); wraps.mat->n_row = 1; - if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0) + if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0) goto error; if (!wraps.mat->n_row) goto unbounded; @@ -1253,15 +1471,15 @@ static int check_eq_adj_eq(struct isl_map *map, int i, int j, isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total); wraps.mat->n_row++; - if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0) + if (add_wraps(&wraps, &info[i], bound->el, set_j) < 0) goto error; if (!wraps.mat->n_row) goto unbounded; - changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat); + change = fuse(i, j, info, wraps.mat, detect_equalities, 0); if (0) { -error: changed = -1; +error: change = isl_change_error; } unbounded: @@ -1270,13 +1488,14 @@ unbounded: isl_set_free(set_j); isl_vec_free(bound); - return changed; + return change; } /* Check if the union of the given pair of basic maps * can be represented by a single basic map. - * If so, replace the pair by the single basic map and return 1. - * Otherwise, return 0; + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. * The two basic maps are assumed to live in the same local space. * * We first check the effect of each constraint of one basic map @@ -1355,94 +1574,184 @@ unbounded: * corresponding to the basic maps. When the basic maps are dropped * or combined, the tableaus are modified accordingly. */ -static int coalesce_local_pair(__isl_keep isl_map *map, int i, int j, - struct isl_tab **tabs) +static enum isl_change coalesce_local_pair(int i, int j, + struct isl_coalesce_info *info) { - int changed = 0; - int *eq_i = NULL; - int *eq_j = NULL; - int *ineq_i = NULL; - int *ineq_j = NULL; + enum isl_change change = isl_change_none; - eq_i = eq_status_in(map->p[i], tabs[j]); - if (map->p[i]->n_eq && !eq_i) + info[i].eq = info[i].ineq = NULL; + info[j].eq = info[j].ineq = NULL; + + info[i].eq = eq_status_in(info[i].bmap, info[j].tab); + if (info[i].bmap->n_eq && !info[i].eq) goto error; - if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ERROR)) + if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ERROR)) goto error; - if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_SEPARATE)) + if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_SEPARATE)) goto done; - eq_j = eq_status_in(map->p[j], tabs[i]); - if (map->p[j]->n_eq && !eq_j) + info[j].eq = eq_status_in(info[j].bmap, info[i].tab); + if (info[j].bmap->n_eq && !info[j].eq) goto error; - if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ERROR)) + if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ERROR)) goto error; - if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_SEPARATE)) + if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_SEPARATE)) goto done; - ineq_i = ineq_status_in(map->p[i], tabs[i], tabs[j]); - if (map->p[i]->n_ineq && !ineq_i) + info[i].ineq = ineq_status_in(info[i].bmap, info[i].tab, info[j].tab); + if (info[i].bmap->n_ineq && !info[i].ineq) goto error; - if (any(ineq_i, map->p[i]->n_ineq, STATUS_ERROR)) + if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ERROR)) goto error; - if (any(ineq_i, map->p[i]->n_ineq, STATUS_SEPARATE)) + if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_SEPARATE)) goto done; - ineq_j = ineq_status_in(map->p[j], tabs[j], tabs[i]); - if (map->p[j]->n_ineq && !ineq_j) + info[j].ineq = ineq_status_in(info[j].bmap, info[j].tab, info[i].tab); + if (info[j].bmap->n_ineq && !info[j].ineq) goto error; - if (any(ineq_j, map->p[j]->n_ineq, STATUS_ERROR)) + if (any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ERROR)) goto error; - if (any(ineq_j, map->p[j]->n_ineq, STATUS_SEPARATE)) + if (any(info[j].ineq, info[j].bmap->n_ineq, STATUS_SEPARATE)) goto done; - if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) && - all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) { - drop(map, j, tabs); - changed = 1; - } else if (all(eq_j, 2 * map->p[j]->n_eq, STATUS_VALID) && - all(ineq_j, map->p[j]->n_ineq, STATUS_VALID)) { - drop(map, i, tabs); - changed = 1; - } else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ)) { - changed = check_eq_adj_eq(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); - } else if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_EQ)) { - changed = check_eq_adj_eq(map, j, i, tabs, - eq_j, ineq_j, eq_i, ineq_i); - } else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) || - any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ)) { - changed = check_adj_eq(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); - } else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) || - any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ)) { + if (all(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_VALID) && + all(info[i].ineq, info[i].bmap->n_ineq, STATUS_VALID)) { + drop(&info[j]); + change = isl_change_drop_second; + } else if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) && + all(info[j].ineq, info[j].bmap->n_ineq, STATUS_VALID)) { + drop(&info[i]); + change = isl_change_drop_first; + } else if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_EQ)) { + change = check_eq_adj_eq(i, j, info); + } else if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_EQ)) { + change = check_eq_adj_eq(j, i, info); + } else if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ) || + any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_INEQ)) { + change = check_adj_eq(i, j, info); + } else if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ) || + any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_EQ)) { /* Can't happen */ /* 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)) { - changed = check_adj_ineq(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); + } else if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ) || + any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ)) { + change = check_adj_ineq(i, j, info); } else { - 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_facets(map, i, j, tabs, ineq_i, ineq_j); - if (!changed) - changed = check_wrap(map, i, j, tabs, - eq_i, ineq_i, eq_j, ineq_j); + if (!any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT) && + !any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT)) + change = check_facets(i, j, info); + if (change == isl_change_none) + change = check_wrap(i, j, info); } done: - free(eq_i); - free(eq_j); - free(ineq_i); - free(ineq_j); - return changed; + free(info[i].eq); + free(info[j].eq); + free(info[i].ineq); + free(info[j].ineq); + return change; error: - free(eq_i); - free(eq_j); - free(ineq_i); - free(ineq_j); - return -1; + free(info[i].eq); + free(info[j].eq); + free(info[i].ineq); + free(info[j].ineq); + return isl_change_error; +} + +/* Shift the integer division at position "div" of the basic map + * represented by "info" by "shift". + * + * That is, if the integer division has the form + * + * floor(f(x)/d) + * + * then replace it by + * + * floor((f(x) + shift * d)/d) - shift + */ +static int shift_div(struct isl_coalesce_info *info, int div, isl_int shift) +{ + unsigned total; + + info->bmap = isl_basic_map_shift_div(info->bmap, div, shift); + if (!info->bmap) + return -1; + + total = isl_basic_map_dim(info->bmap, isl_dim_all); + total -= isl_basic_map_dim(info->bmap, isl_dim_div); + if (isl_tab_shift_var(info->tab, total + div, shift) < 0) + return -1; + + return 0; +} + +/* Check if some of the divs in the basic map represented by "info1" + * are shifts of the corresponding divs in the basic map represented + * by "info2". If so, align them with those of "info2". + * Only do this if "info1" and "info2" have the same number + * of integer divisions. + * + * An integer division is considered to be a shift of another integer + * division if one is equal to the other plus a constant. + * + * In particular, for each pair of integer divisions, if both are known, + * have identical coefficients (apart from the constant term) and + * if the difference between the constant terms (taking into account + * the denominator) is an integer, then move the difference outside. + * That is, if one integer division is of the form + * + * floor((f(x) + c_1)/d) + * + * while the other is of the form + * + * floor((f(x) + c_2)/d) + * + * and n = (c_2 - c_1)/d is an integer, then replace the first + * integer division by + * + * floor((f(x) + c_1 + n * d)/d) - n = floor((f(x) + c_2)/d) - n + */ +static int harmonize_divs(struct isl_coalesce_info *info1, + struct isl_coalesce_info *info2) +{ + int i; + int total; + + if (!info1->bmap || !info2->bmap) + return -1; + + if (info1->bmap->n_div != info2->bmap->n_div) + return 0; + if (info1->bmap->n_div == 0) + return 0; + + total = isl_basic_map_total_dim(info1->bmap); + for (i = 0; i < info1->bmap->n_div; ++i) { + isl_int d; + int r = 0; + + if (isl_int_is_zero(info1->bmap->div[i][0]) || + isl_int_is_zero(info2->bmap->div[i][0])) + continue; + if (isl_int_ne(info1->bmap->div[i][0], info2->bmap->div[i][0])) + continue; + if (isl_int_eq(info1->bmap->div[i][1], info2->bmap->div[i][1])) + continue; + if (!isl_seq_eq(info1->bmap->div[i] + 2, + info2->bmap->div[i] + 2, total)) + continue; + isl_int_init(d); + isl_int_sub(d, info2->bmap->div[i][1], info1->bmap->div[i][1]); + if (isl_int_is_divisible_by(d, info1->bmap->div[i][0])) { + isl_int_divexact(d, d, info1->bmap->div[i][0]); + r = shift_div(info1, i, d); + } + isl_int_clear(d); + if (r < 0) + return -1; + } + + return 0; } /* Do the two basic maps live in the same local space, i.e., @@ -1480,29 +1789,26 @@ static int same_divs(__isl_keep isl_basic_map *bmap1, return 1; } -/* Given two basic maps "i" and "j", where the divs of "i" form a subset - * of those of "j", check if basic map "j" is a subset of basic map "i" - * and, if so, drop basic map "j". - * - * We first expand the divs of basic map "i" to match those of basic map "j", - * using the divs and expansion computed by the caller. - * Then we check if all constraints of the expanded "i" are valid for "j". +/* Does "bmap" contain the basic map represented by the tableau "tab" + * after expanding the divs of "bmap" to match those of "tab"? + * The expansion is performed using the divs "div" and expansion "exp" + * computed by the caller. + * Then we check if all constraints of the expanded "bmap" are valid for "tab". */ -static int coalesce_subset(__isl_keep isl_map *map, int i, int j, - struct isl_tab **tabs, __isl_keep isl_mat *div, int *exp) +static int contains_with_expanded_divs(__isl_keep isl_basic_map *bmap, + struct isl_tab *tab, __isl_keep isl_mat *div, int *exp) { - isl_basic_map *bmap; - int changed = 0; + int superset = 0; int *eq_i = NULL; int *ineq_i = NULL; - bmap = isl_basic_map_copy(map->p[i]); + bmap = isl_basic_map_copy(bmap); bmap = isl_basic_set_expand_divs(bmap, isl_mat_copy(div), exp); if (!bmap) goto error; - eq_i = eq_status_in(bmap, tabs[j]); + eq_i = eq_status_in(bmap, tab); if (bmap->n_eq && !eq_i) goto error; if (any(eq_i, 2 * bmap->n_eq, STATUS_ERROR)) @@ -1510,7 +1816,7 @@ static int coalesce_subset(__isl_keep isl_map *map, int i, int j, if (any(eq_i, 2 * bmap->n_eq, STATUS_SEPARATE)) goto done; - ineq_i = ineq_status_in(bmap, NULL, tabs[j]); + ineq_i = ineq_status_in(bmap, NULL, tab); if (bmap->n_ineq && !ineq_i) goto error; if (any(ineq_i, bmap->n_ineq, STATUS_ERROR)) @@ -1518,17 +1824,15 @@ static int coalesce_subset(__isl_keep isl_map *map, int i, int j, if (any(ineq_i, bmap->n_ineq, STATUS_SEPARATE)) goto done; - if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) && - all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) { - drop(map, j, tabs); - changed = 1; - } + if (all(eq_i, 2 * bmap->n_eq, STATUS_VALID) && + all(ineq_i, bmap->n_ineq, STATUS_VALID)) + superset = 1; done: isl_basic_map_free(bmap); free(eq_i); free(ineq_i); - return 0; + return superset; error: isl_basic_map_free(bmap); free(eq_i); @@ -1536,20 +1840,17 @@ error: return -1; } -/* Check if the basic map "j" is a subset of basic map "i", - * assuming that "i" has fewer divs that "j". - * If not, then we change the order. +/* Does "bmap_i" contain the basic map represented by "info_j" + * after aligning the divs of "bmap_i" to those of "info_j". + * Note that this can only succeed if the number of divs of "bmap_i" + * is smaller than (or equal to) the number of divs of "info_j". * - * If the two basic maps have the same number of divs, then - * they must necessarily be different. Otherwise, we would have - * called coalesce_local_pair. We therefore don't try anything - * in this case. - * - * We first check if the divs of "i" are all known and form a subset - * of those of "j". If so, we pass control over to coalesce_subset. + * We first check if the divs of "bmap_i" are all known and form a subset + * of those of "bmap_j". If so, we pass control over to + * contains_with_expanded_divs. */ -static int check_coalesce_subset(__isl_keep isl_map *map, int i, int j, - struct isl_tab **tabs) +static int contains_after_aligning_divs(__isl_keep isl_basic_map *bmap_i, + struct isl_coalesce_info *info_j) { int known; isl_mat *div_i, *div_j, *div; @@ -1558,19 +1859,14 @@ static int check_coalesce_subset(__isl_keep isl_map *map, int i, int j, isl_ctx *ctx; int subset; - if (map->p[i]->n_div == map->p[j]->n_div) - return 0; - if (map->p[j]->n_div < map->p[i]->n_div) - return check_coalesce_subset(map, j, i, tabs); - - known = isl_basic_map_divs_known(map->p[i]); + known = isl_basic_map_divs_known(bmap_i); if (known < 0 || !known) return known; - ctx = isl_map_get_ctx(map); + ctx = isl_basic_map_get_ctx(bmap_i); - div_i = isl_basic_map_get_divs(map->p[i]); - div_j = isl_basic_map_get_divs(map->p[j]); + div_i = isl_basic_map_get_divs(bmap_i); + div_j = isl_basic_map_get_divs(info_j->bmap); if (!div_i || !div_j) goto error; @@ -1585,7 +1881,8 @@ static int check_coalesce_subset(__isl_keep isl_map *map, int i, int j, goto error; if (div->n_row == div_j->n_row) - subset = coalesce_subset(map, i, j, tabs, div, exp1); + subset = contains_with_expanded_divs(bmap_i, + info_j->tab, div, exp1); else subset = 0; @@ -1606,53 +1903,682 @@ error: return -1; } +/* Check if the basic map "j" is a subset of basic map "i", + * if "i" has fewer divs that "j". + * If so, remove basic map "j". + * + * If the two basic maps have the same number of divs, then + * they must necessarily be different. Otherwise, we would have + * called coalesce_local_pair. We therefore don't try anything + * in this case. + */ +static int coalesced_subset(int i, int j, struct isl_coalesce_info *info) +{ + int superset; + + if (info[i].bmap->n_div >= info[j].bmap->n_div) + return 0; + + superset = contains_after_aligning_divs(info[i].bmap, &info[j]); + if (superset < 0) + return -1; + if (superset) + drop(&info[j]); + + return superset; +} + +/* Check if basic map "j" is a subset of basic map "i" after + * exploiting the extra equalities of "j" to simplify the divs of "i". + * If so, remove basic map "j". + * + * If "j" does not have any equalities or if they are the same + * as those of "i", then we cannot exploit them to simplify the divs. + * Similarly, if there are no divs in "i", then they cannot be simplified. + * If, on the other hand, the affine hulls of "i" and "j" do not intersect, + * then "j" cannot be a subset of "i". + * + * Otherwise, we intersect "i" with the affine hull of "j" and then + * check if "j" is a subset of the result after aligning the divs. + * If so, then "j" is definitely a subset of "i" and can be removed. + * Note that if after intersection with the affine hull of "j". + * "i" still has more divs than "j", then there is no way we can + * align the divs of "i" to those of "j". + */ +static int coalesced_subset_with_equalities(int i, int j, + struct isl_coalesce_info *info) +{ + isl_basic_map *hull_i, *hull_j, *bmap_i; + int equal, empty, subset; + + if (info[j].bmap->n_eq == 0) + return 0; + if (info[i].bmap->n_div == 0) + return 0; + + hull_i = isl_basic_map_copy(info[i].bmap); + hull_i = isl_basic_map_plain_affine_hull(hull_i); + hull_j = isl_basic_map_copy(info[j].bmap); + hull_j = isl_basic_map_plain_affine_hull(hull_j); + + hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i)); + equal = isl_basic_map_plain_is_equal(hull_i, hull_j); + empty = isl_basic_map_plain_is_empty(hull_j); + isl_basic_map_free(hull_i); + + if (equal < 0 || equal || empty < 0 || empty) { + isl_basic_map_free(hull_j); + return equal < 0 || empty < 0 ? -1 : 0; + } + + bmap_i = isl_basic_map_copy(info[i].bmap); + bmap_i = isl_basic_map_intersect(bmap_i, hull_j); + if (!bmap_i) + return -1; + + if (bmap_i->n_div > info[j].bmap->n_div) { + isl_basic_map_free(bmap_i); + return 0; + } + + subset = contains_after_aligning_divs(bmap_i, &info[j]); + + isl_basic_map_free(bmap_i); + + if (subset < 0) + return -1; + if (subset) + drop(&info[j]); + + return subset; +} + +/* Check if one of the basic maps is a subset of the other and, if so, + * drop the subset. + * Note that we only perform any test if the number of divs is different + * in the two basic maps. In case the number of divs is the same, + * we have already established that the divs are different + * in the two basic maps. + * In particular, if the number of divs of basic map i is smaller than + * the number of divs of basic map j, then we check if j is a subset of i + * and vice versa. + */ +static enum isl_change check_coalesce_subset(int i, int j, + struct isl_coalesce_info *info) +{ + int changed; + + changed = coalesced_subset(i, j, info); + if (changed < 0 || changed) + return changed < 0 ? isl_change_error : isl_change_drop_second; + + changed = coalesced_subset(j, i, info); + if (changed < 0 || changed) + return changed < 0 ? isl_change_error : isl_change_drop_first; + + changed = coalesced_subset_with_equalities(i, j, info); + if (changed < 0 || changed) + return changed < 0 ? isl_change_error : isl_change_drop_second; + + changed = coalesced_subset_with_equalities(j, i, info); + if (changed < 0 || changed) + return changed < 0 ? isl_change_error : isl_change_drop_first; + + return isl_change_none; +} + +/* Does "bmap" involve any divs that themselves refer to divs? + */ +static int has_nested_div(__isl_keep isl_basic_map *bmap) +{ + int i; + unsigned total; + unsigned n_div; + + total = isl_basic_map_dim(bmap, isl_dim_all); + n_div = isl_basic_map_dim(bmap, isl_dim_div); + total -= n_div; + + for (i = 0; i < n_div; ++i) + if (isl_seq_first_non_zero(bmap->div[i] + 2 + total, + n_div) != -1) + return 1; + + return 0; +} + +/* Return a list of affine expressions, one for each integer division + * in "bmap_i". For each integer division that also appears in "bmap_j", + * the affine expression is set to NaN. The number of NaNs in the list + * is equal to the number of integer divisions in "bmap_j". + * For the other integer divisions of "bmap_i", the corresponding + * element in the list is a purely affine expression equal to the integer + * division in "hull". + * If no such list can be constructed, then the number of elements + * in the returned list is smaller than the number of integer divisions + * in "bmap_i". + */ +static __isl_give isl_aff_list *set_up_substitutions( + __isl_keep isl_basic_map *bmap_i, __isl_keep isl_basic_map *bmap_j, + __isl_take isl_basic_map *hull) +{ + unsigned n_div_i, n_div_j, total; + isl_ctx *ctx; + isl_local_space *ls; + isl_basic_set *wrap_hull; + isl_aff *aff_nan; + isl_aff_list *list; + int i, j; + + if (!hull) + return NULL; + + ctx = isl_basic_map_get_ctx(hull); + + n_div_i = isl_basic_map_dim(bmap_i, isl_dim_div); + n_div_j = isl_basic_map_dim(bmap_j, isl_dim_div); + total = isl_basic_map_total_dim(bmap_i) - n_div_i; + + ls = isl_basic_map_get_local_space(bmap_i); + ls = isl_local_space_wrap(ls); + wrap_hull = isl_basic_map_wrap(hull); + + aff_nan = isl_aff_nan_on_domain(isl_local_space_copy(ls)); + list = isl_aff_list_alloc(ctx, n_div_i); + + j = 0; + for (i = 0; i < n_div_i; ++i) { + isl_aff *aff; + + if (j < n_div_j && + isl_seq_eq(bmap_i->div[i], bmap_j->div[j], 2 + total)) { + ++j; + list = isl_aff_list_add(list, isl_aff_copy(aff_nan)); + continue; + } + if (n_div_i - i <= n_div_j - j) + break; + + aff = isl_local_space_get_div(ls, i); + aff = isl_aff_substitute_equalities(aff, + isl_basic_set_copy(wrap_hull)); + aff = isl_aff_floor(aff); + if (!aff) + goto error; + if (isl_aff_dim(aff, isl_dim_div) != 0) { + isl_aff_free(aff); + break; + } + + list = isl_aff_list_add(list, aff); + } + + isl_aff_free(aff_nan); + isl_local_space_free(ls); + isl_basic_set_free(wrap_hull); + + return list; +error: + isl_local_space_free(ls); + isl_basic_set_free(wrap_hull); + isl_aff_list_free(list); + return NULL; +} + +/* Add variables to "tab" corresponding to the elements in "list" + * that are not set to NaN. + * "dim" is the offset in the variables of "tab" where we should + * start considering the elements in "list". + * When this function returns, the total number of variables in "tab" + * is equal to "dim" plus the number of elements in "list". + */ +static int add_sub_vars(struct isl_tab *tab, __isl_keep isl_aff_list *list, + int dim) +{ + int i, n; + + n = isl_aff_list_n_aff(list); + for (i = 0; i < n; ++i) { + int is_nan; + isl_aff *aff; + + aff = isl_aff_list_get_aff(list, i); + is_nan = isl_aff_is_nan(aff); + isl_aff_free(aff); + if (is_nan < 0) + return -1; + + if (!is_nan && isl_tab_insert_var(tab, dim + i) < 0) + return -1; + } + + return 0; +} + +/* For each element in "list" that is not set to NaN, fix the corresponding + * variable in "tab" to the purely affine expression defined by the element. + * "dim" is the offset in the variables of "tab" where we should + * start considering the elements in "list". + */ +static int add_sub_equalities(struct isl_tab *tab, + __isl_keep isl_aff_list *list, int dim) +{ + int i, n; + isl_ctx *ctx; + isl_vec *sub; + isl_aff *aff; + + n = isl_aff_list_n_aff(list); + + ctx = isl_tab_get_ctx(tab); + sub = isl_vec_alloc(ctx, 1 + dim + n); + if (!sub) + return -1; + isl_seq_clr(sub->el + 1 + dim, n); + + for (i = 0; i < n; ++i) { + aff = isl_aff_list_get_aff(list, i); + if (!aff) + goto error; + if (isl_aff_is_nan(aff)) { + isl_aff_free(aff); + continue; + } + isl_seq_cpy(sub->el, aff->v->el + 1, 1 + dim); + isl_int_neg(sub->el[1 + dim + i], aff->v->el[0]); + if (isl_tab_add_eq(tab, sub->el) < 0) + goto error; + isl_int_set_si(sub->el[1 + dim + i], 0); + isl_aff_free(aff); + } + + isl_vec_free(sub); + return 0; +error: + isl_aff_free(aff); + isl_vec_free(sub); + return -1; +} + +/* Add variables to info->tab corresponding to the elements in "list" + * that are not set to NaN. The value of the added variable + * is fixed to the purely affine expression defined by the element. + * "dim" is the offset in the variables of info->tab where we should + * start considering the elements in "list". + * When this function returns, the total number of variables in info->tab + * is equal to "dim" plus the number of elements in "list". + * Additionally, add the div constraints that have been added info->bmap + * after the tableau was constructed to info->tab. These constraints + * start at position "n_ineq" in info->bmap. + * The constraints need to be added to the tableau before + * the equalities assigning the purely affine expression + * because the position needs to match that in info->bmap. + * They are frozen because the corresponding added equality is a consequence + * of the two div constraints and the other equalities, meaning that + * the div constraints would otherwise get marked as redundant, + * while they are only redundant with respect to the extra equalities + * added to the tableau, which do not appear explicitly in the basic map. + */ +static int add_subs(struct isl_coalesce_info *info, + __isl_keep isl_aff_list *list, int dim, int n_ineq) +{ + int i, extra_var, extra_con; + int n; + unsigned n_eq = info->bmap->n_eq; + + if (!list) + return -1; + + n = isl_aff_list_n_aff(list); + extra_var = n - (info->tab->n_var - dim); + extra_con = info->bmap->n_ineq - n_ineq; + + if (isl_tab_extend_vars(info->tab, extra_var) < 0) + return -1; + if (isl_tab_extend_cons(info->tab, extra_con + 2 * extra_var) < 0) + return -1; + if (add_sub_vars(info->tab, list, dim) < 0) + return -1; + + for (i = n_ineq; i < info->bmap->n_ineq; ++i) { + if (isl_tab_add_ineq(info->tab, info->bmap->ineq[i]) < 0) + return -1; + if (isl_tab_freeze_constraint(info->tab, n_eq + i) < 0) + return -1; + } + + return add_sub_equalities(info->tab, list, dim); +} + +/* Coalesce basic map "j" into basic map "i" after adding the extra integer + * divisions in "i" but not in "j" to basic map "j", with values + * specified by "list". The total number of elements in "list" + * is equal to the number of integer divisions in "i", while the number + * of NaN elements in the list is equal to the number of integer divisions + * in "j". + * Adding extra integer divisions to "j" through isl_basic_map_align_divs + * also adds the corresponding div constraints. These need to be added + * to the corresponding tableau as well in add_subs to maintain consistency. + * + * If no coalescing can be performed, then we need to revert basic map "j" + * to its original state. We do the same if basic map "i" gets dropped + * during the coalescing, even though this should not happen in practice + * since we have already checked for "j" being a subset of "i" + * before we reach this stage. + */ +static enum isl_change coalesce_with_subs(int i, int j, + struct isl_coalesce_info *info, __isl_keep isl_aff_list *list) +{ + isl_basic_map *bmap_j; + struct isl_tab_undo *snap; + unsigned dim; + enum isl_change change; + int n_ineq; + + bmap_j = isl_basic_map_copy(info[j].bmap); + n_ineq = info[j].bmap->n_ineq; + info[j].bmap = isl_basic_map_align_divs(info[j].bmap, info[i].bmap); + if (!info[j].bmap) + goto error; + + snap = isl_tab_snap(info[j].tab); + + dim = isl_basic_map_dim(bmap_j, isl_dim_all); + dim -= isl_basic_map_dim(bmap_j, isl_dim_div); + if (add_subs(&info[j], list, dim, n_ineq) < 0) + goto error; + + change = coalesce_local_pair(i, j, info); + if (change != isl_change_none && change != isl_change_drop_first) { + isl_basic_map_free(bmap_j); + } else { + isl_basic_map_free(info[j].bmap); + info[j].bmap = bmap_j; + + if (isl_tab_rollback(info[j].tab, snap) < 0) + return isl_change_error; + } + + return change; +error: + isl_basic_map_free(bmap_j); + return isl_change_error; +} + +/* Check if we can coalesce basic map "j" into basic map "i" after copying + * those extra integer divisions in "i" that can be simplified away + * using the extra equalities in "j". + * All divs are assumed to be known and not contain any nested divs. + * + * We first check if there are any extra equalities in "j" that we + * can exploit. Then we check if every integer division in "i" + * either already appears in "j" or can be simplified using the + * extra equalities to a purely affine expression. + * If these tests succeed, then we try to coalesce the two basic maps + * by introducing extra dimensions in "j" corresponding to + * the extra integer divsisions "i" fixed to the corresponding + * purely affine expression. + */ +static enum isl_change check_coalesce_into_eq(int i, int j, + struct isl_coalesce_info *info) +{ + unsigned n_div_i, n_div_j; + isl_basic_map *hull_i, *hull_j; + int equal, empty; + isl_aff_list *list; + enum isl_change change; + + n_div_i = isl_basic_map_dim(info[i].bmap, isl_dim_div); + n_div_j = isl_basic_map_dim(info[j].bmap, isl_dim_div); + if (n_div_i <= n_div_j) + return isl_change_none; + if (info[j].bmap->n_eq == 0) + return isl_change_none; + + hull_i = isl_basic_map_copy(info[i].bmap); + hull_i = isl_basic_map_plain_affine_hull(hull_i); + hull_j = isl_basic_map_copy(info[j].bmap); + hull_j = isl_basic_map_plain_affine_hull(hull_j); + + hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i)); + equal = isl_basic_map_plain_is_equal(hull_i, hull_j); + empty = isl_basic_map_plain_is_empty(hull_j); + isl_basic_map_free(hull_i); + + if (equal < 0 || empty < 0) + goto error; + if (equal || empty) { + isl_basic_map_free(hull_j); + return isl_change_none; + } + + list = set_up_substitutions(info[i].bmap, info[j].bmap, hull_j); + if (!list) + goto error; + if (isl_aff_list_n_aff(list) < n_div_i) + change = isl_change_none; + else + change = coalesce_with_subs(i, j, info, list); + + isl_aff_list_free(list); + + return change; +error: + isl_basic_map_free(hull_j); + return isl_change_error; +} + +/* Check if we can coalesce basic maps "i" and "j" after copying + * those extra integer divisions in one of the basic maps that can + * be simplified away using the extra equalities in the other basic map. + * We require all divs to be known in both basic maps. + * Furthermore, to simplify the comparison of div expressions, + * we do not allow any nested integer divisions. + */ +static enum isl_change check_coalesce_eq(int i, int j, + struct isl_coalesce_info *info) +{ + int known, nested; + enum isl_change change; + + known = isl_basic_map_divs_known(info[i].bmap); + if (known < 0 || !known) + return known < 0 ? isl_change_error : isl_change_none; + known = isl_basic_map_divs_known(info[j].bmap); + if (known < 0 || !known) + return known < 0 ? isl_change_error : isl_change_none; + nested = has_nested_div(info[i].bmap); + if (nested < 0 || nested) + return nested < 0 ? isl_change_error : isl_change_none; + nested = has_nested_div(info[j].bmap); + if (nested < 0 || nested) + return nested < 0 ? isl_change_error : isl_change_none; + + change = check_coalesce_into_eq(i, j, info); + if (change != isl_change_none) + return change; + change = check_coalesce_into_eq(j, i, info); + if (change != isl_change_none) + return invert_change(change); + + return isl_change_none; +} + /* Check if the union of the given pair of basic maps * can be represented by a single basic map. - * If so, replace the pair by the single basic map and return 1. - * Otherwise, return 0; + * If so, replace the pair by the single basic map and return + * isl_change_drop_first, isl_change_drop_second or isl_change_fuse. + * Otherwise, return isl_change_none. * - * We first check if the two basic maps live in the same local space. - * If so, we do the complete check. Otherwise, we check if one is - * an obvious subset of the other. + * We first check if the two basic maps live in the same local space, + * after aligning the divs that differ by only an integer constant. + * If so, we do the complete check. Otherwise, we check if they have + * the same number of integer divisions and can be coalesced, if one is + * an obvious subset of the other or if the extra integer divisions + * of one basic map can be simplified away using the extra equalities + * of the other basic map. */ -static int coalesce_pair(__isl_keep isl_map *map, int i, int j, - struct isl_tab **tabs) +static enum isl_change coalesce_pair(int i, int j, + struct isl_coalesce_info *info) { int same; + enum isl_change change; - same = same_divs(map->p[i], map->p[j]); + if (harmonize_divs(&info[i], &info[j]) < 0) + return isl_change_error; + same = same_divs(info[i].bmap, info[j].bmap); if (same < 0) - return -1; + return isl_change_error; if (same) - return coalesce_local_pair(map, i, j, tabs); + return coalesce_local_pair(i, j, info); + + if (info[i].bmap->n_div == info[j].bmap->n_div) { + change = coalesce_local_pair(i, j, info); + if (change != isl_change_none) + return change; + } + + change = check_coalesce_subset(i, j, info); + if (change != isl_change_none) + return change; - return check_coalesce_subset(map, i, j, tabs); + return check_coalesce_eq(i, j, info); } -static struct isl_map *coalesce(struct isl_map *map, struct isl_tab **tabs) +/* Return the maximum of "a" and "b". + */ +static inline int max(int a, int b) +{ + return a > b ? a : b; +} + +/* Pairwise coalesce the basic maps in the range [start1, end1[ of "info" + * with those in the range [start2, end2[, skipping basic maps + * that have been removed (either before or within this function). + * + * For each basic map i in the first range, we check if it can be coalesced + * with respect to any previously considered basic map j in the second range. + * If i gets dropped (because it was a subset of some j), then + * we can move on to the next basic map. + * If j gets dropped, we need to continue checking against the other + * previously considered basic maps. + * If the two basic maps got fused, then we recheck the fused basic map + * against the previously considered basic maps, starting at i + 1 + * (even if start2 is greater than i + 1). + */ +static int coalesce_range(isl_ctx *ctx, struct isl_coalesce_info *info, + int start1, int end1, int start2, int end2) { int i, j; - for (i = map->n - 2; i >= 0; --i) -restart: - for (j = i + 1; j < map->n; ++j) { - int changed; - changed = coalesce_pair(map, i, j, tabs); - if (changed < 0) - goto error; - if (changed) - goto restart; + for (i = end1 - 1; i >= start1; --i) { + if (info[i].removed) + continue; + for (j = max(i + 1, start2); j < end2; ++j) { + enum isl_change changed; + + if (info[j].removed) + continue; + if (info[i].removed) + isl_die(ctx, isl_error_internal, + "basic map unexpectedly removed", + return -1); + changed = coalesce_pair(i, j, info); + switch (changed) { + case isl_change_error: + return -1; + case isl_change_none: + case isl_change_drop_second: + continue; + case isl_change_drop_first: + j = end2; + break; + case isl_change_fuse: + j = i; + break; + } + } + } + + return 0; +} + +/* Pairwise coalesce the basic maps described by the "n" elements of "info". + * + * We consider groups of basic maps that live in the same apparent + * affine hull and we first coalesce within such a group before we + * coalesce the elements in the group with elements of previously + * considered groups. If a fuse happens during the second phase, + * then we also reconsider the elements within the group. + */ +static int coalesce(isl_ctx *ctx, int n, struct isl_coalesce_info *info) +{ + int start, end; + + for (end = n; end > 0; end = start) { + start = end - 1; + while (start >= 1 && + info[start - 1].hull_hash == info[start].hull_hash) + start--; + if (coalesce_range(ctx, info, start, end, start, end) < 0) + return -1; + if (coalesce_range(ctx, info, start, end, end, n) < 0) + return -1; + } + + return 0; +} + +/* Update the basic maps in "map" based on the information in "info". + * In particular, remove the basic maps that have been marked removed and + * update the others based on the information in the corresponding tableau. + * Since we detected implicit equalities without calling + * isl_basic_map_gauss, we need to do it now. + * Also call isl_basic_map_simplify if we may have lost the definition + * of one or more integer divisions. + */ +static __isl_give isl_map *update_basic_maps(__isl_take isl_map *map, + int n, struct isl_coalesce_info *info) +{ + int i; + + if (!map) + return NULL; + + for (i = n - 1; i >= 0; --i) { + if (info[i].removed) { + isl_basic_map_free(map->p[i]); + if (i != map->n - 1) + map->p[i] = map->p[map->n - 1]; + map->n--; + continue; } + + info[i].bmap = isl_basic_map_update_from_tab(info[i].bmap, + info[i].tab); + info[i].bmap = isl_basic_map_gauss(info[i].bmap, NULL); + if (info[i].simplify) + info[i].bmap = isl_basic_map_simplify(info[i].bmap); + info[i].bmap = isl_basic_map_finalize(info[i].bmap); + if (!info[i].bmap) + return isl_map_free(map); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT); + ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT); + isl_basic_map_free(map->p[i]); + map->p[i] = info[i].bmap; + info[i].bmap = NULL; + } + return map; -error: - isl_map_free(map); - return NULL; } /* For each pair of basic maps in the map, check if the union of the two * can be represented by a single basic map. * If so, replace the pair by the single basic map and start over. * + * We factor out any (hidden) common factor from the constraint + * coefficients to improve the detection of adjacent constraints. + * * Since we are constructing the tableaus of the basic maps anyway, * we exploit them to detect implicit equalities and redundant constraints. * This also helps the coalescing as it can ignore the redundant constraints. @@ -1660,14 +2586,17 @@ error: * in the basic maps. We don't call isl_basic_map_gauss, though, * as that may affect the number of constraints. * This means that we have to call isl_basic_map_gauss at the end - * of the computation to ensure that the basic maps are not left - * in an unexpected state. + * of the computation (in update_basic_maps) to ensure that + * the basic maps are not left in an unexpected state. + * For each basic map, we also compute the hash of the apparent affine hull + * for use in coalesce. */ struct isl_map *isl_map_coalesce(struct isl_map *map) { int i; unsigned n; - struct isl_tab **tabs = NULL; + isl_ctx *ctx; + struct isl_coalesce_info *info = NULL; map = isl_map_remove_empty_parts(map); if (!map) @@ -1676,61 +2605,54 @@ struct isl_map *isl_map_coalesce(struct isl_map *map) if (map->n <= 1) return map; + ctx = isl_map_get_ctx(map); map = isl_map_sort_divs(map); map = isl_map_cow(map); if (!map) return NULL; - tabs = isl_calloc_array(map->ctx, struct isl_tab *, map->n); - if (!tabs) + n = map->n; + + info = isl_calloc_array(map->ctx, struct isl_coalesce_info, n); + if (!info) goto error; - n = map->n; for (i = 0; i < map->n; ++i) { - tabs[i] = isl_tab_from_basic_map(map->p[i], 0); - if (!tabs[i]) + map->p[i] = isl_basic_map_reduce_coefficients(map->p[i]); + if (!map->p[i]) + goto error; + info[i].bmap = isl_basic_map_copy(map->p[i]); + info[i].tab = isl_tab_from_basic_map(info[i].bmap, 0); + if (!info[i].tab) goto error; - if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT)) - if (isl_tab_detect_implicit_equalities(tabs[i]) < 0) + if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT)) + if (isl_tab_detect_implicit_equalities(info[i].tab) < 0) goto error; - map->p[i] = isl_tab_make_equalities_explicit(tabs[i], - map->p[i]); - if (!map->p[i]) + info[i].bmap = isl_tab_make_equalities_explicit(info[i].tab, + info[i].bmap); + if (!info[i].bmap) goto error; - if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT)) - if (isl_tab_detect_redundant(tabs[i]) < 0) + if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT)) + if (isl_tab_detect_redundant(info[i].tab) < 0) goto error; + if (coalesce_info_set_hull_hash(&info[i]) < 0) + goto error; } for (i = map->n - 1; i >= 0; --i) - if (tabs[i]->empty) - drop(map, i, tabs); - - map = coalesce(map, tabs); - - if (map) - for (i = 0; i < map->n; ++i) { - map->p[i] = isl_basic_map_update_from_tab(map->p[i], - tabs[i]); - map->p[i] = isl_basic_map_gauss(map->p[i], NULL); - map->p[i] = isl_basic_map_finalize(map->p[i]); - if (!map->p[i]) - goto error; - ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT); - ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT); - } + if (info[i].tab->empty) + drop(&info[i]); + + if (coalesce(ctx, n, info) < 0) + goto error; - for (i = 0; i < n; ++i) - isl_tab_free(tabs[i]); + map = update_basic_maps(map, n, info); - free(tabs); + clear_coalesce_info(n, info); return map; error: - if (tabs) - for (i = 0; i < n; ++i) - isl_tab_free(tabs[i]); - free(tabs); + clear_coalesce_info(n, info); isl_map_free(map); return NULL; } diff --git a/polly/lib/External/isl/isl_convex_hull.c b/polly/lib/External/isl/isl_convex_hull.c index b1254be1783..419c22e8b1f 100644 --- a/polly/lib/External/isl/isl_convex_hull.c +++ b/polly/lib/External/isl/isl_convex_hull.c @@ -595,8 +595,9 @@ static struct isl_basic_set *compute_facet(struct isl_set *set, isl_int *c) set = isl_set_preimage(set, U); facet = uset_convex_hull_wrap_bounded(set); facet = isl_basic_set_preimage(facet, Q); - if (facet) - isl_assert(ctx, facet->n_eq == 0, goto error); + if (facet && facet->n_eq != 0) + isl_die(ctx, isl_error_internal, "unexpected equality", + return isl_basic_set_free(facet)); return facet; error: isl_basic_set_free(facet); @@ -2638,114 +2639,125 @@ error: return NULL; } -/* Compute a superset of the convex hull of "set" that is described +/* Compute a superset of the convex hull of "map" that is described * by only constraints in the elements of "list". * * If the list is empty, then we can only describe the universe set. - * If the input set is empty, then all constraints are valid, so + * If the input map is empty, then all constraints are valid, so * we return the intersection of the elements in "list". * * Otherwise, we align all divs and temporarily treat them * as regular variables, computing the unshifted simple hull in * uset_unshifted_simple_hull_from_basic_set_list. */ -static __isl_give isl_basic_set *set_unshifted_simple_hull_from_basic_set_list( - __isl_take isl_set *set, __isl_take isl_basic_set_list *list) +static __isl_give isl_basic_map *map_unshifted_simple_hull_from_basic_map_list( + __isl_take isl_map *map, __isl_take isl_basic_map_list *list) { - isl_basic_set *model; - isl_basic_set *hull; + isl_basic_map *model; + isl_basic_map *hull; + isl_set *set; + isl_basic_set_list *bset_list; - if (!set || !list) + if (!map || !list) goto error; - if (isl_basic_set_list_n_basic_set(list) == 0) { + if (isl_basic_map_list_n_basic_map(list) == 0) { isl_space *space; - space = isl_set_get_space(set); - isl_set_free(set); - isl_basic_set_list_free(list); - return isl_basic_set_universe(space); + space = isl_map_get_space(map); + isl_map_free(map); + isl_basic_map_list_free(list); + return isl_basic_map_universe(space); } - if (isl_set_plain_is_empty(set)) { - isl_set_free(set); - return isl_basic_set_list_intersect(list); + if (isl_map_plain_is_empty(map)) { + isl_map_free(map); + return isl_basic_map_list_intersect(list); } - set = isl_set_align_divs_to_basic_set_list(set, list); - if (!set) + map = isl_map_align_divs_to_basic_map_list(map, list); + if (!map) goto error; - list = isl_basic_set_list_align_divs_to_basic_set(list, set->p[0]); + list = isl_basic_map_list_align_divs_to_basic_map(list, map->p[0]); - model = isl_basic_set_list_get_basic_set(list, 0); + model = isl_basic_map_list_get_basic_map(list, 0); - set = isl_set_to_underlying_set(set); - list = isl_basic_set_list_underlying_set(list); + set = isl_map_underlying_set(map); + bset_list = isl_basic_map_list_underlying_set(list); - hull = uset_unshifted_simple_hull_from_basic_set_list(set, list); + hull = uset_unshifted_simple_hull_from_basic_set_list(set, bset_list); hull = isl_basic_map_overlying_set(hull, model); return hull; error: - isl_set_free(set); - isl_basic_set_list_free(list); + isl_map_free(map); + isl_basic_map_list_free(list); return NULL; } -/* Return a sequence of the basic sets that make up the sets in "list". +/* Return a sequence of the basic maps that make up the maps in "list". */ -static __isl_give isl_basic_set_list *collect_basic_sets( - __isl_take isl_set_list *list) +static __isl_give isl_basic_set_list *collect_basic_maps( + __isl_take isl_map_list *list) { int i, n; isl_ctx *ctx; - isl_basic_set_list *bset_list; + isl_basic_map_list *bmap_list; if (!list) return NULL; - n = isl_set_list_n_set(list); - ctx = isl_set_list_get_ctx(list); - bset_list = isl_basic_set_list_alloc(ctx, 0); + n = isl_map_list_n_map(list); + ctx = isl_map_list_get_ctx(list); + bmap_list = isl_basic_map_list_alloc(ctx, 0); for (i = 0; i < n; ++i) { - isl_set *set; - isl_basic_set_list *list_i; + isl_map *map; + isl_basic_map_list *list_i; - set = isl_set_list_get_set(list, i); - set = isl_set_compute_divs(set); - list_i = isl_set_get_basic_set_list(set); - isl_set_free(set); - bset_list = isl_basic_set_list_concat(bset_list, list_i); + map = isl_map_list_get_map(list, i); + map = isl_map_compute_divs(map); + list_i = isl_map_get_basic_map_list(map); + isl_map_free(map); + bmap_list = isl_basic_map_list_concat(bmap_list, list_i); } - isl_set_list_free(list); - return bset_list; + isl_map_list_free(list); + return bmap_list; } -/* Compute a superset of the convex hull of "set" that is described +/* Compute a superset of the convex hull of "map" that is described * by only constraints in the elements of "list". * - * If "set" is the universe, then the convex hull (and therefore + * If "map" is the universe, then the convex hull (and therefore * any superset of the convexhull) is the universe as well. * - * Otherwise, we collect all the basic sets in the set list and - * continue with set_unshifted_simple_hull_from_basic_set_list. + * Otherwise, we collect all the basic maps in the map list and + * continue with map_unshifted_simple_hull_from_basic_map_list. */ -__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list( - __isl_take isl_set *set, __isl_take isl_set_list *list) +__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list( + __isl_take isl_map *map, __isl_take isl_map_list *list) { - isl_basic_set_list *bset_list; + isl_basic_map_list *bmap_list; int is_universe; - is_universe = isl_set_plain_is_universe(set); + is_universe = isl_map_plain_is_universe(map); if (is_universe < 0) - set = isl_set_free(set); + map = isl_map_free(map); if (is_universe < 0 || is_universe) { - isl_set_list_free(list); - return isl_set_unshifted_simple_hull(set); + isl_map_list_free(list); + return isl_map_unshifted_simple_hull(map); } - bset_list = collect_basic_sets(list); - return set_unshifted_simple_hull_from_basic_set_list(set, bset_list); + bmap_list = collect_basic_maps(list); + return map_unshifted_simple_hull_from_basic_map_list(map, bmap_list); +} + +/* Compute a superset of the convex hull of "set" that is described + * by only constraints in the elements of "list". + */ +__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list( + __isl_take isl_set *set, __isl_take isl_set_list *list) +{ + return isl_map_unshifted_simple_hull_from_map_list(set, list); } /* Given a set "set", return parametric bounds on the dimension "dim". diff --git a/polly/lib/External/isl/isl_fold.c b/polly/lib/External/isl/isl_fold.c index dee86c31f47..104475ddef6 100644 --- a/polly/lib/External/isl/isl_fold.c +++ b/polly/lib/External/isl/isl_fold.c @@ -641,6 +641,7 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( #define DEFAULT_IS_ZERO 1 #define NO_NEG +#define NO_SUB #define NO_PULLBACK #include <isl_pw_templ.c> @@ -651,7 +652,6 @@ __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params( #define PART isl_pw_qpolynomial_fold #undef PARTS #define PARTS pw_qpolynomial_fold -#define ALIGN_DOMAIN #define NO_SUB @@ -901,7 +901,8 @@ __isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_ hash = isl_space_get_hash(part->dim); entry = isl_hash_table_find(u->space->ctx, &u->table, hash, - &has_same_domain_space, part->dim, 1); + &isl_union_pw_qpolynomial_fold_has_same_domain_space, + part->dim, 1); if (!entry) goto error; @@ -1366,7 +1367,8 @@ static int add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user) ctx = pwqp->dim->ctx; hash = isl_space_get_hash(pwqp->dim); entry = isl_hash_table_find(ctx, &(*upwf)->table, hash, - &has_same_domain_space, pwqp->dim, 1); + &isl_union_pw_qpolynomial_fold_has_same_domain_space, + pwqp->dim, 1); if (!entry) goto error; diff --git a/polly/lib/External/isl/isl_input.c b/polly/lib/External/isl/isl_input.c index 520e7f45c19..b6073deaeda 100644 --- a/polly/lib/External/isl/isl_input.c +++ b/polly/lib/External/isl/isl_input.c @@ -145,7 +145,7 @@ static int vars_add_anon(struct vars *v) * In particular, evaluate expressions of the form x^y, * with x and y values. */ -static struct isl_token *next_token(struct isl_stream *s) +static struct isl_token *next_token(__isl_keep isl_stream *s) { struct isl_token *tok, *tok2; @@ -182,7 +182,7 @@ error: * * where n, d and v are integer constants. */ -__isl_give isl_val *isl_stream_read_val(struct isl_stream *s) +__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s) { struct isl_token *tok = NULL; struct isl_token *tok2 = NULL; @@ -242,7 +242,7 @@ struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx, const char *str) { isl_val *val; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; val = isl_stream_read_val(s); @@ -250,7 +250,7 @@ struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx, return val; } -static int accept_cst_factor(struct isl_stream *s, isl_int *f) +static int accept_cst_factor(__isl_keep isl_stream *s, isl_int *f) { struct isl_token *tok; @@ -280,7 +280,7 @@ error: * We introduce an integer division q = [aff/d] and the result * is set to aff - d q. */ -static __isl_give isl_pw_aff *affine_mod(struct isl_stream *s, +static __isl_give isl_pw_aff *affine_mod(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_pw_aff *aff) { struct isl_token *tok; @@ -307,12 +307,12 @@ error: return NULL; } -static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, __isl_take isl_space *space, struct vars *v); -static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s, +static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v); -static __isl_give isl_pw_aff *accept_minmax(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v) { struct isl_token *tok; @@ -372,7 +372,7 @@ static int is_start_of_div(struct isl_token *tok) * floord(<affine expression>,<denominator>) * ceild(<affine expression>,<denominator>) */ -static __isl_give isl_pw_aff *accept_div(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v) { struct isl_token *tok; @@ -436,7 +436,7 @@ error: return NULL; } -static __isl_give isl_pw_aff *accept_affine_factor(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v) { struct isl_token *tok = NULL; @@ -564,7 +564,7 @@ static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space) return isl_pw_aff_nan_on_domain(ls); } -static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, __isl_take isl_space *space, struct vars *v) { struct isl_token *tok = NULL; @@ -675,14 +675,14 @@ static int is_comparator(struct isl_token *tok) } } -static __isl_give isl_map *read_formula(struct isl_stream *s, +static __isl_give isl_map *read_formula(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational); -static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v, int rational); /* Accept a ternary operator, given the first argument. */ -static __isl_give isl_pw_aff *accept_ternary(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_ternary(__isl_keep isl_stream *s, __isl_take isl_map *cond, struct vars *v, int rational) { isl_space *dim; @@ -718,7 +718,7 @@ error: /* Set *line and *col to those of the next token, if any. */ -static void set_current_line_col(struct isl_stream *s, int *line, int *col) +static void set_current_line_col(__isl_keep isl_stream *s, int *line, int *col) { struct isl_token *tok; @@ -734,7 +734,7 @@ static void set_current_line_col(struct isl_stream *s, int *line, int *col) /* Push a token encapsulating "pa" onto "s", with the given * line and column. */ -static int push_aff(struct isl_stream *s, int line, int col, +static int push_aff(__isl_keep isl_stream *s, int line, int col, __isl_take isl_pw_aff *pa) { struct isl_token *tok; @@ -758,7 +758,7 @@ error: * Otherwise, we assume the affine expression is part of the first * argument of a ternary operator and try to parse that. */ -static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v, int rational) { isl_space *space; @@ -798,7 +798,7 @@ static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s, return accept_ternary(s, cond, v, rational); } -static __isl_give isl_map *read_var_def(struct isl_stream *s, +static __isl_give isl_map *read_var_def(__isl_keep isl_stream *s, __isl_take isl_map *map, enum isl_dim_type type, struct vars *v, int rational) { @@ -827,7 +827,7 @@ static __isl_give isl_map *read_var_def(struct isl_stream *s, return map; } -static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s, +static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s, __isl_take isl_space *dim, struct vars *v) { isl_pw_aff *pwaff; @@ -866,7 +866,7 @@ error: return NULL; } -static __isl_give isl_map *read_defined_var_list(struct isl_stream *s, +static __isl_give isl_map *read_defined_var_list(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { struct isl_token *tok; @@ -911,7 +911,7 @@ error: return NULL; } -static int next_is_tuple(struct isl_stream *s) +static int next_is_tuple(__isl_keep isl_stream *s) { struct isl_token *tok; int is_tuple; @@ -935,21 +935,6 @@ static int next_is_tuple(struct isl_stream *s) return is_tuple; } -/* Allocate an initial tuple with zero dimensions and an anonymous, - * unstructured space. - * A tuple is represented as an isl_multi_pw_aff. - * The range space is the space of the tuple. - * The domain space is an anonymous space - * with a dimension for each variable in the set of variables in "v". - * If a given dimension is not defined in terms of earlier dimensions in - * the input, then the corresponding isl_pw_aff is set equal to one time - * the variable corresponding to the dimension being defined. - */ -static __isl_give isl_multi_pw_aff *tuple_alloc(struct vars *v) -{ - return isl_multi_pw_aff_alloc(isl_space_alloc(v->ctx, 0, v->n, 0)); -} - /* Is "pa" an expression in term of earlier dimensions? * The alternative is that the dimension is defined to be equal to itself, * meaning that it has a universe domain and an expression that depends @@ -997,49 +982,27 @@ static int tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple) return has_expr; } -/* Add a dimension to the given tuple. - * The dimension is initially undefined, so it is encoded - * as one times itself. - */ -static __isl_give isl_multi_pw_aff *tuple_add_dim( - __isl_take isl_multi_pw_aff *tuple, struct vars *v) -{ - isl_space *space; - isl_aff *aff; - isl_pw_aff *pa; - - tuple = isl_multi_pw_aff_add_dims(tuple, isl_dim_in, 1); - space = isl_multi_pw_aff_get_domain_space(tuple); - aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); - aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n, 1); - pa = isl_pw_aff_from_aff(aff); - tuple = isl_multi_pw_aff_flat_range_product(tuple, - isl_multi_pw_aff_from_pw_aff(pa)); - - return tuple; -} - -/* Set the name of dimension "pos" in "tuple" to "name". +/* Set the name of dimension "pos" in "space" to "name". * During printing, we add primes if the same name appears more than once * to distinguish the occurrences. Here, we remove those primes from "name" * before setting the name of the dimension. */ -static __isl_give isl_multi_pw_aff *tuple_set_dim_name( - __isl_take isl_multi_pw_aff *tuple, int pos, char *name) +static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space, + int pos, char *name) { char *prime; if (!name) - return tuple; + return space; prime = strchr(name, '\''); if (prime) *prime = '\0'; - tuple = isl_multi_pw_aff_set_dim_name(tuple, isl_dim_set, pos, name); + space = isl_space_set_dim_name(space, isl_dim_out, pos, name); if (prime) *prime = '\''; - return tuple; + return space; } /* Accept a piecewise affine expression. @@ -1063,7 +1026,7 @@ static __isl_give isl_multi_pw_aff *tuple_set_dim_name( * expression, we push the parsed expression onto the stream and parse * again in case the parentheses enclose some subexpression of "aff1". */ -static __isl_give isl_pw_aff *accept_piecewise_affine(struct isl_stream *s, +static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s, __isl_take isl_space *space, struct vars *v, int rational) { isl_pw_aff *res; @@ -1116,17 +1079,15 @@ error: return isl_pw_aff_free(res); } -/* Read an affine expression from "s" and replace the definition - * of dimension "pos" in "tuple" by this expression. +/* Read an affine expression from "s" for use in read_tuple. * * accept_extended_affine requires a wrapped space as input. - * The domain space of "tuple", on the other hand is an anonymous space, - * so we have to adjust the space of the isl_pw_aff before adding it - * to "tuple". + * read_tuple on the other hand expects each isl_pw_aff + * to have an anonymous space. We therefore adjust the space + * of the isl_pw_aff before returning it. */ -static __isl_give isl_multi_pw_aff *read_tuple_var_def(struct isl_stream *s, - __isl_take isl_multi_pw_aff *tuple, int pos, struct vars *v, - int rational) +static __isl_give isl_pw_aff *read_tuple_var_def(__isl_keep isl_stream *s, + struct vars *v, int rational) { isl_space *space; isl_pw_aff *def; @@ -1137,87 +1098,70 @@ static __isl_give isl_multi_pw_aff *read_tuple_var_def(struct isl_stream *s, space = isl_space_set_alloc(s->ctx, 0, v->n); def = isl_pw_aff_reset_domain_space(def, space); - tuple = isl_multi_pw_aff_set_pw_aff(tuple, pos, def); - return tuple; + return def; } -/* Read a list of variables and/or affine expressions and return the list - * as an isl_multi_pw_aff. +/* Read a list of tuple elements by calling "read_el" on each of them and + * return a space with the same number of set dimensions derived from + * the parameter space "space" and possibly updated by "read_el". * The elements in the list are separated by either "," or "][". * If "comma" is set then only "," is allowed. */ -static __isl_give isl_multi_pw_aff *read_tuple_var_list(struct isl_stream *s, - struct vars *v, int rational, int comma) +static __isl_give isl_space *read_tuple_list(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, int comma, + __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, + void *user), + void *user) { - int i = 0; - struct isl_token *tok; - isl_multi_pw_aff *res; + if (!space) + return NULL; - res = tuple_alloc(v); + space = isl_space_set_from_params(space); if (isl_stream_next_token_is(s, ']')) - return res; + return space; - while ((tok = next_token(s)) != NULL) { - int new_name = 0; - - res = tuple_add_dim(res, v); + for (;;) { + struct isl_token *tok; - if (tok->type == ISL_TOKEN_IDENT) { - int n = v->n; - int p = vars_pos(v, tok->u.s, -1); - if (p < 0) - goto error; - new_name = p >= n; - } + space = isl_space_add_dims(space, isl_dim_set, 1); - 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, '=')) - res = read_tuple_var_def(s, res, i, v, - rational); - } else { - isl_stream_push_token(s, tok); - tok = NULL; - if (vars_add_anon(v) < 0) - goto error; - res = read_tuple_var_def(s, res, i, v, rational); - } + space = read_el(s, v, space, rational, user); + if (!space) + return NULL; tok = isl_stream_next_token(s); if (!comma && tok && tok->type == ']' && isl_stream_next_token_is(s, '[')) { isl_token_free(tok); tok = isl_stream_next_token(s); - } else if (!tok || tok->type != ',') + } else if (!tok || tok->type != ',') { + if (tok) + isl_stream_push_token(s, tok); break; + } isl_token_free(tok); - i++; } - if (tok) - isl_stream_push_token(s, tok); - return res; -error: - isl_token_free(tok); - return isl_multi_pw_aff_free(res); + return space; } -/* Read a tuple and represent it as an isl_multi_pw_aff. See tuple_alloc. +/* Read a tuple space from "s" derived from the parameter space "space". + * Call "read_el" on each element in the tuples. */ -static __isl_give isl_multi_pw_aff *read_tuple(struct isl_stream *s, - struct vars *v, int rational, int comma) +static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, int comma, + __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, + void *user), + void *user) { struct isl_token *tok; char *name = NULL; - isl_multi_pw_aff *res = NULL; + isl_space *res = NULL; tok = isl_stream_next_token(s); if (!tok) @@ -1232,29 +1176,149 @@ static __isl_give isl_multi_pw_aff *read_tuple(struct isl_stream *s, if (isl_stream_eat(s, '[')) goto error; if (next_is_tuple(s)) { - isl_multi_pw_aff *out; - int n; - res = read_tuple(s, v, rational, comma); + isl_space *out; + res = read_tuple_space(s, v, isl_space_copy(space), + rational, comma, read_el, user); if (isl_stream_eat(s, ISL_TOKEN_TO)) goto error; - out = read_tuple(s, v, rational, comma); - n = isl_multi_pw_aff_dim(out, isl_dim_out); - res = isl_multi_pw_aff_add_dims(res, isl_dim_in, n); - res = isl_multi_pw_aff_range_product(res, out); + out = read_tuple_space(s, v, isl_space_copy(space), + rational, comma, read_el, user); + res = isl_space_range_product(res, out); } else - res = read_tuple_var_list(s, v, rational, comma); + res = read_tuple_list(s, v, isl_space_copy(space), + rational, comma, read_el, user); if (isl_stream_eat(s, ']')) goto error; if (name) { - res = isl_multi_pw_aff_set_tuple_name(res, isl_dim_out, name); + res = isl_space_set_tuple_name(res, isl_dim_set, name); free(name); } + isl_space_free(space); return res; error: free(name); - return isl_multi_pw_aff_free(res); + isl_space_free(res); + isl_space_free(space); + return NULL; +} + +/* Construct an isl_pw_aff defined on a space with v->n variables + * that is equal to the last of those variables. + */ +static __isl_give isl_pw_aff *identity_tuple_el(struct vars *v) +{ + isl_space *space; + isl_aff *aff; + + space = isl_space_set_alloc(v->ctx, 0, v->n); + aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); + aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n - 1, 1); + return isl_pw_aff_from_aff(aff); +} + +/* This function is called for each element in a tuple inside read_tuple. + * Add a new variable to "v" and construct a corresponding isl_pw_aff defined + * over a space containing all variables in "v" defined so far. + * The isl_pw_aff expresses the new variable in terms of earlier variables + * if a definition is provided. Otherwise, it is represented as being + * equal to itself. + * Add the isl_pw_aff to *list. + * If the new variable was named, then adjust "space" accordingly and + * return the updated space. + */ +static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_pw_aff_list **list = (isl_pw_aff_list **) user; + isl_pw_aff *pa; + struct isl_token *tok; + int new_name = 0; + + tok = next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return isl_space_free(space); + } + + if (tok->type == ISL_TOKEN_IDENT) { + int n = v->n; + int p = vars_pos(v, tok->u.s, -1); + if (p < 0) + goto error; + new_name = p >= n; + } + + if (tok->type == '*') { + if (vars_add_anon(v) < 0) + goto error; + isl_token_free(tok); + pa = identity_tuple_el(v); + } else if (new_name) { + int pos = isl_space_dim(space, isl_dim_out) - 1; + space = space_set_dim_name(space, pos, v->v->name); + isl_token_free(tok); + if (isl_stream_eat_if_available(s, '=')) + pa = read_tuple_var_def(s, v, rational); + else + pa = identity_tuple_el(v); + } else { + isl_stream_push_token(s, tok); + tok = NULL; + if (vars_add_anon(v) < 0) + goto error; + pa = read_tuple_var_def(s, v, rational); + } + + *list = isl_pw_aff_list_add(*list, pa); + if (!*list) + return isl_space_free(space); + + return space; +error: + isl_token_free(tok); + return isl_space_free(space); +} + +/* Read a tuple and represent it as an isl_multi_pw_aff. + * The range space of the isl_multi_pw_aff is the space of the tuple. + * The domain space is an anonymous space + * with a dimension for each variable in the set of variables in "v", + * including the variables in the range. + * If a given dimension is not defined in terms of earlier dimensions in + * the input, then the corresponding isl_pw_aff is set equal to one time + * the variable corresponding to the dimension being defined. + * + * The elements in the tuple are collected in a list by read_tuple_pw_aff_el. + * Each element in this list is defined over a space representing + * the variables defined so far. We need to adjust the earlier + * elements to have as many variables in the domain as the final + * element in the list. + */ +static __isl_give isl_multi_pw_aff *read_tuple(__isl_keep isl_stream *s, + struct vars *v, int rational, int comma) +{ + int i, n; + isl_space *space; + isl_pw_aff_list *list; + + space = isl_space_params_alloc(v->ctx, 0); + list = isl_pw_aff_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, rational, comma, + &read_tuple_pw_aff_el, &list); + n = isl_space_dim(space, isl_dim_set); + for (i = 0; i + 1 < n; ++i) { + isl_pw_aff *pa; + + pa = isl_pw_aff_list_get_pw_aff(list, i); + pa = isl_pw_aff_add_dims(pa, isl_dim_in, n - (i + 1)); + list = isl_pw_aff_list_set_pw_aff(list, i, pa); + } + + space = isl_space_from_range(space); + space = isl_space_add_dims(space, isl_dim_in, v->n); + return isl_multi_pw_aff_from_pw_aff_list(space, list); } /* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map". @@ -1348,7 +1412,7 @@ error: * The tuple is initially represented as an isl_multi_pw_aff and * then added to "map". */ -static __isl_give isl_map *read_map_tuple(struct isl_stream *s, +static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s, __isl_take isl_map *map, enum isl_dim_type type, struct vars *v, int rational, int comma) { @@ -1390,7 +1454,7 @@ static __isl_give isl_set *construct_constraints( return isl_set_intersect(set, cond); } -static __isl_give isl_map *add_constraint(struct isl_stream *s, +static __isl_give isl_map *add_constraint(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { struct isl_token *tok = NULL; @@ -1439,7 +1503,7 @@ error: return NULL; } -static __isl_give isl_map *read_exists(struct isl_stream *s, +static __isl_give isl_map *read_exists(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { int n = v->n; @@ -1479,7 +1543,7 @@ error: * Otherwise, we assume that the affine expression is the * start of a condition and continue parsing. */ -static int resolve_paren_expr(struct isl_stream *s, +static int resolve_paren_expr(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { struct isl_token *tok, *tok2; @@ -1551,7 +1615,7 @@ error: return -1; } -static __isl_give isl_map *read_conjunct(struct isl_stream *s, +static __isl_give isl_map *read_conjunct(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { if (isl_stream_next_token_is(s, '(')) @@ -1587,7 +1651,7 @@ error: return NULL; } -static __isl_give isl_map *read_conjuncts(struct isl_stream *s, +static __isl_give isl_map *read_conjuncts(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { isl_map *res; @@ -1613,7 +1677,7 @@ static __isl_give isl_map *read_conjuncts(struct isl_stream *s, return res; } -static struct isl_map *read_disjuncts(struct isl_stream *s, +static struct isl_map *read_disjuncts(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { isl_map *res; @@ -1657,7 +1721,7 @@ static struct isl_map *read_disjuncts(struct isl_stream *s, * * (map \setminus { [..] : a}) \cup (map \cap { [..] : b }) */ -static __isl_give isl_map *read_formula(struct isl_stream *s, +static __isl_give isl_map *read_formula(__isl_keep isl_stream *s, struct vars *v, __isl_take isl_map *map, int rational) { isl_map *res; @@ -1700,7 +1764,7 @@ static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos) } static __isl_give isl_basic_map *basic_map_read_polylib_constraint( - struct isl_stream *s, __isl_take isl_basic_map *bmap) + __isl_keep isl_stream *s, __isl_take isl_basic_map *bmap) { int j; struct isl_token *tok; @@ -1769,7 +1833,8 @@ error: return NULL; } -static __isl_give isl_basic_map *basic_map_read_polylib(struct isl_stream *s) +static __isl_give isl_basic_map *basic_map_read_polylib( + __isl_keep isl_stream *s) { int i; struct isl_token *tok; @@ -1885,7 +1950,7 @@ error: return NULL; } -static struct isl_map *map_read_polylib(struct isl_stream *s) +static struct isl_map *map_read_polylib(__isl_keep isl_stream *s) { struct isl_token *tok; struct isl_token *tok2; @@ -1923,7 +1988,7 @@ static struct isl_map *map_read_polylib(struct isl_stream *s) return map; } -static int optional_power(struct isl_stream *s) +static int optional_power(__isl_keep isl_stream *s) { int pow; struct isl_token *tok; @@ -1948,10 +2013,10 @@ static int optional_power(struct isl_stream *s) return pow; } -static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s, +static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s, __isl_keep isl_map *map, struct vars *v); -static __isl_give isl_pw_qpolynomial *read_factor(struct isl_stream *s, +static __isl_give isl_pw_qpolynomial *read_factor(__isl_keep isl_stream *s, __isl_keep isl_map *map, struct vars *v) { isl_pw_qpolynomial *pwqp; @@ -2059,7 +2124,7 @@ error: return NULL; } -static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s, +static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s, __isl_keep isl_map *map, struct vars *v) { struct isl_token *tok; @@ -2100,7 +2165,7 @@ static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s, return pwqp; } -static __isl_give isl_map *read_optional_formula(struct isl_stream *s, +static __isl_give isl_map *read_optional_formula(__isl_keep isl_stream *s, __isl_take isl_map *map, struct vars *v, int rational) { struct isl_token *tok; @@ -2123,7 +2188,7 @@ error: return NULL; } -static struct isl_obj obj_read_poly(struct isl_stream *s, +static struct isl_obj obj_read_poly(__isl_keep isl_stream *s, __isl_take isl_map *map, struct vars *v, int n) { struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL }; @@ -2142,7 +2207,7 @@ static struct isl_obj obj_read_poly(struct isl_stream *s, return obj; } -static struct isl_obj obj_read_poly_or_fold(struct isl_stream *s, +static struct isl_obj obj_read_poly_or_fold(__isl_keep isl_stream *s, __isl_take isl_set *set, struct vars *v, int n) { struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL }; @@ -2183,7 +2248,7 @@ error: return obj; } -static int is_rational(struct isl_stream *s) +static int is_rational(__isl_keep isl_stream *s) { struct isl_token *tok; @@ -2201,7 +2266,7 @@ static int is_rational(struct isl_stream *s) return 0; } -static struct isl_obj obj_read_body(struct isl_stream *s, +static struct isl_obj obj_read_body(__isl_keep isl_stream *s, __isl_take isl_map *map, struct vars *v) { struct isl_token *tok; @@ -2278,47 +2343,54 @@ error: return obj; } -static struct isl_obj obj_add(struct isl_ctx *ctx, +static struct isl_obj obj_add(__isl_keep isl_stream *s, struct isl_obj obj1, struct isl_obj obj2) { if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set) - obj1 = to_union(ctx, obj1); + obj1 = to_union(s->ctx, obj1); if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set) - obj2 = to_union(ctx, obj2); + obj2 = to_union(s->ctx, obj2); if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map) - obj1 = to_union(ctx, obj1); + obj1 = to_union(s->ctx, obj1); if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map) - obj2 = to_union(ctx, obj2); + obj2 = to_union(s->ctx, obj2); if (obj1.type == isl_obj_pw_qpolynomial && obj2.type == isl_obj_union_pw_qpolynomial) - obj1 = to_union(ctx, obj1); + obj1 = to_union(s->ctx, obj1); if (obj1.type == isl_obj_union_pw_qpolynomial && obj2.type == isl_obj_pw_qpolynomial) - obj2 = to_union(ctx, obj2); + obj2 = to_union(s->ctx, obj2); if (obj1.type == isl_obj_pw_qpolynomial_fold && obj2.type == isl_obj_union_pw_qpolynomial_fold) - obj1 = to_union(ctx, obj1); + obj1 = to_union(s->ctx, obj1); if (obj1.type == isl_obj_union_pw_qpolynomial_fold && obj2.type == isl_obj_pw_qpolynomial_fold) - obj2 = to_union(ctx, obj2); - isl_assert(ctx, obj1.type == obj2.type, goto error); + obj2 = to_union(s->ctx, obj2); + if (obj1.type != obj2.type) { + isl_stream_error(s, NULL, + "attempt to combine incompatible objects"); + goto error; + } + if (!obj1.type->add) + isl_die(s->ctx, isl_error_internal, + "combination not supported on object type", goto error); if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) { - obj1 = to_union(ctx, obj1); - obj2 = to_union(ctx, obj2); + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); } if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) { - obj1 = to_union(ctx, obj1); - obj2 = to_union(ctx, obj2); + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); } if (obj1.type == isl_obj_pw_qpolynomial && !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) { - obj1 = to_union(ctx, obj1); - obj2 = to_union(ctx, obj2); + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); } if (obj1.type == isl_obj_pw_qpolynomial_fold && !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) { - obj1 = to_union(ctx, obj1); - obj2 = to_union(ctx, obj2); + obj1 = to_union(s->ctx, obj1); + obj2 = to_union(s->ctx, obj2); } obj1.v = obj1.type->add(obj1.v, obj2.v); return obj1; @@ -2330,13 +2402,80 @@ error: return obj1; } -static struct isl_obj obj_read(struct isl_stream *s) +/* Are the first two tokens on "s", "domain" (either as a string + * or as an identifier) followed by ":"? + */ +static int next_is_domain_colon(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + char *name; + int res; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != ISL_TOKEN_IDENT && tok->type != ISL_TOKEN_STRING) { + isl_stream_push_token(s, tok); + return 0; + } + + name = isl_token_get_str(s->ctx, tok); + res = !strcmp(name, "domain") && isl_stream_next_token_is(s, ':'); + free(name); + + isl_stream_push_token(s, tok); + + return res; +} + +/* Do the first tokens on "s" look like a schedule? + * + * The root of a schedule is always a domain node, so the first thing + * we expect in the stream is a domain key, i.e., "domain" followed + * by ":". If the schedule was printed in YAML flow style, then + * we additionally expect a "{" to open the outer mapping. + */ +static int next_is_schedule(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int is_schedule; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '{') { + isl_stream_push_token(s, tok); + return next_is_domain_colon(s); + } + + is_schedule = next_is_domain_colon(s); + isl_stream_push_token(s, tok); + + return is_schedule; +} + +/* Read an isl_schedule from "s" and store it in an isl_obj. + */ +static struct isl_obj schedule_read(__isl_keep isl_stream *s) +{ + struct isl_obj obj; + + obj.type = isl_obj_schedule; + obj.v = isl_stream_read_schedule(s); + + return obj; +} + +static struct isl_obj obj_read(__isl_keep isl_stream *s) { isl_map *map = NULL; struct isl_token *tok; struct vars *v = NULL; struct isl_obj obj = { isl_obj_set, NULL }; + if (next_is_schedule(s)) + return schedule_read(s); + tok = next_token(s); if (!tok) { isl_stream_error(s, NULL, "unexpected EOF"); @@ -2425,7 +2564,7 @@ static struct isl_obj obj_read(struct isl_stream *s) if (!obj.v) obj = o; else { - obj = obj_add(s->ctx, obj, o); + obj = obj_add(s, obj, o); if (obj.type == isl_obj_none || !obj.v) goto error; } @@ -2461,12 +2600,12 @@ error: return obj; } -struct isl_obj isl_stream_read_obj(struct isl_stream *s) +struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s) { return obj_read(s); } -__isl_give isl_map *isl_stream_read_map(struct isl_stream *s) +__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s) { struct isl_obj obj; @@ -2484,7 +2623,7 @@ error: return NULL; } -__isl_give isl_set *isl_stream_read_set(struct isl_stream *s) +__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s) { struct isl_obj obj; @@ -2503,7 +2642,7 @@ error: return NULL; } -__isl_give isl_union_map *isl_stream_read_union_map(struct isl_stream *s) +__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s) { struct isl_obj obj; @@ -2528,7 +2667,7 @@ error: return NULL; } -__isl_give isl_union_set *isl_stream_read_union_set(struct isl_stream *s) +__isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s) { struct isl_obj obj; @@ -2546,7 +2685,7 @@ error: return NULL; } -static __isl_give isl_basic_map *basic_map_read(struct isl_stream *s) +static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s) { struct isl_obj obj; struct isl_map *map; @@ -2578,7 +2717,7 @@ error: return NULL; } -static __isl_give isl_basic_set *basic_set_read(struct isl_stream *s) +static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s) { isl_basic_map *bmap; bmap = basic_map_read(s); @@ -2597,7 +2736,7 @@ __isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx, FILE *input) { struct isl_basic_map *bmap; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; bmap = basic_map_read(s); @@ -2609,7 +2748,7 @@ __isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx, FILE *input) { isl_basic_set *bset; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; bset = basic_set_read(s); @@ -2621,7 +2760,7 @@ struct isl_basic_map *isl_basic_map_read_from_str(struct isl_ctx *ctx, const char *str) { struct isl_basic_map *bmap; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; bmap = basic_map_read(s); @@ -2633,7 +2772,7 @@ struct isl_basic_set *isl_basic_set_read_from_str(struct isl_ctx *ctx, const char *str) { isl_basic_set *bset; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; bset = basic_set_read(s); @@ -2645,7 +2784,7 @@ __isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx, FILE *input) { struct isl_map *map; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; map = isl_stream_read_map(s); @@ -2657,7 +2796,7 @@ __isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx, const char *str) { struct isl_map *map; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; map = isl_stream_read_map(s); @@ -2669,7 +2808,7 @@ __isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx, FILE *input) { isl_set *set; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; set = isl_stream_read_set(s); @@ -2681,7 +2820,7 @@ struct isl_set *isl_set_read_from_str(struct isl_ctx *ctx, const char *str) { isl_set *set; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; set = isl_stream_read_set(s); @@ -2693,7 +2832,7 @@ __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, FILE *input) { isl_union_map *umap; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; umap = isl_stream_read_union_map(s); @@ -2705,7 +2844,7 @@ __isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx, const char *str) { isl_union_map *umap; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; umap = isl_stream_read_union_map(s); @@ -2717,7 +2856,7 @@ __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx, FILE *input) { isl_union_set *uset; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; uset = isl_stream_read_union_set(s); @@ -2729,7 +2868,7 @@ __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx, const char *str) { isl_union_set *uset; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; uset = isl_stream_read_union_set(s); @@ -2737,7 +2876,7 @@ __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx, return uset; } -static __isl_give isl_vec *isl_vec_read_polylib(struct isl_stream *s) +static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s) { struct isl_vec *vec = NULL; struct isl_token *tok; @@ -2772,7 +2911,7 @@ error: return NULL; } -static __isl_give isl_vec *vec_read(struct isl_stream *s) +static __isl_give isl_vec *vec_read(__isl_keep isl_stream *s) { return isl_vec_read_polylib(s); } @@ -2780,7 +2919,7 @@ static __isl_give isl_vec *vec_read(struct isl_stream *s) __isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input) { isl_vec *v; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; v = vec_read(s); @@ -2789,7 +2928,7 @@ __isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input) } __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial( - struct isl_stream *s) + __isl_keep isl_stream *s) { struct isl_obj obj; @@ -2808,7 +2947,7 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx, const char *str) { isl_pw_qpolynomial *pwqp; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; pwqp = isl_stream_read_pw_qpolynomial(s); @@ -2820,7 +2959,7 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx, FILE *input) { isl_pw_qpolynomial *pwqp; - struct isl_stream *s = isl_stream_new_file(ctx, input); + isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; pwqp = isl_stream_read_pw_qpolynomial(s); @@ -2830,7 +2969,7 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx, /* Is the next token an identifer not in "v"? */ -static int next_is_fresh_ident(struct isl_stream *s, struct vars *v) +static int next_is_fresh_ident(__isl_keep isl_stream *s, struct vars *v) { int n = v->n; int fresh; @@ -2857,7 +2996,7 @@ static int next_is_fresh_ident(struct isl_stream *s, struct vars *v) * or a new identifier, we again assume it's the domain. * Otherwise, we assume we are reading an affine expression. */ -static __isl_give isl_set *read_aff_domain(struct isl_stream *s, +static __isl_give isl_set *read_aff_domain(__isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) { struct isl_token *tok; @@ -2887,7 +3026,7 @@ error: /* Read an affine expression from "s". */ -__isl_give isl_aff *isl_stream_read_aff(struct isl_stream *s) +__isl_give isl_aff *isl_stream_read_aff(__isl_keep isl_stream *s) { isl_aff *aff; isl_multi_aff *ma; @@ -2910,7 +3049,7 @@ error: /* Read a piecewise affine expression from "s" with domain (space) "dom". */ -static __isl_give isl_pw_aff *read_pw_aff_with_dom(struct isl_stream *s, +static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) { isl_pw_aff *pwaff = NULL; @@ -2936,7 +3075,7 @@ error: return NULL; } -__isl_give isl_pw_aff *isl_stream_read_pw_aff(struct isl_stream *s) +__isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s) { struct vars *v; isl_set *dom = NULL; @@ -2989,7 +3128,7 @@ error: __isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str) { isl_aff *aff; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; aff = isl_stream_read_aff(s); @@ -3000,7 +3139,7 @@ __isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str) __isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str) { isl_pw_aff *pa; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; pa = isl_stream_read_pw_aff(s); @@ -3014,7 +3153,8 @@ __isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str) * It would be more efficient if we were to construct the isl_pw_multi_aff * directly. */ -__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(struct isl_stream *s) +__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff( + __isl_keep isl_stream *s) { struct isl_obj obj; @@ -3036,7 +3176,7 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx, const char *str) { isl_pw_multi_aff *pma; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; pma = isl_stream_read_pw_multi_aff(s); @@ -3051,7 +3191,7 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx, * 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) + __isl_keep isl_stream *s) { struct isl_obj obj; @@ -3077,7 +3217,7 @@ __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); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; upma = isl_stream_read_union_pw_multi_aff(s); @@ -3111,6 +3251,86 @@ error: return NULL; } +/* This function is called for each element in a tuple inside + * isl_stream_read_multi_val. + * Read an isl_val from "s" and add it to *list. + */ +static __isl_give isl_space *read_val_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_val_list **list = (isl_val_list **) user; + isl_val *val; + + val = isl_stream_read_val(s); + *list = isl_val_list_add(*list, val); + if (!*list) + return isl_space_free(space); + + return space; +} + +/* Read an isl_multi_val from "s". + * + * We first read a tuple space, collecting the element values in a list. + * Then we create an isl_multi_val from the space and the isl_val_list. + */ +__isl_give isl_multi_val *isl_stream_read_multi_val(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_space *space; + isl_multi_val *mv = NULL; + isl_val_list *list; + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + if (!isl_set_plain_is_universe(dom)) + isl_die(s->ctx, isl_error_invalid, + "expecting universe parameter domain", goto error); + if (isl_stream_eat(s, '{')) + goto error; + + space = isl_set_get_space(dom); + + list = isl_val_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, 1, 0, &read_val_el, &list); + mv = isl_multi_val_from_val_list(space, list); + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + isl_set_free(dom); + return mv; +error: + vars_free(v); + isl_set_free(dom); + isl_multi_val_free(mv); + return NULL; +} + +/* Read an isl_multi_val from "str". + */ +__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx, + const char *str) +{ + isl_multi_val *mv; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + mv = isl_stream_read_multi_val(s); + isl_stream_free(s); + return mv; +} + /* Read a multi-affine expression from "s". * If the multi-affine expression has a domain, then the tuple * representing this domain cannot involve any affine expressions. @@ -3119,7 +3339,7 @@ error: * only depend on parameters and input dimensions and not on other * output dimensions. */ -__isl_give isl_multi_aff *isl_stream_read_multi_aff(struct isl_stream *s) +__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) { struct vars *v; isl_set *dom = NULL; @@ -3215,7 +3435,7 @@ __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, const char *str) { isl_multi_aff *maff; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; maff = isl_stream_read_multi_aff(s); @@ -3248,7 +3468,8 @@ __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, * of read_tuple (which is of the form [input, output] -> [output], * with anonymous domain) and reset the space. */ -__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(struct isl_stream *s) +__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff( + __isl_keep isl_stream *s) { struct vars *v; isl_set *dom = NULL; @@ -3329,7 +3550,7 @@ __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, const char *str) { isl_multi_pw_aff *mpa; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; mpa = isl_stream_read_multi_pw_aff(s); @@ -3337,8 +3558,202 @@ __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, return mpa; } +/* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom". + */ +static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom( + __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) +{ + isl_pw_aff *pa; + isl_union_pw_aff *upa = NULL; + isl_set *aff_dom; + int n; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + upa = isl_union_pw_aff_from_pw_aff(pa); + + while (isl_stream_eat_if_available(s, ';')) { + isl_pw_aff *pa_i; + isl_union_pw_aff *upa_i; + + n = v->n; + aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + pa_i = read_pw_aff_with_dom(s, aff_dom, v); + vars_drop(v, v->n - n); + + upa_i = isl_union_pw_aff_from_pw_aff(pa_i); + upa = isl_union_pw_aff_union_add(upa, upa_i); + } + + isl_set_free(dom); + return upa; +} + +/* This function is called for each element in a tuple inside + * isl_stream_read_multi_union_pw_aff. + * + * Read a '{', the union piecewise affine expression body and a '}' and + * add the isl_union_pw_aff to *list. + */ +static __isl_give isl_space *read_union_pw_aff_el(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + isl_set *dom; + isl_union_pw_aff *upa; + isl_union_pw_aff_list **list = (isl_union_pw_aff_list **) user; + + dom = isl_set_universe(isl_space_params(isl_space_copy(space))); + if (isl_stream_eat(s, '{')) + goto error; + upa = read_union_pw_aff_with_dom(s, dom, v); + *list = isl_union_pw_aff_list_add(*list, upa); + if (isl_stream_eat(s, '}')) + return isl_space_free(space); + if (!*list) + return isl_space_free(space); + return space; +error: + isl_set_free(dom); + return isl_space_free(space); +} + +/* Do the next tokens in "s" correspond to an empty tuple? + * In particular, does the stream start with a '[', followed by a ']', + * not followed by a "->"? + */ +static int next_is_empty_tuple(__isl_keep isl_stream *s) +{ + struct isl_token *tok, *tok2, *tok3; + int is_empty_tuple = 0; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '[') { + isl_stream_push_token(s, tok); + return 0; + } + + tok2 = isl_stream_next_token(s); + if (tok2 && tok2->type == ']') { + tok3 = isl_stream_next_token(s); + is_empty_tuple = !tok || tok->type != ISL_TOKEN_TO; + if (tok3) + isl_stream_push_token(s, tok3); + } + if (tok2) + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + + return is_empty_tuple; +} + +/* Do the next tokens in "s" correspond to a tuple of parameters? + * In particular, does the stream start with a '[' that is not + * followed by a '{' or a nested tuple? + */ +static int next_is_param_tuple(__isl_keep isl_stream *s) +{ + struct isl_token *tok, *tok2; + int is_tuple; + + tok = isl_stream_next_token(s); + if (!tok) + return 0; + if (tok->type != '[' || next_is_tuple(s)) { + isl_stream_push_token(s, tok); + return 0; + } + + tok2 = isl_stream_next_token(s); + is_tuple = tok2 && tok2->type != '{'; + if (tok2) + isl_stream_push_token(s, tok2); + isl_stream_push_token(s, tok); + + return is_tuple; +} + +/* Read an isl_multi_union_pw_aff from "s". + * + * The input has the form + * + * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }] + * + * or + * + * [..] -> [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }] + * + * We first check for the special case of an empty tuple "[]". + * Then we check if there are any parameters. + * Finally, we read the tuple, collecting the individual isl_union_pw_aff + * elements in a list and construct the result from the tuple space and + * the list. + */ +__isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff( + __isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom = NULL; + isl_space *space; + isl_multi_union_pw_aff *mupa = NULL; + isl_union_pw_aff_list *list; + + if (next_is_empty_tuple(s)) { + if (isl_stream_eat(s, '[')) + return NULL; + if (isl_stream_eat(s, ']')) + return NULL; + space = isl_space_set_alloc(s->ctx, 0, 0); + return isl_multi_union_pw_aff_zero(space); + } + + v = vars_new(s->ctx); + if (!v) + return NULL; + + dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0)); + if (next_is_param_tuple(s)) { + dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0); + if (isl_stream_eat(s, ISL_TOKEN_TO)) + goto error; + } + space = isl_set_get_space(dom); + isl_set_free(dom); + list = isl_union_pw_aff_list_alloc(s->ctx, 0); + space = read_tuple_space(s, v, space, 1, 0, + &read_union_pw_aff_el, &list); + mupa = isl_multi_union_pw_aff_from_union_pw_aff_list(space, list); + + vars_free(v); + + return mupa; +error: + vars_free(v); + isl_set_free(dom); + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Read an isl_multi_union_pw_aff from "str". + */ +__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str( + isl_ctx *ctx, const char *str) +{ + isl_multi_union_pw_aff *mupa; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + mupa = isl_stream_read_multi_union_pw_aff(s); + isl_stream_free(s); + return mupa; +} + __isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial( - struct isl_stream *s) + __isl_keep isl_stream *s) { struct isl_obj obj; @@ -3361,7 +3776,7 @@ __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str( isl_ctx *ctx, const char *str) { isl_union_pw_qpolynomial *upwqp; - struct isl_stream *s = isl_stream_new_str(ctx, str); + isl_stream *s = isl_stream_new_str(ctx, str); if (!s) return NULL; upwqp = isl_stream_read_union_pw_qpolynomial(s); diff --git a/polly/lib/External/isl/isl_local_space.c b/polly/lib/External/isl/isl_local_space.c index 4de3b357de1..7b1f09d65a9 100644 --- a/polly/lib/External/isl/isl_local_space.c +++ b/polly/lib/External/isl/isl_local_space.c @@ -1361,3 +1361,20 @@ __isl_give isl_local_space *isl_local_space_flatten_range( return ls; } + +/* Given the local space "ls" of a map, return the local space of a set + * that lives in a space that wraps the space of "ls" and that has + * the same divs. + */ +__isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls) +{ + ls = isl_local_space_cow(ls); + if (!ls) + return NULL; + + ls->dim = isl_space_wrap(ls->dim); + if (!ls->dim) + return isl_local_space_free(ls); + + return ls; +} diff --git a/polly/lib/External/isl/isl_map.c b/polly/lib/External/isl/isl_map.c index 8f021c09e66..7bc6d14b099 100644 --- a/polly/lib/External/isl/isl_map.c +++ b/polly/lib/External/isl/isl_map.c @@ -1626,8 +1626,10 @@ struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap) bmap->ref--; bmap = isl_basic_map_dup(bmap); } - if (bmap) + if (bmap) { ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL); + ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); + } return bmap; } @@ -4553,22 +4555,23 @@ __isl_give isl_basic_set *isl_basic_set_underlying_set( } /* Replace each element in "list" by the result of applying - * isl_basic_set_underlying_set to the element. + * isl_basic_map_underlying_set to the element. */ -__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set( - __isl_take isl_basic_set_list *list) +__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set( + __isl_take isl_basic_map_list *list) { int i, n; if (!list) return NULL; - n = isl_basic_set_list_n_basic_set(list); + n = isl_basic_map_list_n_basic_map(list); for (i = 0; i < n; ++i) { + isl_basic_map *bmap; isl_basic_set *bset; - bset = isl_basic_set_list_get_basic_set(list, i); - bset = isl_basic_set_underlying_set(bset); + bmap = isl_basic_map_list_get_basic_map(list, i); + bset = isl_basic_set_underlying_set(bmap); list = isl_basic_set_list_set_basic_set(list, i, bset); } @@ -8405,54 +8408,54 @@ struct isl_set *isl_set_align_divs(struct isl_set *set) return (struct isl_set *)isl_map_align_divs((struct isl_map *)set); } -/* Align the divs of the basic sets in "set" to those - * of the basic sets in "list", as well as to the other basic sets in "set". +/* Align the divs of the basic maps in "map" to those + * of the basic maps in "list", as well as to the other basic maps in "map". * The elements in "list" are assumed to have known divs. */ -__isl_give isl_set *isl_set_align_divs_to_basic_set_list( - __isl_take isl_set *set, __isl_keep isl_basic_set_list *list) +__isl_give isl_map *isl_map_align_divs_to_basic_map_list( + __isl_take isl_map *map, __isl_keep isl_basic_map_list *list) { int i, n; - set = isl_set_compute_divs(set); - set = isl_set_cow(set); - if (!set || !list) - return isl_set_free(set); - if (set->n == 0) - return set; + map = isl_map_compute_divs(map); + map = isl_map_cow(map); + if (!map || !list) + return isl_map_free(map); + if (map->n == 0) + return map; - n = isl_basic_set_list_n_basic_set(list); + n = isl_basic_map_list_n_basic_map(list); for (i = 0; i < n; ++i) { - isl_basic_set *bset; + isl_basic_map *bmap; - bset = isl_basic_set_list_get_basic_set(list, i); - set->p[0] = isl_basic_set_align_divs(set->p[0], bset); - isl_basic_set_free(bset); + bmap = isl_basic_map_list_get_basic_map(list, i); + map->p[0] = isl_basic_map_align_divs(map->p[0], bmap); + isl_basic_map_free(bmap); } - if (!set->p[0]) - return isl_set_free(set); + if (!map->p[0]) + return isl_map_free(map); - return isl_set_align_divs(set); + return isl_map_align_divs(map); } -/* Align the divs of each element of "list" to those of "bset". - * Both "bset" and the elements of "list" are assumed to have known divs. +/* Align the divs of each element of "list" to those of "bmap". + * Both "bmap" and the elements of "list" are assumed to have known divs. */ -__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set( - __isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset) +__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map( + __isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap) { int i, n; - if (!list || !bset) - return isl_basic_set_list_free(list); + if (!list || !bmap) + return isl_basic_map_list_free(list); - n = isl_basic_set_list_n_basic_set(list); + n = isl_basic_map_list_n_basic_map(list); for (i = 0; i < n; ++i) { - isl_basic_set *bset_i; + isl_basic_map *bmap_i; - bset_i = isl_basic_set_list_get_basic_set(list, i); - bset_i = isl_basic_set_align_divs(bset_i, bset); - list = isl_basic_set_list_set_basic_set(list, i, bset_i); + bmap_i = isl_basic_map_list_get_basic_map(list, i); + bmap_i = isl_basic_map_align_divs(bmap_i, bmap); + list = isl_basic_map_list_set_basic_map(list, i, bmap_i); } return list; @@ -9326,25 +9329,25 @@ error: return NULL; } -/* Return the basic sets in "set" as a list. +/* Return the basic maps in "map" as a list. */ -__isl_give isl_basic_set_list *isl_set_get_basic_set_list( - __isl_keep isl_set *set) +__isl_give isl_basic_map_list *isl_map_get_basic_map_list( + __isl_keep isl_map *map) { int i; isl_ctx *ctx; - isl_basic_set_list *list; + isl_basic_map_list *list; - if (!set) + if (!map) return NULL; - ctx = isl_set_get_ctx(set); - list = isl_basic_set_list_alloc(ctx, set->n); + ctx = isl_map_get_ctx(map); + list = isl_basic_map_list_alloc(ctx, map->n); - for (i = 0; i < set->n; ++i) { - isl_basic_set *bset; + for (i = 0; i < map->n; ++i) { + isl_basic_map *bmap; - bset = isl_basic_set_copy(set->p[i]); - list = isl_basic_set_list_add(list, bset); + bmap = isl_basic_map_copy(map->p[i]); + list = isl_basic_map_list_add(list, bmap); } return list; @@ -9353,34 +9356,43 @@ __isl_give isl_basic_set_list *isl_set_get_basic_set_list( /* Return the intersection of the elements in the non-empty list "list". * All elements are assumed to live in the same space. */ -__isl_give isl_basic_set *isl_basic_set_list_intersect( - __isl_take struct isl_basic_set_list *list) +__isl_give isl_basic_map *isl_basic_map_list_intersect( + __isl_take isl_basic_map_list *list) { int i, n; - isl_basic_set *bset; + isl_basic_map *bmap; if (!list) return NULL; - n = isl_basic_set_list_n_basic_set(list); + n = isl_basic_map_list_n_basic_map(list); if (n < 1) - isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid, + isl_die(isl_basic_map_list_get_ctx(list), isl_error_invalid, "expecting non-empty list", goto error); - - bset = isl_basic_set_list_get_basic_set(list, 0); + + bmap = isl_basic_map_list_get_basic_map(list, 0); for (i = 1; i < n; ++i) { - isl_basic_set *bset_i; + isl_basic_map *bmap_i; - bset_i = isl_basic_set_list_get_basic_set(list, i); - bset = isl_basic_set_intersect(bset, bset_i); + bmap_i = isl_basic_map_list_get_basic_map(list, i); + bmap = isl_basic_map_intersect(bmap, bmap_i); } - isl_basic_set_list_free(list); - return bset; + isl_basic_map_list_free(list); + return bmap; error: - isl_basic_set_list_free(list); + isl_basic_map_list_free(list); return NULL; } +/* Return the intersection of the elements in the non-empty list "list". + * All elements are assumed to live in the same space. + */ +__isl_give isl_basic_set *isl_basic_set_list_intersect( + __isl_take isl_basic_set_list *list) +{ + return isl_basic_map_list_intersect(list); +} + /* Return the Cartesian product of the basic sets in list (in the given order). */ __isl_give isl_basic_set *isl_basic_set_list_product( diff --git a/polly/lib/External/isl/isl_map_list.c b/polly/lib/External/isl/isl_map_list.c new file mode 100644 index 00000000000..6e818c59636 --- /dev/null +++ b/polly/lib/External/isl/isl_map_list.c @@ -0,0 +1,31 @@ +#include <isl/map.h> + +#undef EL +#define EL isl_basic_map + +#include <isl_list_templ.h> + +#undef BASE +#define BASE basic_map + +#include <isl_list_templ.c> + +#undef EL +#define EL isl_map + +#include <isl_list_templ.h> + +#undef BASE +#define BASE map + +#include <isl_list_templ.c> + +#undef EL +#define EL isl_union_map + +#include <isl_list_templ.h> + +#undef BASE +#define BASE union_map + +#include <isl_list_templ.c> diff --git a/polly/lib/External/isl/isl_map_private.h b/polly/lib/External/isl/isl_map_private.h index 7f1cd589b56..a424ef99ec3 100644 --- a/polly/lib/External/isl/isl_map_private.h +++ b/polly/lib/External/isl/isl_map_private.h @@ -15,12 +15,11 @@ #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> #include <isl/vec.h> +#include <isl/hash.h> #include <isl_blk.h> /* A "basic map" is a relation between two sets of variables, @@ -43,6 +42,7 @@ struct isl_basic_map { #define ISL_BASIC_MAP_NORMALIZED (1 << 5) #define ISL_BASIC_MAP_NORMALIZED_DIVS (1 << 6) #define ISL_BASIC_MAP_ALL_EQUALITIES (1 << 7) +#define ISL_BASIC_MAP_REDUCED_COEFFICIENTS (1 << 8) #define ISL_BASIC_SET_FINAL (1 << 0) #define ISL_BASIC_SET_EMPTY (1 << 1) #define ISL_BASIC_SET_NO_IMPLICIT (1 << 2) @@ -51,6 +51,7 @@ struct isl_basic_map { #define ISL_BASIC_SET_NORMALIZED (1 << 5) #define ISL_BASIC_SET_NORMALIZED_DIVS (1 << 6) #define ISL_BASIC_SET_ALL_EQUALITIES (1 << 7) +#define ISL_BASIC_SET_REDUCED_COEFFICIENTS (1 << 8) unsigned flags; struct isl_ctx *ctx; @@ -198,6 +199,8 @@ struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap); struct isl_set *isl_set_cow(struct isl_set *set); struct isl_map *isl_map_cow(struct isl_map *map); +uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap); + struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap); struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset); struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset); @@ -208,10 +211,10 @@ struct isl_basic_map *isl_basic_map_align_divs( struct isl_basic_map *dst, struct isl_basic_map *src); struct isl_basic_set *isl_basic_set_align_divs( struct isl_basic_set *dst, struct isl_basic_set *src); -__isl_give isl_set *isl_set_align_divs_to_basic_set_list( - __isl_take isl_set *set, __isl_keep isl_basic_set_list *list); -__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set( - __isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset); +__isl_give isl_map *isl_map_align_divs_to_basic_map_list( + __isl_take isl_map *map, __isl_keep isl_basic_map_list *list); +__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map( + __isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap); __isl_give isl_basic_map *isl_basic_map_sort_divs( __isl_take isl_basic_map *bmap); __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map); @@ -234,8 +237,8 @@ struct isl_basic_map *isl_basic_map_implicit_equalities( struct isl_basic_set *isl_basic_map_underlying_set(struct isl_basic_map *bmap); __isl_give isl_basic_set *isl_basic_set_underlying_set( __isl_take isl_basic_set *bset); -__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set( - __isl_take isl_basic_set_list *list); +__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set( + __isl_take isl_basic_map_list *list); struct isl_set *isl_map_underlying_set(struct isl_map *map); struct isl_basic_map *isl_basic_map_overlying_set(struct isl_basic_set *bset, struct isl_basic_map *like); @@ -258,6 +261,8 @@ struct isl_map *isl_map_drop(struct isl_map *map, __isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints( __isl_take isl_basic_map *bmap, int *progress, int detect_divs); +__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs( + __isl_take isl_basic_map *bmap, int *progress); struct isl_map *isl_map_remove_empty_parts(struct isl_map *map); struct isl_set *isl_set_remove_empty_parts(struct isl_set *set); @@ -381,6 +386,9 @@ int isl_map_is_set(__isl_keep isl_map *map); int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset, unsigned dim, isl_int *val); +__isl_give isl_basic_map *isl_basic_map_plain_affine_hull( + __isl_take isl_basic_map *bmap); + int isl_basic_set_dim_residue_class(struct isl_basic_set *bset, int pos, isl_int *modulo, isl_int *residue); int isl_set_dim_residue_class(struct isl_set *set, @@ -396,8 +404,14 @@ int isl_map_plain_is_fixed(__isl_keep isl_map *map, int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap, int pos); -__isl_give isl_basic_set_list *isl_set_get_basic_set_list( - __isl_keep isl_set *set); +__isl_give isl_basic_map *isl_basic_map_reduce_coefficients( + __isl_take isl_basic_map *bmap); + +__isl_give isl_basic_map *isl_basic_map_shift_div( + __isl_take isl_basic_map *bmap, int div, isl_int shift); + +__isl_give isl_basic_map_list *isl_map_get_basic_map_list( + __isl_keep isl_map *map); __isl_give isl_map *isl_map_fixed_power(__isl_take isl_map *map, isl_int exp); diff --git a/polly/lib/External/isl/isl_map_simplify.c b/polly/lib/External/isl/isl_map_simplify.c index 78815bd98c7..fdde7308288 100644 --- a/polly/lib/External/isl/isl_map_simplify.c +++ b/polly/lib/External/isl/isl_map_simplify.c @@ -1,6 +1,6 @@ /* * Copyright 2008-2009 Katholieke Universiteit Leuven - * Copyright 2012 Ecole Normale Superieure + * Copyright 2012-2013 Ecole Normale Superieure * Copyright 2014 INRIA Rocquencourt * * Use of this software is governed by the MIT license @@ -1184,6 +1184,26 @@ __isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints( return bmap; } +/* Detect all pairs of inequalities that form an equality. + * + * isl_basic_map_remove_duplicate_constraints detects at most one such pair. + * Call it repeatedly while it is making progress. + */ +__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs( + __isl_take isl_basic_map *bmap, int *progress) +{ + int duplicate; + + do { + duplicate = 0; + bmap = isl_basic_map_remove_duplicate_constraints(bmap, + &duplicate, 0); + if (progress && duplicate) + *progress = 1; + } while (duplicate); + + return bmap; +} /* Eliminate knowns divs from constraints where they appear with * a (positive or negative) unit coefficient. @@ -1300,6 +1320,8 @@ struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap) bmap = normalize_divs(bmap, &progress); bmap = isl_basic_map_remove_duplicate_constraints(bmap, &progress, 1); + if (bmap && progress) + ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); } return bmap; } @@ -2352,12 +2374,21 @@ error: * return the corresponding universe. * * If none of these cases apply, we have to work a bit harder. + * During this computation, we make use of a single disjunct context, + * so if the original context consists of more than one disjunct + * then we need to approximate the context by a single disjunct set. + * Simply taking the simple hull may drop constraints that are + * only implicitly available in each disjunct. We therefore also + * look for constraints among those defining "map" that are valid + * for the context. These can then be used to simplify away + * the corresponding constraints in "map". */ static __isl_give isl_map *map_gist(__isl_take isl_map *map, __isl_take isl_map *context) { int equal; int is_universe; + isl_basic_map *hull; is_universe = isl_map_plain_is_universe(map); if (is_universe >= 0 && !is_universe) @@ -2380,7 +2411,22 @@ static __isl_give isl_map *map_gist(__isl_take isl_map *map, } context = isl_map_compute_divs(context); - return isl_map_gist_basic_map(map, isl_map_simple_hull(context)); + if (!context) + goto error; + if (isl_map_n_basic_map(context) == 1) { + hull = isl_map_simple_hull(context); + } else { + isl_ctx *ctx; + isl_map_list *list; + + ctx = isl_map_get_ctx(map); + list = isl_map_list_alloc(ctx, 2); + list = isl_map_list_add(list, isl_map_copy(context)); + list = isl_map_list_add(list, isl_map_copy(map)); + hull = isl_map_unshifted_simple_hull_from_map_list(context, + list); + } + return isl_map_gist_basic_map(map, hull); error: isl_map_free(map); isl_map_free(context); @@ -2423,6 +2469,19 @@ __isl_give isl_set *isl_set_gist(__isl_take isl_set *set, (struct isl_map *)context); } +/* Compute the gist of "bmap" with respect to the constraints "context" + * on the domain. + */ +__isl_give isl_basic_map *isl_basic_map_gist_domain( + __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context) +{ + isl_space *space = isl_basic_map_get_space(bmap); + isl_basic_map *bmap_context = isl_basic_map_universe(space); + + bmap_context = isl_basic_map_intersect_domain(bmap_context, context); + return isl_basic_map_gist(bmap, bmap_context); +} + __isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map, __isl_take isl_set *context) { @@ -3255,3 +3314,207 @@ struct isl_set *isl_set_drop_redundant_divs(struct isl_set *set) return (struct isl_set *) isl_map_drop_redundant_divs((struct isl_map *)set); } + +/* Does "bmap" satisfy any equality that involves more than 2 variables + * and/or has coefficients different from -1 and 1? + */ +static int has_multiple_var_equality(__isl_keep isl_basic_map *bmap) +{ + int i; + unsigned total; + + total = isl_basic_map_dim(bmap, isl_dim_all); + + for (i = 0; i < bmap->n_eq; ++i) { + int j, k; + + j = isl_seq_first_non_zero(bmap->eq[i] + 1, total); + if (j < 0) + continue; + if (!isl_int_is_one(bmap->eq[i][1 + j]) && + !isl_int_is_negone(bmap->eq[i][1 + j])) + return 1; + + j += 1; + k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j); + if (k < 0) + continue; + j += k; + if (!isl_int_is_one(bmap->eq[i][1 + j]) && + !isl_int_is_negone(bmap->eq[i][1 + j])) + return 1; + + j += 1; + k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j); + if (k >= 0) + return 1; + } + + return 0; +} + +/* Remove any common factor g from the constraint coefficients in "v". + * The constant term is stored in the first position and is replaced + * by floor(c/g). If any common factor is removed and if this results + * in a tightening of the constraint, then set *tightened. + */ +static __isl_give isl_vec *normalize_constraint(__isl_take isl_vec *v, + int *tightened) +{ + isl_ctx *ctx; + + if (!v) + return NULL; + ctx = isl_vec_get_ctx(v); + isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd); + if (isl_int_is_zero(ctx->normalize_gcd)) + return v; + if (isl_int_is_one(ctx->normalize_gcd)) + return v; + v = isl_vec_cow(v); + if (!v) + return NULL; + if (tightened && !isl_int_is_divisible_by(v->el[0], ctx->normalize_gcd)) + *tightened = 1; + isl_int_fdiv_q(v->el[0], v->el[0], ctx->normalize_gcd); + isl_seq_scale_down(v->el + 1, v->el + 1, ctx->normalize_gcd, + v->size - 1); + return v; +} + +/* If "bmap" is an integer set that satisfies any equality involving + * more than 2 variables and/or has coefficients different from -1 and 1, + * then use variable compression to reduce the coefficients by removing + * any (hidden) common factor. + * In particular, apply the variable compression to each constraint, + * factor out any common factor in the non-constant coefficients and + * then apply the inverse of the compression. + * At the end, we mark the basic map as having reduced constants. + * If this flag is still set on the next invocation of this function, + * then we skip the computation. + * + * Removing a common factor may result in a tightening of some of + * the constraints. If this happens, then we may end up with two + * opposite inequalities that can be replaced by an equality. + * We therefore call isl_basic_map_detect_inequality_pairs, + * which checks for such pairs of inequalities as well as eliminate_divs_eq + * if such a pair was found. + */ +__isl_give isl_basic_map *isl_basic_map_reduce_coefficients( + __isl_take isl_basic_map *bmap) +{ + unsigned total; + isl_ctx *ctx; + isl_vec *v; + isl_mat *eq, *T, *T2; + int i; + int tightened; + + if (!bmap) + return NULL; + if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS)) + return bmap; + if (isl_basic_map_is_rational(bmap)) + return bmap; + if (bmap->n_eq == 0) + return bmap; + if (!has_multiple_var_equality(bmap)) + return bmap; + + total = isl_basic_map_dim(bmap, isl_dim_all); + ctx = isl_basic_map_get_ctx(bmap); + v = isl_vec_alloc(ctx, 1 + total); + if (!v) + return isl_basic_map_free(bmap); + + eq = isl_mat_sub_alloc6(ctx, bmap->eq, 0, bmap->n_eq, 0, 1 + total); + T = isl_mat_variable_compression(eq, &T2); + if (!T || !T2) + goto error; + if (T->n_col == 0) { + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + return isl_basic_map_set_to_empty(bmap); + } + + tightened = 0; + for (i = 0; i < bmap->n_ineq; ++i) { + isl_seq_cpy(v->el, bmap->ineq[i], 1 + total); + v = isl_vec_mat_product(v, isl_mat_copy(T)); + v = normalize_constraint(v, &tightened); + v = isl_vec_mat_product(v, isl_mat_copy(T2)); + if (!v) + goto error; + isl_seq_cpy(bmap->ineq[i], v->el, 1 + total); + } + + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + + ISL_F_SET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); + + if (tightened) { + int progress = 0; + + bmap = isl_basic_map_detect_inequality_pairs(bmap, &progress); + if (progress) + bmap = eliminate_divs_eq(bmap, &progress); + } + + return bmap; +error: + isl_mat_free(T); + isl_mat_free(T2); + isl_vec_free(v); + return isl_basic_map_free(bmap); +} + +/* Shift the integer division at position "div" of "bmap" by "shift". + * + * That is, if the integer division has the form + * + * floor(f(x)/d) + * + * then replace it by + * + * floor((f(x) + shift * d)/d) - shift + */ +__isl_give isl_basic_map *isl_basic_map_shift_div( + __isl_take isl_basic_map *bmap, int div, isl_int shift) +{ + int i; + unsigned total; + + if (!bmap) + return NULL; + + total = isl_basic_map_dim(bmap, isl_dim_all); + total -= isl_basic_map_dim(bmap, isl_dim_div); + + isl_int_addmul(bmap->div[div][1], shift, bmap->div[div][0]); + + for (i = 0; i < bmap->n_eq; ++i) { + if (isl_int_is_zero(bmap->eq[i][1 + total + div])) + continue; + isl_int_submul(bmap->eq[i][0], + shift, bmap->eq[i][1 + total + div]); + } + for (i = 0; i < bmap->n_ineq; ++i) { + if (isl_int_is_zero(bmap->ineq[i][1 + total + div])) + continue; + isl_int_submul(bmap->ineq[i][0], + shift, bmap->ineq[i][1 + total + div]); + } + for (i = 0; i < bmap->n_div; ++i) { + if (isl_int_is_zero(bmap->div[i][0])) + continue; + if (isl_int_is_zero(bmap->div[i][1 + 1 + total + div])) + continue; + isl_int_submul(bmap->div[i][1], + shift, bmap->div[i][1 + 1 + total + div]); + } + + return bmap; +} diff --git a/polly/lib/External/isl/isl_morph.c b/polly/lib/External/isl/isl_morph.c index 9030cab1bda..9c14c80a466 100644 --- a/polly/lib/External/isl/isl_morph.c +++ b/polly/lib/External/isl/isl_morph.c @@ -304,8 +304,8 @@ void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out) if (!morph) return; - isl_basic_set_print(morph->dom, out, 0, "", "", ISL_FORMAT_ISL); - isl_basic_set_print(morph->ran, out, 0, "", "", ISL_FORMAT_ISL); + isl_basic_set_dump(morph->dom); + isl_basic_set_dump(morph->ran); isl_mat_print_internal(morph->map, out, 4); isl_mat_print_internal(morph->inv, out, 4); } diff --git a/polly/lib/External/isl/isl_multi_apply_set.c b/polly/lib/External/isl/isl_multi_apply_set.c new file mode 100644 index 00000000000..df97878d109 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_apply_set.c @@ -0,0 +1,7 @@ +#define APPLY_DOMBASE set +#define APPLY_DOM isl_set + +#include <isl_multi_apply_templ.c> + +#undef APPLY_DOMBASE +#undef APPLY_DOM diff --git a/polly/lib/External/isl/isl_multi_apply_templ.c b/polly/lib/External/isl/isl_multi_apply_templ.c new file mode 100644 index 00000000000..d4f70b2f82e --- /dev/null +++ b/polly/lib/External/isl/isl_multi_apply_templ.c @@ -0,0 +1,81 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include <isl_multi_macro.h> + +/* Transform the elements of "multi" by applying "fn" to them + * with extra argument "set". + * + * The parameters of "multi" and "set" are assumed to have been aligned. + */ +__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)( + __isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set, + __isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set)) +{ + int i; + + if (!multi || !set) + goto error; + + if (multi->n == 0) { + FN(APPLY_DOM,free)(set); + return multi; + } + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + goto error; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = fn(multi->p[i], FN(APPLY_DOM,copy)(set)); + if (!multi->p[i]) + goto error; + } + + FN(APPLY_DOM,free)(set); + return multi; +error: + FN(APPLY_DOM,free)(set); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +/* Transform the elements of "multi" by applying "fn" to them + * with extra argument "set". + * + * Align the parameters if needed and call apply_set_aligned. + */ +static __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply),APPLY_DOMBASE)( + __isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set, + __isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set)) +{ + isl_ctx *ctx; + + if (!multi || !set) + goto error; + + if (isl_space_match(multi->space, isl_dim_param, + set->dim, isl_dim_param)) + return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi, + set, fn); + ctx = FN(MULTI(BASE),get_ctx)(multi); + if (!isl_space_has_named_params(multi->space) || + !isl_space_has_named_params(set->dim)) + isl_die(ctx, isl_error_invalid, + "unaligned unnamed parameters", goto error); + multi = FN(MULTI(BASE),align_params)(multi, + FN(APPLY_DOM,get_space)(set)); + set = FN(APPLY_DOM,align_params)(set, FN(MULTI(BASE),get_space)(multi)); + return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi, set, fn); +error: + FN(MULTI(BASE),free)(multi); + FN(APPLY_DOM,free)(set); + return NULL; +} diff --git a/polly/lib/External/isl/isl_multi_apply_union_set.c b/polly/lib/External/isl/isl_multi_apply_union_set.c new file mode 100644 index 00000000000..d7c298a3630 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_apply_union_set.c @@ -0,0 +1,7 @@ +#define APPLY_DOMBASE union_set +#define APPLY_DOM isl_union_set + +#include <isl_multi_apply_templ.c> + +#undef APPLY_DOMBASE +#undef APPLY_DOM diff --git a/polly/lib/External/isl/isl_multi_floor.c b/polly/lib/External/isl/isl_multi_floor.c new file mode 100644 index 00000000000..d869e65efcf --- /dev/null +++ b/polly/lib/External/isl/isl_multi_floor.c @@ -0,0 +1,29 @@ +/* + * Copyright 2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include <isl_multi_macro.h> + +/* Given f, return floor(f). + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),floor)(__isl_take MULTI(BASE) *multi) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,floor)(multi->p[i]); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} diff --git a/polly/lib/External/isl/isl_multi_gist.c b/polly/lib/External/isl/isl_multi_gist.c new file mode 100644 index 00000000000..d43525f8720 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_gist.c @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include <isl_multi_macro.h> + +/* Compute the gist of "multi" with respect to the domain constraints + * of "context". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi, + __isl_take DOM *context) +{ + return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, context, &FN(EL,gist)); +} + +/* Compute the gist of "multi" with respect to the parameter constraints + * of "context". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)( + __isl_take MULTI(BASE) *multi, __isl_take isl_set *context) +{ + return FN(MULTI(BASE),apply_set)(multi, context, &FN(EL,gist_params)); +} diff --git a/polly/lib/External/isl/isl_multi_intersect.c b/polly/lib/External/isl/isl_multi_intersect.c new file mode 100644 index 00000000000..b9341025888 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_intersect.c @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012-2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + */ + +#include <isl_multi_macro.h> + +/* Intersect the domain of "multi" with "domain". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)( + __isl_take MULTI(BASE) *multi, __isl_take DOM *domain) +{ + return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, domain, + &FN(EL,intersect_domain)); +} + +/* Intersect the parameter domain of "multi" with "domain". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)( + __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) +{ + return FN(MULTI(BASE),apply_set)(multi, domain, + &FN(EL,intersect_params)); +} diff --git a/polly/lib/External/isl/isl_multi_macro.h b/polly/lib/External/isl/isl_multi_macro.h new file mode 100644 index 00000000000..0200b4ddd44 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_macro.h @@ -0,0 +1,10 @@ +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef EL +#define EL CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) +#define xMULTI(BASE) isl_multi_ ## BASE +#define MULTI(BASE) xMULTI(BASE) +#undef DOM +#define DOM CAT(isl_,DOMBASE) diff --git a/polly/lib/External/isl/isl_multi_templ.c b/polly/lib/External/isl/isl_multi_templ.c index 69dc93c3007..c60aff0b309 100644 --- a/polly/lib/External/isl/isl_multi_templ.c +++ b/polly/lib/External/isl/isl_multi_templ.c @@ -12,14 +12,8 @@ #include <isl/set.h> #include <isl_reordering.h> -#define xCAT(A,B) A ## B -#define CAT(A,B) xCAT(A,B) -#undef EL -#define EL CAT(isl_,BASE) -#define xFN(TYPE,NAME) TYPE ## _ ## NAME -#define FN(TYPE,NAME) xFN(TYPE,NAME) -#define xMULTI(BASE) isl_multi_ ## BASE -#define MULTI(BASE) xMULTI(BASE) +#include <isl_multi_macro.h> + #define MULTI_NAME(BASE) "isl_multi_" #BASE #define xLIST(EL) EL ## _list #define LIST(EL) xLIST(EL) @@ -135,6 +129,7 @@ __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi) return NULL; } +#ifndef NO_DIMS /* Check whether "multi" has non-zero coefficients for any dimension * in the given range or if any of these dimensions appear * with non-zero coefficients in any of the integer divisions involved. @@ -201,6 +196,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi, return FN(MULTI(BASE),insert_dims)(multi, type, pos, n); } +#endif unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi, enum isl_dim_type type) @@ -544,154 +540,6 @@ error: return NULL; } -#if !defined(NO_GIST) || !defined(NO_INTERSECT_DOMAIN) -static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_set_and)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *set, - __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi, - __isl_take isl_set *set)) -{ - isl_ctx *ctx; - - if (!multi || !set) - goto error; - if (isl_space_match(multi->space, isl_dim_param, - set->dim, isl_dim_param)) - return fn(multi, set); - ctx = FN(MULTI(BASE),get_ctx)(multi); - if (!isl_space_has_named_params(multi->space) || - !isl_space_has_named_params(set->dim)) - isl_die(ctx, isl_error_invalid, - "unaligned unnamed parameters", goto error); - multi = FN(MULTI(BASE),align_params)(multi, isl_set_get_space(set)); - set = isl_set_align_params(set, FN(MULTI(BASE),get_space)(multi)); - return fn(multi, set); -error: - FN(MULTI(BASE),free)(multi); - isl_set_free(set); - return NULL; -} -#endif - -#ifndef NO_GIST -__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_aligned)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *context) -{ - int i; - - multi = FN(MULTI(BASE),cow)(multi); - if (!multi || !context) - goto error; - - for (i = 0; i < multi->n; ++i) { - multi->p[i] = FN(EL,gist)(multi->p[i], isl_set_copy(context)); - if (!multi->p[i]) - goto error; - } - - isl_set_free(context); - return multi; -error: - isl_set_free(context); - FN(MULTI(BASE),free)(multi); - return NULL; -} - -__isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi, - __isl_take isl_set *context) -{ - return FN(MULTI(BASE),align_params_multi_set_and)(multi, context, - &FN(MULTI(BASE),gist_aligned)); -} - -__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *context) -{ - isl_space *space = FN(MULTI(BASE),get_domain_space)(multi); - isl_set *dom_context = isl_set_universe(space); - dom_context = isl_set_intersect_params(dom_context, context); - return FN(MULTI(BASE),gist)(multi, dom_context); -} -#endif - -#ifndef NO_INTERSECT_DOMAIN -/* Transform the domain of "multi" by combining it with "domain" - * using "fn". - * - * The parameters of "multi" and "domain" are assumed to have been aligned. - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_aligned)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain, - __isl_give EL *(*fn)(EL *el, __isl_take isl_set *set2)) -{ - int i; - - if (!multi || !domain) - goto error; - - if (multi->n == 0) { - isl_set_free(domain); - return multi; - } - - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - goto error; - - for (i = 0; i < multi->n; ++i) { - multi->p[i] = fn(multi->p[i], isl_set_copy(domain)); - if (!multi->p[i]) - goto error; - } - - isl_set_free(domain); - return multi; -error: - isl_set_free(domain); - FN(MULTI(BASE),free)(multi); - return NULL; -} - -/* Intersect the domain of "multi" with "domain". - * - * The parameters of "multi" and "domain" are assumed to have been aligned. - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain_aligned)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) -{ - return FN(MULTI(BASE),intersect_aligned)(multi, domain, - &FN(EL,intersect_domain)); -} - -/* Intersect the domain of "multi" with "domain". - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) -{ - return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain, - &FN(MULTI(BASE),intersect_domain_aligned)); -} - -/* Intersect the parameter domain of "multi" with "domain". - * - * The parameters of "multi" and "domain" are assumed to have been aligned. - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params_aligned)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) -{ - return FN(MULTI(BASE),intersect_aligned)(multi, domain, - &FN(EL,intersect_params)); -} - -/* Intersect the parameter domain of "multi" with "domain". - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)( - __isl_take MULTI(BASE) *multi, __isl_take isl_set *domain) -{ - return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain, - &FN(MULTI(BASE),intersect_params_aligned)); -} -#endif - __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))( __isl_take isl_space *space, __isl_take LIST(EL) *list) { @@ -773,6 +621,7 @@ error: } #endif +#ifndef NO_ZERO /* Construct a multi expression in the given space with value zero in * each of the output dimensions. */ @@ -807,13 +656,29 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space) return multi; } +#endif #ifndef NO_FROM_BASE +/* Create a multiple expression with a single output/set dimension + * equal to "el". + * For most multiple expression types, the base type has a single + * output/set dimension and the space of the result is therefore + * the same as the space of the input. + * In the case of isl_multi_union_pw_aff, however, the base type + * lives in a parameter space and we therefore need to add + * a single set dimension. + */ __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el) { + isl_space *space; MULTI(BASE) *multi; - multi = FN(MULTI(BASE),alloc)(FN(EL,get_space)(el)); + space = FN(EL,get_space(el)); + if (isl_space_is_params(space)) { + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); + } + multi = FN(MULTI(BASE),alloc)(space); multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el); return multi; @@ -1002,6 +867,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)( return multi; } +#ifndef NO_PRODUCT /* Given two MULTI(BASE)s A -> B and C -> D, * construct a MULTI(BASE) [A -> C] -> [B -> D]. * @@ -1054,6 +920,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),product)( return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, &FN(MULTI(BASE),product_aligned)); } +#endif __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)( __isl_take MULTI(BASE) *multi) @@ -1129,6 +996,7 @@ error: return NULL; } +#ifndef NO_SPLICE /* Given two multi expressions, "multi1" * * [A1 A2] -> [B1 B2] @@ -1180,6 +1048,7 @@ error: FN(MULTI(BASE),free)(multi2); return NULL; } +#endif /* This function is currently only used from isl_aff.c */ @@ -1221,6 +1090,25 @@ error: return NULL; } +/* Subtract "multi2" from "multi1" and return the result. + * + * The parameters of "multi1" and "multi2" are assumed to have been aligned. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)( + __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub)); +} + +/* Subtract "multi2" from "multi1" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1, + __isl_take MULTI(BASE) *multi2) +{ + return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2, + &FN(MULTI(BASE),sub_aligned)); +} + /* Multiply the elements of "multi" by "v" and return the result. */ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi, @@ -1369,6 +1257,42 @@ error: return FN(MULTI(BASE),free)(multi); } +/* Compute the residues of the elements of "multi" modulo + * the corresponding element of "mv" and return the result. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)( + __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv) +{ + int i; + + if (!multi || !mv) + goto error; + + if (!isl_space_tuple_is_equal(multi->space, isl_dim_out, + mv->space, isl_dim_set)) + isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, + "spaces don't match", goto error); + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + isl_val *v; + + v = isl_multi_val_get_val(mv, i); + multi->p[i] = FN(EL,mod_val)(multi->p[i], v); + if (!multi->p[i]) + goto error; + } + + isl_multi_val_free(mv); + return multi; +error: + isl_multi_val_free(mv); + return FN(MULTI(BASE),free)(multi); +} + #ifndef NO_MOVE_DIMS /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi" * to dimensions of "dst_type" at "dst_pos". @@ -1496,3 +1420,24 @@ __isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi) return dom; } #endif + +#ifndef NO_NEG +/* Return the opposite of "multi". + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < multi->n; ++i) { + multi->p[i] = FN(EL,neg)(multi->p[i]); + if (!multi->p[i]) + return FN(MULTI(BASE),free)(multi); + } + + return multi; +} +#endif diff --git a/polly/lib/External/isl/isl_multi_templ.h b/polly/lib/External/isl/isl_multi_templ.h index 342d9a22315..8170892e62d 100644 --- a/polly/lib/External/isl/isl_multi_templ.h +++ b/polly/lib/External/isl/isl_multi_templ.h @@ -1,11 +1,6 @@ #include <isl/space.h> -#define xCAT(A,B) A ## B -#define CAT(A,B) xCAT(A,B) -#undef EL -#define EL CAT(isl_,BASE) -#define xMULTI(BASE) isl_multi_ ## BASE -#define MULTI(BASE) xMULTI(BASE) +#include <isl_multi_macro.h> struct MULTI(BASE) { int ref; diff --git a/polly/lib/External/isl/isl_obj.c b/polly/lib/External/isl/isl_obj.c index 5bc26ce6cc7..460c123e13c 100644 --- a/polly/lib/External/isl/isl_obj.c +++ b/polly/lib/External/isl/isl_obj.c @@ -1,6 +1,7 @@ /* * Copyright 2010 INRIA Saclay * Copyright 2014 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt * * Use of this software is governed by the MIT license * @@ -8,12 +9,15 @@ * 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 + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France */ #include <isl/aff.h> #include <isl/set.h> #include <isl/map.h> #include <isl/polynomial.h> +#include <isl/schedule.h> #include <isl/obj.h> static void *isl_obj_val_copy(void *v) @@ -333,3 +337,26 @@ struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable = { isl_obj_union_pw_qpf_print, isl_obj_union_pw_qpf_free }; + +static void *isl_obj_schedule_copy(void *v) +{ + return isl_schedule_copy((isl_schedule *) v); +} + +static void isl_obj_schedule_free(void *v) +{ + isl_schedule_free((isl_schedule *) v); +} + +static __isl_give isl_printer *isl_obj_schedule_print( + __isl_take isl_printer *p, void *v) +{ + return isl_printer_print_schedule(p, (isl_schedule *) v); +} + +struct isl_obj_vtable isl_obj_schedule_vtable = { + isl_obj_schedule_copy, + NULL, + isl_obj_schedule_print, + isl_obj_schedule_free +}; diff --git a/polly/lib/External/isl/isl_output.c b/polly/lib/External/isl/isl_output.c index b5d6c923384..58f8241e996 100644 --- a/polly/lib/External/isl/isl_output.c +++ b/polly/lib/External/isl/isl_output.c @@ -1008,24 +1008,6 @@ error: return NULL; } -void isl_basic_map_print(__isl_keep isl_basic_map *bmap, FILE *out, int indent, - const char *prefix, const char *suffix, unsigned output_format) -{ - isl_printer *printer; - - if (!bmap) - return; - - printer = isl_printer_to_file(bmap->ctx, out); - printer = isl_printer_set_indent(printer, indent); - printer = isl_printer_set_prefix(printer, prefix); - printer = isl_printer_set_suffix(printer, suffix); - printer = isl_printer_set_output_format(printer, output_format); - isl_printer_print_basic_map(printer, bmap); - - isl_printer_free(printer); -} - __isl_give isl_printer *isl_printer_print_basic_set(__isl_take isl_printer *p, __isl_keep isl_basic_set *bset) { @@ -1048,24 +1030,6 @@ error: return NULL; } -void isl_basic_set_print(struct isl_basic_set *bset, FILE *out, int indent, - const char *prefix, const char *suffix, unsigned output_format) -{ - isl_printer *printer; - - if (!bset) - return; - - printer = isl_printer_to_file(bset->ctx, out); - printer = isl_printer_set_indent(printer, indent); - printer = isl_printer_set_prefix(printer, prefix); - printer = isl_printer_set_suffix(printer, suffix); - printer = isl_printer_set_output_format(printer, output_format); - isl_printer_print_basic_set(printer, bset); - - isl_printer_free(printer); -} - __isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *p, __isl_keep isl_set *set) { @@ -1087,22 +1051,6 @@ error: return NULL; } -void isl_set_print(struct isl_set *set, FILE *out, int indent, - unsigned output_format) -{ - isl_printer *printer; - - if (!set) - return; - - printer = isl_printer_to_file(set->ctx, out); - printer = isl_printer_set_indent(printer, indent); - printer = isl_printer_set_output_format(printer, output_format); - printer = isl_printer_print_set(printer, set); - - isl_printer_free(printer); -} - __isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *p, __isl_keep isl_map *map) { @@ -1225,22 +1173,6 @@ error: return NULL; } -void isl_map_print(__isl_keep isl_map *map, FILE *out, int indent, - unsigned output_format) -{ - isl_printer *printer; - - if (!map) - return; - - printer = isl_printer_to_file(map->ctx, out); - printer = isl_printer_set_indent(printer, indent); - printer = isl_printer_set_output_format(printer, output_format); - printer = isl_printer_print_map(printer, map); - - isl_printer_free(printer); -} - static int upoly_rec_n_non_zero(__isl_keep struct isl_upoly_rec *rec) { int i; @@ -2161,11 +2093,31 @@ error: return NULL; } +/* Print the body of an isl_pw_aff, i.e., a semicolon delimited + * sequence of affine expressions, each followed by constraints. + */ +static __isl_give isl_printer *print_pw_aff_body( + __isl_take isl_printer *p, __isl_keep isl_pw_aff *pa) +{ + int i; + + if (!pa) + return isl_printer_free(p); + + for (i = 0; i < pa->n; ++i) { + if (i) + p = isl_printer_print_str(p, "; "); + p = print_aff(p, pa->p[i].aff); + p = print_disjuncts((isl_map *)pa->p[i].set, p, 0); + } + + return p; +} + static __isl_give isl_printer *print_pw_aff_isl(__isl_take isl_printer *p, __isl_keep isl_pw_aff *pwaff) { struct isl_print_space_data data = { 0 }; - int i; if (!pwaff) goto error; @@ -2175,12 +2127,7 @@ static __isl_give isl_printer *print_pw_aff_isl(__isl_take isl_printer *p, p = isl_printer_print_str(p, " -> "); } p = isl_printer_print_str(p, "{ "); - for (i = 0; i < pwaff->n; ++i) { - if (i) - p = isl_printer_print_str(p, "; "); - p = print_aff(p, pwaff->p[i].aff); - p = print_disjuncts((isl_map *)pwaff->p[i].set, p, 0); - } + p = print_pw_aff_body(p, pwaff); p = isl_printer_print_str(p, " }"); return p; error: @@ -2345,6 +2292,84 @@ error: return NULL; } +/* Print "pa" in a sequence of isl_pw_affs delimited by semicolons. + * Each isl_pw_aff itself is also printed as semicolon delimited + * sequence of pieces. + * If data->first = 1, then this is the first in the sequence. + * Update data->first to tell the next element that it is not the first. + */ +static int print_pw_aff_body_wrap(__isl_take isl_pw_aff *pa, + void *user) +{ + struct isl_union_print_data *data; + data = (struct isl_union_print_data *) user; + + if (!data->first) + data->p = isl_printer_print_str(data->p, "; "); + data->first = 0; + + data->p = print_pw_aff_body(data->p, pa); + isl_pw_aff_free(pa); + + return data->p ? 0 : -1; +} + +/* Print the body of an isl_union_pw_aff, i.e., a semicolon delimited + * sequence of affine expressions, each followed by constraints, + * with the sequence enclosed in braces. + */ +static __isl_give isl_printer *print_union_pw_aff_body( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + struct isl_union_print_data data = { p, 1 }; + + p = isl_printer_print_str(p, s_open_set[0]); + data.p = p; + if (isl_union_pw_aff_foreach_pw_aff(upa, + &print_pw_aff_body_wrap, &data) < 0) + data.p = isl_printer_free(p); + p = data.p; + p = isl_printer_print_str(p, s_close_set[0]); + + return p; +} + +/* Print the isl_union_pw_aff "upa" to "p" in isl format. + * + * The individual isl_pw_affs are delimited by a semicolon. + */ +static __isl_give isl_printer *print_union_pw_aff_isl( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + struct isl_print_space_data data = { 0 }; + isl_space *space; + + space = isl_union_pw_aff_get_space(upa); + if (isl_space_dim(space, isl_dim_param) > 0) { + p = print_tuple(space, p, isl_dim_param, &data); + p = isl_printer_print_str(p, s_to[0]); + } + isl_space_free(space); + p = print_union_pw_aff_body(p, upa); + return p; +} + +/* Print the isl_union_pw_aff "upa" to "p". + * + * We currently only support an isl format. + */ +__isl_give isl_printer *isl_printer_print_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) +{ + if (!p || !upa) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_union_pw_aff_isl(p, upa); + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "unsupported output format", return isl_printer_free(p)); +} + /* Print dimension "pos" of data->space to "p". * * data->user is assumed to be an isl_multi_aff. @@ -2696,3 +2721,64 @@ __isl_give isl_printer *isl_printer_print_multi_val( isl_die(p->ctx, isl_error_unsupported, "unsupported output format", return isl_printer_free(p)); } + +/* Print dimension "pos" of data->space to "p". + * + * data->user is assumed to be an isl_multi_union_pw_aff. + * + * The current dimension is necessarily a set dimension, so + * we print the corresponding isl_union_pw_aff, including + * the braces. + */ +static __isl_give isl_printer *print_union_pw_aff_dim(__isl_take isl_printer *p, + struct isl_print_space_data *data, unsigned pos) +{ + isl_multi_union_pw_aff *mupa = data->user; + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, pos); + p = print_union_pw_aff_body(p, upa); + isl_union_pw_aff_free(upa); + + return p; +} + +/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. + */ +static __isl_give isl_printer *print_multi_union_pw_aff_isl( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) +{ + struct isl_print_space_data data = { 0 }; + isl_space *space; + + space = isl_multi_union_pw_aff_get_space(mupa); + if (isl_space_dim(space, isl_dim_param) > 0) { + struct isl_print_space_data space_data = { 0 }; + p = print_tuple(space, p, isl_dim_param, &space_data); + p = isl_printer_print_str(p, s_to[0]); + } + + data.print_dim = &print_union_pw_aff_dim; + data.user = mupa; + + p = print_space(space, p, 0, &data); + isl_space_free(space); + + return p; +} + +/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. + * + * We currently only support an isl format. + */ +__isl_give isl_printer *isl_printer_print_multi_union_pw_aff( + __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) +{ + if (!p || !mupa) + return isl_printer_free(p); + + if (p->output_format == ISL_FORMAT_ISL) + return print_multi_union_pw_aff_isl(p, mupa); + isl_die(isl_printer_get_ctx(p), isl_error_unsupported, + "unsupported output format", return isl_printer_free(p)); +} diff --git a/polly/lib/External/isl/isl_polynomial.c b/polly/lib/External/isl/isl_polynomial.c index 6b73bb397d0..dd2dbf66834 100644 --- a/polly/lib/External/isl/isl_polynomial.c +++ b/polly/lib/External/isl/isl_polynomial.c @@ -2808,7 +2808,6 @@ __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial( #define PART isl_pw_qpolynomial #undef PARTS #define PARTS pw_qpolynomial -#define ALIGN_DOMAIN #include <isl_union_templ.c> @@ -4060,37 +4059,12 @@ error: return NULL; } -static int neg_entry(void **entry, void *user) -{ - isl_pw_qpolynomial **pwqp = (isl_pw_qpolynomial **)entry; - - *pwqp = isl_pw_qpolynomial_neg(*pwqp); - - return *pwqp ? 0 : -1; -} - -__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_neg( - __isl_take isl_union_pw_qpolynomial *upwqp) -{ - upwqp = isl_union_pw_qpolynomial_cow(upwqp); - if (!upwqp) - return NULL; - - if (isl_hash_table_foreach(upwqp->space->ctx, &upwqp->table, - &neg_entry, NULL) < 0) - goto error; - - return upwqp; -error: - isl_union_pw_qpolynomial_free(upwqp); - return NULL; -} - __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) { - return match_bin_op(upwqp1, upwqp2, &isl_pw_qpolynomial_mul); + return isl_union_pw_qpolynomial_match_bin_op(upwqp1, upwqp2, + &isl_pw_qpolynomial_mul); } /* Reorder the columns of the given div definitions according to the diff --git a/polly/lib/External/isl/isl_printer.c b/polly/lib/External/isl/isl_printer.c index d5407fce6ad..a0b3823ec0d 100644 --- a/polly/lib/External/isl/isl_printer.c +++ b/polly/lib/External/isl/isl_printer.c @@ -118,6 +118,7 @@ static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p) static __isl_give isl_printer *str_flush(__isl_take isl_printer *p) { p->buf_n = 0; + p->buf[p->buf_n] = '\0'; return p; } @@ -212,7 +213,7 @@ static struct isl_printer_ops str_ops = { __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file) { - struct isl_printer *p = isl_alloc_type(ctx, struct isl_printer); + struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer); if (!p) return NULL; p->ctx = ctx; @@ -228,6 +229,7 @@ __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file) p->prefix = NULL; p->suffix = NULL; p->width = 0; + p->yaml_style = ISL_YAML_STYLE_FLOW; return p; } @@ -253,6 +255,7 @@ __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx) p->prefix = NULL; p->suffix = NULL; p->width = 0; + p->yaml_style = ISL_YAML_STYLE_FLOW; return p; error: @@ -268,6 +271,7 @@ __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p) free(p->indent_prefix); free(p->prefix); free(p->suffix); + free(p->yaml_state); isl_ctx_deref(p->ctx); free(p); @@ -380,6 +384,161 @@ int isl_printer_get_output_format(__isl_keep isl_printer *p) return p->output_format; } +/* Set the YAML style of "p" to "yaml_style" and return the updated printer. + */ +__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p, + int yaml_style) +{ + if (!p) + return NULL; + + p->yaml_style = yaml_style; + + return p; +} + +/* Return the YAML style of "p" or -1 on error. + */ +int isl_printer_get_yaml_style(__isl_keep isl_printer *p) +{ + if (!p) + return -1; + return p->yaml_style; +} + +/* Push "state" onto the stack of currently active YAML elements and + * return the updated printer. + */ +static __isl_give isl_printer *push_state(__isl_take isl_printer *p, + enum isl_yaml_state state) +{ + if (!p) + return NULL; + + if (p->yaml_size < p->yaml_depth + 1) { + enum isl_yaml_state *state; + state = isl_realloc_array(p->ctx, p->yaml_state, + enum isl_yaml_state, p->yaml_depth + 1); + if (!state) + return isl_printer_free(p); + p->yaml_state = state; + p->yaml_size = p->yaml_depth + 1; + } + + p->yaml_state[p->yaml_depth] = state; + p->yaml_depth++; + + return p; +} + +/* Remove the innermost active YAML element from the stack and + * return the updated printer. + */ +static __isl_give isl_printer *pop_state(__isl_take isl_printer *p) +{ + if (!p) + return NULL; + p->yaml_depth--; + return p; +} + +/* Set the state of the innermost active YAML element to "state" and + * return the updated printer. + */ +static __isl_give isl_printer *update_state(__isl_take isl_printer *p, + enum isl_yaml_state state) +{ + if (!p) + return NULL; + if (p->yaml_depth < 1) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "not in YAML construct", return isl_printer_free(p)); + + p->yaml_state[p->yaml_depth - 1] = state; + + return p; +} + +/* Return the state of the innermost active YAML element. + * Return isl_yaml_none if we are not inside any YAML element. + */ +static enum isl_yaml_state current_state(__isl_keep isl_printer *p) +{ + if (!p) + return isl_yaml_none; + if (p->yaml_depth < 1) + return isl_yaml_none; + return p->yaml_state[p->yaml_depth - 1]; +} + +/* If we are printing a YAML document and we are at the start of an element, + * print whatever is needed before we can print the actual element and + * keep track of the fact that we are now printing the element. + * If "eol" is set, then whatever we print is going to be the last + * thing that gets printed on this line. + * + * If we are about the print the first key of a mapping, then nothing + * extra needs to be printed. For any other key, however, we need + * to either move to the next line (in block format) or print a comma + * (in flow format). + * Before printing a value in a mapping, we need to print a colon. + * + * For sequences, in flow format, we only need to print a comma + * for each element except the first. + * In block format, before the first element in the sequence, + * we move to a new line, print a dash and increase the indentation. + * Before any other element, we print a dash on a new line, + * temporarily moving the indentation back. + */ +static __isl_give isl_printer *enter_state(__isl_take isl_printer *p, + int eol) +{ + enum isl_yaml_state state; + + if (!p) + return NULL; + + state = current_state(p); + if (state == isl_yaml_mapping_val_start) { + if (eol) + p = p->ops->print_str(p, ":"); + else + p = p->ops->print_str(p, ": "); + p = update_state(p, isl_yaml_mapping_val); + } else if (state == isl_yaml_mapping_first_key_start) { + p = update_state(p, isl_yaml_mapping_key); + } else if (state == isl_yaml_mapping_key_start) { + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, ", "); + else { + p = p->ops->end_line(p); + p = p->ops->start_line(p); + } + p = update_state(p, isl_yaml_mapping_key); + } else if (state == isl_yaml_sequence_first_start) { + if (p->yaml_style != ISL_YAML_STYLE_FLOW) { + p = p->ops->end_line(p); + p = p->ops->start_line(p); + p = p->ops->print_str(p, "- "); + p = isl_printer_indent(p, 2); + } + p = update_state(p, isl_yaml_sequence); + } else if (state == isl_yaml_sequence_start) { + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, ", "); + else { + p = p->ops->end_line(p); + p = isl_printer_indent(p, -2); + p = p->ops->start_line(p); + p = p->ops->print_str(p, "- "); + p = isl_printer_indent(p, 2); + } + p = update_state(p, isl_yaml_sequence); + } + + return p; +} + __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p, const char *s) { @@ -387,13 +546,16 @@ __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p, return NULL; if (!s) return isl_printer_free(p); - + p = enter_state(p, 0); + if (!p) + return NULL; return p->ops->print_str(p, s); } __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p, double d) { + p = enter_state(p, 0); if (!p) return NULL; @@ -402,6 +564,7 @@ __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p, __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i) { + p = enter_state(p, 0); if (!p) return NULL; @@ -411,6 +574,7 @@ __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i) __isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p, isl_int i) { + p = enter_state(p, 0); if (!p) return NULL; @@ -447,3 +611,154 @@ __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p) return p->ops->flush(p); } + +/* Start a YAML mapping and push a new state to reflect that we + * are about to print the first key in a mapping. + * + * In flow style, print the opening brace. + * In block style, move to the next line with an increased indentation, + * except if this is the outer mapping or if we are inside a sequence + * (in which case we have already increased the indentation and we want + * to print the first key on the same line as the dash). + */ +__isl_give isl_printer *isl_printer_yaml_start_mapping( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK); + if (!p) + return NULL; + state = current_state(p); + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, "{ "); + else if (state != isl_yaml_none && state != isl_yaml_sequence) { + p = p->ops->end_line(p); + p = isl_printer_indent(p, 2); + p = p->ops->start_line(p); + } + p = push_state(p, isl_yaml_mapping_first_key_start); + return p; +} + +/* Finish a YAML mapping and pop it from the state stack. + * + * In flow style, print the closing brace. + * + * In block style, first check if we are still in the + * isl_yaml_mapping_first_key_start state. If so, we have not printed + * anything yet, so print "{}" to indicate an empty mapping. + * If we increased the indentation in isl_printer_yaml_start_mapping, + * then decrease it again. + * If this is the outer mapping then print a newline. + */ +__isl_give isl_printer *isl_printer_yaml_end_mapping( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + state = current_state(p); + p = pop_state(p); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + return p->ops->print_str(p, " }"); + if (state == isl_yaml_mapping_first_key_start) + p = p->ops->print_str(p, "{}"); + if (!p) + return NULL; + state = current_state(p); + if (state != isl_yaml_none && state != isl_yaml_sequence) + p = isl_printer_indent(p, -2); + if (state == isl_yaml_none) + p = p->ops->end_line(p); + return p; +} + +/* Start a YAML sequence and push a new state to reflect that we + * are about to print the first element in a sequence. + * + * In flow style, print the opening bracket. + */ +__isl_give isl_printer *isl_printer_yaml_start_sequence( + __isl_take isl_printer *p) +{ + p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK); + p = push_state(p, isl_yaml_sequence_first_start); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + p = p->ops->print_str(p, "[ "); + return p; +} + +/* Finish a YAML sequence and pop it from the state stack. + * + * In flow style, print the closing bracket. + * + * In block style, check if we are still in the + * isl_yaml_sequence_first_start state. If so, we have not printed + * anything yet, so print "[]" or " []" to indicate an empty sequence. + * We print the extra space when we instructed enter_state not + * to print a space at the end of the line. + * Otherwise, undo the increase in indentation performed by + * enter_state when moving away from the isl_yaml_sequence_first_start + * state. + * If this is the outer sequence then print a newline. + */ +__isl_give isl_printer *isl_printer_yaml_end_sequence( + __isl_take isl_printer *p) +{ + enum isl_yaml_state state, up; + + state = current_state(p); + p = pop_state(p); + if (!p) + return NULL; + if (p->yaml_style == ISL_YAML_STYLE_FLOW) + return p->ops->print_str(p, " ]"); + up = current_state(p); + if (state == isl_yaml_sequence_first_start) { + if (up == isl_yaml_mapping_val) + p = p->ops->print_str(p, " []"); + else + p = p->ops->print_str(p, "[]"); + } else { + p = isl_printer_indent(p, -2); + } + if (!p) + return NULL; + state = current_state(p); + if (state == isl_yaml_none) + p = p->ops->end_line(p); + return p; +} + +/* Mark the fact that the current element is finished and that + * the next output belongs to the next element. + * In particular, if we are printing a key, then prepare for + * printing the subsequent value. If we are printing a value, + * prepare for printing the next key. If we are printing an + * element in a sequence, prepare for printing the next element. + */ +__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p) +{ + enum isl_yaml_state state; + + if (!p) + return NULL; + if (p->yaml_depth < 1) + isl_die(isl_printer_get_ctx(p), isl_error_invalid, + "not in YAML construct", return isl_printer_free(p)); + + state = current_state(p); + if (state == isl_yaml_mapping_key) + state = isl_yaml_mapping_val_start; + else if (state == isl_yaml_mapping_val) + state = isl_yaml_mapping_key_start; + else if (state == isl_yaml_sequence) + state = isl_yaml_sequence_start; + p = update_state(p, state); + + return p; +} diff --git a/polly/lib/External/isl/isl_printer_private.h b/polly/lib/External/isl/isl_printer_private.h index c977214ce49..29f3db57d36 100644 --- a/polly/lib/External/isl/isl_printer_private.h +++ b/polly/lib/External/isl/isl_printer_private.h @@ -1,7 +1,18 @@ #include <isl/printer.h> +#include <isl_yaml.h> struct isl_printer_ops; +/* A printer to a file or a string. + * + * yaml_style is the YAML style in which the next elements should + * be printed and may be either ISL_YAML_STYLE_BLOCK or ISL_YAML_STYLE_FLOW, + * with ISL_YAML_STYLE_FLOW being the default. + * yaml_state keeps track of the currently active YAML elements. + * yaml_size is the size of this arrays, while yaml_depth + * is the number of elements currently in use. + * yaml_state may be NULL if no YAML printing is being performed. + */ struct isl_printer { struct isl_ctx *ctx; struct isl_printer_ops *ops; @@ -15,4 +26,9 @@ struct isl_printer { char *prefix; char *suffix; int width; + + int yaml_style; + int yaml_depth; + int yaml_size; + enum isl_yaml_state *yaml_state; }; diff --git a/polly/lib/External/isl/isl_pw_templ.c b/polly/lib/External/isl/isl_pw_templ.c index 594f6b73cc6..f9e2a5fdcdf 100644 --- a/polly/lib/External/isl/isl_pw_templ.c +++ b/polly/lib/External/isl/isl_pw_templ.c @@ -644,7 +644,9 @@ __isl_give PW *FN(PW,neg)(__isl_take PW *pw) return pw; } +#endif +#ifndef NO_SUB __isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2) { return FN(PW,add)(pw1, FN(PW,neg)(pw2)); @@ -802,9 +804,9 @@ __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type, /* Restrict the domain of "pw" by combining each cell * with "set" through a call to "fn", where "fn" may be - * isl_set_intersect or isl_set_intersect_params. + * isl_set_intersect, isl_set_intersect_params or isl_set_subtract. */ -static __isl_give PW *FN(PW,intersect_aligned)(__isl_take PW *pw, +static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw, __isl_take isl_set *set, __isl_give isl_set *(*fn)(__isl_take isl_set *set1, __isl_take isl_set *set2)) @@ -840,7 +842,7 @@ error: static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw, __isl_take isl_set *set) { - return FN(PW,intersect_aligned)(pw, set, &isl_set_intersect); + return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect); } __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, @@ -853,7 +855,8 @@ __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw, __isl_take isl_set *set) { - return FN(PW,intersect_aligned)(pw, set, &isl_set_intersect_params); + return FN(PW,restrict_domain_aligned)(pw, set, + &isl_set_intersect_params); } /* Intersect the domain of "pw" with the parameter domain "context". @@ -865,6 +868,24 @@ __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw, &FN(PW,intersect_params_aligned)); } +/* Subtract "domain' from the domain of "pw", assuming their + * parameters have been aligned. + */ +static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw, + __isl_take isl_set *domain) +{ + return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract); +} + +/* Subtract "domain' from the domain of "pw". + */ +__isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw, + __isl_take isl_set *domain) +{ + return FN(PW,align_params_pw_set_and)(pw, domain, + &FN(PW,subtract_domain_aligned)); +} + /* Compute the gist of "pw" with respect to the domain constraints * of "context" for the case where the domain of the last element * of "pw" is equal to "context". @@ -1514,6 +1535,19 @@ error: } #endif +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "pw". + */ +__isl_give PW *FN(PW,reset_user)(__isl_take PW *pw) +{ + isl_space *space; + + space = FN(PW,get_space)(pw); + space = isl_space_reset_user(space); + + return FN(PW,reset_space)(pw, space); +} + int FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2) { if (!pw1 || !pw2) diff --git a/polly/lib/External/isl/isl_schedule.c b/polly/lib/External/isl/isl_schedule.c index 1ad98d5df4d..85a8e7c4a0b 100644 --- a/polly/lib/External/isl/isl_schedule.c +++ b/polly/lib/External/isl/isl_schedule.c @@ -14,34 +14,219 @@ #include <isl_aff_private.h> #include <isl/map.h> #include <isl/set.h> +#include <isl/schedule.h> +#include <isl/schedule_node.h> #include <isl_sort.h> #include <isl_schedule_private.h> +#include <isl_schedule_tree.h> +#include <isl_schedule_node_private.h> #include <isl_band_private.h> +/* Return a schedule encapsulating the given schedule tree. + * + * We currently only allow schedule trees with a domain as root. + * + * The leaf field is initialized as a leaf node so that it can be + * used to represent leaves in the constructed schedule. + * The reference count is set to -1 since the isl_schedule_tree + * should never be freed. It is up to the (internal) users of + * these leaves to ensure that they are only used while the schedule + * is still alive. + */ +__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx, + __isl_take isl_schedule_tree *tree) +{ + isl_schedule *schedule; + + if (!tree) + return NULL; + if (isl_schedule_tree_get_type(tree) != isl_schedule_node_domain) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported, + "root of schedule tree should be a domain", + goto error); + + schedule = isl_calloc_type(ctx, isl_schedule); + if (!schedule) + goto error; + + schedule->leaf.ctx = ctx; + isl_ctx_ref(ctx); + schedule->ref = 1; + schedule->root = tree; + schedule->leaf.ref = -1; + schedule->leaf.type = isl_schedule_node_leaf; + + return schedule; +error: + isl_schedule_tree_free(tree); + return NULL; +} + +/* Return a pointer to a schedule with as single node + * a domain node with the given domain. + */ +__isl_give isl_schedule *isl_schedule_from_domain( + __isl_take isl_union_set *domain) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + ctx = isl_union_set_get_ctx(domain); + tree = isl_schedule_tree_from_domain(domain); + return isl_schedule_from_schedule_tree(ctx, tree); +} + +/* Return a pointer to a schedule with as single node + * a domain node with an empty domain. + */ +__isl_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space) +{ + return isl_schedule_from_domain(isl_union_set_empty(space)); +} + +/* Return a new reference to "sched". + */ +__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched) +{ + if (!sched) + return NULL; + + sched->ref++; + return sched; +} + +/* Return an isl_schedule that is equal to "schedule" and that has only + * a single reference. + * + * We only need and support this function when the schedule is represented + * as a schedule tree. + */ +__isl_give isl_schedule *isl_schedule_cow(__isl_take isl_schedule *schedule) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!schedule) + return NULL; + if (schedule->ref == 1) + return schedule; + + ctx = isl_schedule_get_ctx(schedule); + if (!schedule->root) + isl_die(ctx, isl_error_internal, + "only for schedule tree based schedules", + return isl_schedule_free(schedule)); + schedule->ref--; + tree = isl_schedule_tree_copy(schedule->root); + return isl_schedule_from_schedule_tree(ctx, tree); +} + __isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched) { - int i; if (!sched) return NULL; if (--sched->ref > 0) return NULL; - for (i = 0; i < sched->n; ++i) { - isl_multi_aff_free(sched->node[i].sched); - free(sched->node[i].band_end); - free(sched->node[i].band_id); - free(sched->node[i].coincident); - } - isl_space_free(sched->dim); isl_band_list_free(sched->band_forest); + isl_schedule_tree_free(sched->root); + isl_ctx_deref(sched->leaf.ctx); free(sched); return NULL; } +/* Replace the root of "schedule" by "tree". + */ +__isl_give isl_schedule *isl_schedule_set_root( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree) +{ + if (!schedule || !tree) + goto error; + if (schedule->root == tree) { + isl_schedule_tree_free(tree); + return schedule; + } + + schedule = isl_schedule_cow(schedule); + if (!schedule) + goto error; + isl_schedule_tree_free(schedule->root); + schedule->root = tree; + + return schedule; +error: + isl_schedule_free(schedule); + isl_schedule_tree_free(tree); + return NULL; +} + isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule) { - return schedule ? isl_space_get_ctx(schedule->dim) : NULL; + return schedule ? schedule->leaf.ctx : NULL; +} + +/* Return a pointer to the leaf of "schedule". + * + * Even though these leaves are not reference counted, we still + * indicate that this function does not return a copy. + */ +__isl_keep isl_schedule_tree *isl_schedule_peek_leaf( + __isl_keep isl_schedule *schedule) +{ + return schedule ? &schedule->leaf : NULL; +} + +/* Return the (parameter) space of the schedule, i.e., the space + * of the root domain. + */ +__isl_give isl_space *isl_schedule_get_space( + __isl_keep isl_schedule *schedule) +{ + enum isl_schedule_node_type type; + isl_space *space; + isl_union_set *domain; + + if (!schedule) + return NULL; + if (!schedule->root) + isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid, + "schedule tree representation not available", + return NULL); + type = isl_schedule_tree_get_type(schedule->root); + if (type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(schedule), isl_error_internal, + "root node not a domain node", return NULL); + + domain = isl_schedule_tree_domain_get_domain(schedule->root); + space = isl_union_set_get_space(domain); + isl_union_set_free(domain); + + return space; +} + +/* Return a pointer to the root of "schedule". + */ +__isl_give isl_schedule_node *isl_schedule_get_root( + __isl_keep isl_schedule *schedule) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + isl_schedule_tree_list *ancestors; + + if (!schedule) + return NULL; + + if (!schedule->root) + isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid, + "schedule tree representation not available", + return NULL); + + ctx = isl_schedule_get_ctx(schedule); + tree = isl_schedule_tree_copy(schedule->root); + schedule = isl_schedule_copy(schedule); + ancestors = isl_schedule_tree_list_alloc(ctx, 0); + return isl_schedule_node_alloc(schedule, tree, ancestors, NULL); } /* Set max_out to the maximal number of output dimensions over @@ -114,473 +299,382 @@ static __isl_give isl_union_map *pad_schedule_map( return data.res; } -/* Return an isl_union_map of the schedule. If we have already constructed - * a band forest, then this band forest may have been modified so we need - * to extract the isl_union_map from the forest rather than from - * the originally computed schedule. This reconstructed schedule map +/* Return the domain of the root domain node of "schedule". + */ +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule) +{ + if (!schedule) + return NULL; + if (!schedule->root) + isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid, + "schedule tree representation not available", + return NULL); + return isl_schedule_tree_domain_get_domain(schedule->root); +} + +/* Traverse all nodes of "sched" in depth first preorder. + * + * If "fn" returns -1 on any of the nodes, then the traversal is aborted. + * If "fn" returns 0 on any of the nodes, then the subtree rooted + * at that node is skipped. + * + * Return 0 on success and -1 on failure. + */ +int isl_schedule_foreach_schedule_node(__isl_keep isl_schedule *sched, + int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user) +{ + isl_schedule_node *node; + int r; + + if (!sched) + return -1; + + node = isl_schedule_get_root(sched); + r = isl_schedule_node_foreach_descendant(node, fn, user); + isl_schedule_node_free(node); + + return r; +} + +/* Traverse the node of "sched" in depth first postorder, + * allowing the user to modify the visited node. + * The traversal continues from the node returned by the callback function. + * It is the responsibility of the user to ensure that this does not + * lead to an infinite loop. It is safest to always return a pointer + * to the same position (same ancestors and child positions) as the input node. + */ +__isl_give isl_schedule *isl_schedule_map_schedule_node( + __isl_take isl_schedule *schedule, + __isl_give isl_schedule_node *(*fn)( + __isl_take isl_schedule_node *node, void *user), void *user) +{ + isl_schedule_node *node; + + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + node = isl_schedule_node_map_descendant(node, fn, user); + schedule = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); + + return schedule; +} + +/* Return an isl_union_map representation of the schedule. + * If we still have access to the schedule tree, then we return + * an isl_union_map corresponding to the subtree schedule of the child + * of the root domain node. That is, we do not intersect the domain + * of the returned isl_union_map with the domain constraints. + * Otherwise, we must have removed it because we created a band forest. + * If so, we extract the isl_union_map from the forest. + * This reconstructed schedule map * then needs to be padded with zeros to unify the schedule space * since the result of isl_band_list_get_suffix_schedule may not have * a unified schedule space. */ __isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched) { - int i; + enum isl_schedule_node_type type; + isl_schedule_node *node; isl_union_map *umap; if (!sched) return NULL; - if (sched->band_forest) { - umap = isl_band_list_get_suffix_schedule(sched->band_forest); - return pad_schedule_map(umap); - } + if (sched->root) { + type = isl_schedule_tree_get_type(sched->root); + if (type != isl_schedule_node_domain) + isl_die(isl_schedule_get_ctx(sched), isl_error_internal, + "root node not a domain node", return NULL); - umap = isl_union_map_empty(isl_space_copy(sched->dim)); - for (i = 0; i < sched->n; ++i) { - isl_multi_aff *ma; + node = isl_schedule_get_root(sched); + node = isl_schedule_node_child(node, 0); + umap = isl_schedule_node_get_subtree_schedule_union_map(node); + isl_schedule_node_free(node); - ma = isl_multi_aff_copy(sched->node[i].sched); - umap = isl_union_map_add_map(umap, isl_map_from_multi_aff(ma)); + return umap; } - return umap; + umap = isl_band_list_get_suffix_schedule(sched->band_forest); + return pad_schedule_map(umap); } static __isl_give isl_band_list *construct_band_list( - __isl_keep isl_schedule *schedule, __isl_keep isl_band *parent, - int band_nr, int *parent_active, int n_active); - -/* Construct an isl_band structure for the band in the given schedule - * with sequence number band_nr for the n_active nodes marked by active. - * If the nodes don't have a band with the given sequence number, - * then a band without members is created. + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain, + __isl_keep isl_band *parent); + +/* Construct an isl_band structure from the given schedule tree node, + * which may be either a band node or a leaf node. + * In the latter case, construct a zero-dimensional band. + * "domain" is the universe set of the domain elements that reach "node". + * "parent" is the parent isl_band of the isl_band constructed + * by this function. * - * 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. + * In case of a band node, we copy the properties (except tilability, + * which is implicit in an isl_band) to the isl_band. + * We assume that the band node is not zero-dimensional. + * If the child of the band node is not a leaf node, + * then we extract the children of the isl_band from this child. */ -static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule, - __isl_keep isl_band *parent, - int band_nr, int *active, int n_active) +static __isl_give isl_band *construct_band(__isl_take isl_schedule_node *node, + __isl_take isl_union_set *domain, __isl_keep isl_band *parent) { - int i, j; - isl_ctx *ctx = isl_schedule_get_ctx(schedule); - isl_band *band; - unsigned start, end; + int i; + isl_ctx *ctx; + isl_band *band = NULL; + isl_multi_union_pw_aff *mupa; + + if (!node || !domain) + goto error; + ctx = isl_schedule_node_get_ctx(node); band = isl_band_alloc(ctx); if (!band) - return NULL; + goto error; - band->schedule = schedule; + band->schedule = node->schedule; band->parent = parent; - for (i = 0; i < schedule->n; ++i) - if (active[i]) - break; - - if (i >= schedule->n) - isl_die(ctx, isl_error_internal, - "band without active statements", goto error); - - start = band_nr ? schedule->node[i].band_end[band_nr - 1] : 0; - end = band_nr < schedule->node[i].n_band ? - schedule->node[i].band_end[band_nr] : start; - band->n = end - start; + if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) { + band->n = 0; + band->pma = isl_union_pw_multi_aff_from_domain(domain); + isl_schedule_node_free(node); + return band; + } + band->n = isl_schedule_node_band_n_member(node); + if (band->n == 0) + isl_die(ctx, isl_error_unsupported, + "zero-dimensional band nodes not supported", + goto error); band->coincident = isl_alloc_array(ctx, int, band->n); if (band->n && !band->coincident) goto error; - - for (j = 0; j < band->n; ++j) - band->coincident[j] = schedule->node[i].coincident[start + j]; - - band->pma = isl_union_pw_multi_aff_empty(isl_space_copy(schedule->dim)); - for (i = 0; i < schedule->n; ++i) { - isl_multi_aff *ma; - isl_pw_multi_aff *pma; - unsigned n_out; - - if (!active[i]) - continue; - - ma = isl_multi_aff_copy(schedule->node[i].sched); - n_out = isl_multi_aff_dim(ma, isl_dim_out); - ma = isl_multi_aff_drop_dims(ma, isl_dim_out, end, n_out - end); - ma = isl_multi_aff_drop_dims(ma, isl_dim_out, 0, start); - pma = isl_pw_multi_aff_from_multi_aff(ma); - band->pma = isl_union_pw_multi_aff_add_pw_multi_aff(band->pma, - pma); - } + for (i = 0; i < band->n; ++i) + band->coincident[i] = + isl_schedule_node_band_member_get_coincident(node, i); + mupa = isl_schedule_node_band_get_partial_schedule(node); + band->pma = isl_union_pw_multi_aff_from_multi_union_pw_aff(mupa); 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; + node = isl_schedule_node_child(node, 0); + if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) { + isl_schedule_node_free(node); + isl_union_set_free(domain); + return band; } + band->children = construct_band_list(node, domain, band); + if (!band->children) + return isl_band_free(band); + return band; error: + isl_union_set_free(domain); + isl_schedule_node_free(node); 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. +/* Construct a list of isl_band structures from the children of "node". + * "node" itself is a sequence or set node, so that each of the child nodes + * is a filter node and the list returned by node_construct_band_list + * consists of a single element. + * "domain" is the universe set of the domain elements that reach "node". + * "parent" is the parent isl_band of the isl_band structures constructed + * by this function. */ -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) +static __isl_give isl_band_list *construct_band_list_from_children( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain, + __isl_keep isl_band *parent) { - int r; - - r = isl_pw_multi_aff_foreach_piece(pma, &multi_aff_extract_int, user); - isl_pw_multi_aff_free(pma); + int i, n; + isl_ctx *ctx; + isl_band_list *list; - return r; -} + n = isl_schedule_node_n_children(node); -/* 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; + ctx = isl_schedule_node_get_ctx(node); + list = isl_band_list_alloc(ctx, 0); + for (i = 0; i < n; ++i) { + isl_schedule_node *child; + isl_band_list *list_i; - 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; + child = isl_schedule_node_get_child(node, i); + list_i = construct_band_list(child, isl_union_set_copy(domain), + parent); + list = isl_band_list_concat(list, list_i); } - return !data->first && data->equal; + isl_union_set_free(domain); + isl_schedule_node_free(node); + + return list; } -/* 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. +/* Construct an isl_band structure from the given sequence node + * (or set node that is treated as a sequence node). + * A single-dimensional band is created with as schedule for each of + * filters of the children, the corresponding child position. + * "domain" is the universe set of the domain elements that reach "node". + * "parent" is the parent isl_band of the isl_band constructed + * by this function. */ -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) +static __isl_give isl_band_list *construct_band_list_sequence( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain, + __isl_keep isl_band *parent) { + int i, n; + isl_ctx *ctx; + isl_band *band = NULL; + isl_space *space; isl_union_pw_multi_aff *upma; - isl_union_set *domain; - int r; - if (data->r < 0) - return 0; + if (!node || !domain) + goto error; - 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; - } + ctx = isl_schedule_node_get_ctx(node); + band = isl_band_alloc(ctx); + if (!band) + goto error; - 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); -} + band->schedule = node->schedule; + band->parent = parent; + band->n = 1; + band->coincident = isl_calloc_array(ctx, int, band->n); + if (!band->coincident) + goto error; -/* 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; + n = isl_schedule_node_n_children(node); + space = isl_union_set_get_space(domain); + upma = isl_union_pw_multi_aff_empty(isl_space_copy(space)); - return cmp_band_in_ancestor(b1, b2, data, b1->parent); -} + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, 1); -/* 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_schedule_constraints_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; + for (i = 0; i < n; ++i) { + isl_schedule_node *child; + isl_union_set *filter; + isl_val *v; + isl_val_list *vl; + isl_multi_val *mv; + isl_union_pw_multi_aff *upma_i; + + child = isl_schedule_node_get_child(node, i); + filter = isl_schedule_node_filter_get_filter(child); + isl_schedule_node_free(child); + filter = isl_union_set_intersect(filter, + isl_union_set_copy(domain)); + v = isl_val_int_from_si(ctx, i); + vl = isl_val_list_from_val(v); + mv = isl_multi_val_from_val_list(isl_space_copy(space), vl); + upma_i = isl_union_pw_multi_aff_multi_val_on_domain(filter, mv); + upma = isl_union_pw_multi_aff_union_add(upma, upma_i); + } - 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); + isl_space_free(space); - return list; + band->pma = upma; + if (!band->pma) + goto error; + + band->children = construct_band_list_from_children(node, domain, band); + if (!band->children) + band = isl_band_free(band); + return isl_band_list_from_band(band); +error: + isl_union_set_free(domain); + isl_schedule_node_free(node); + isl_band_free(band); + return NULL; } -/* 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. +/* Construct a list of isl_band structures from "node" depending + * on the type of "node". + * "domain" is the universe set of the domain elements that reach "node". + * "parent" is the parent isl_band of the isl_band structures constructed + * by this function. + * + * If schedule_separate_components is set then set nodes are treated + * as sequence nodes. Otherwise, we directly extract an (implicitly + * parallel) list of isl_band structures. * - * A separate isl_band structure is created for each band_id - * and for each node that does not have a band with sequence - * number band_nr. In the latter case, a band without members - * is created. - * This ensures that if a band has any children, then each node - * that was active in the band is active in exactly one of the children. + * If "node" is a filter, then "domain" is updated by the filter. */ static __isl_give isl_band_list *construct_band_list( - __isl_keep isl_schedule *schedule, __isl_keep isl_band *parent, - int band_nr, int *parent_active, int n_active) + __isl_take isl_schedule_node *node, __isl_take isl_union_set *domain, + __isl_keep isl_band *parent) { - int i, j; - isl_ctx *ctx = isl_schedule_get_ctx(schedule); - int *active; - int n_band; + enum isl_schedule_node_type type; + isl_ctx *ctx; + isl_band *band; isl_band_list *list; + isl_union_set *filter; - n_band = 0; - for (i = 0; i < n_active; ++i) { - for (j = 0; j < schedule->n; ++j) { - if (!parent_active[j]) - continue; - if (schedule->node[j].n_band <= band_nr) - continue; - if (schedule->node[j].band_id[band_nr] == i) { - n_band++; - break; - } - } - } - for (j = 0; j < schedule->n; ++j) - if (schedule->node[j].n_band <= band_nr) - n_band++; - - if (n_band == 1) { - isl_band *band; - list = isl_band_list_alloc(ctx, n_band); - band = construct_band(schedule, parent, band_nr, - parent_active, n_active); - return isl_band_list_add(list, band); - } - - active = isl_alloc_array(ctx, int, schedule->n); - if (schedule->n && !active) - return NULL; - - list = isl_band_list_alloc(ctx, n_band); - - for (i = 0; i < n_active; ++i) { - int n = 0; - isl_band *band; - - for (j = 0; j < schedule->n; ++j) { - active[j] = parent_active[j] && - schedule->node[j].n_band > band_nr && - schedule->node[j].band_id[band_nr] == i; - if (active[j]) - n++; - } - if (n == 0) - continue; - - band = construct_band(schedule, parent, band_nr, active, n); + if (!node || !domain) + goto error; - list = isl_band_list_add(list, band); - } - for (i = 0; i < schedule->n; ++i) { - isl_band *band; - if (!parent_active[i]) - continue; - if (schedule->node[i].n_band > band_nr) - continue; - for (j = 0; j < schedule->n; ++j) - active[j] = j == i; - band = construct_band(schedule, parent, band_nr, active, 1); - list = isl_band_list_add(list, band); + type = isl_schedule_node_get_type(node); + switch (type) { + case isl_schedule_node_error: + goto error; + case isl_schedule_node_domain: + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "internal domain nodes not allowed", goto error); + case isl_schedule_node_filter: + filter = isl_schedule_node_filter_get_filter(node); + domain = isl_union_set_intersect(domain, filter); + node = isl_schedule_node_child(node, 0); + return construct_band_list(node, domain, parent); + case isl_schedule_node_set: + ctx = isl_schedule_node_get_ctx(node); + if (isl_options_get_schedule_separate_components(ctx)) + return construct_band_list_sequence(node, domain, + parent); + else + return construct_band_list_from_children(node, domain, + parent); + case isl_schedule_node_sequence: + return construct_band_list_sequence(node, domain, parent); + case isl_schedule_node_leaf: + case isl_schedule_node_band: + band = construct_band(node, domain, parent); + list = isl_band_list_from_band(band); + break; } - free(active); - - list = sort_band_list(list, parent); - return list; -} - -/* Construct a band forest representation of the schedule and - * return the list of roots. - */ -static __isl_give isl_band_list *construct_forest( - __isl_keep isl_schedule *schedule) -{ - int i; - isl_ctx *ctx = isl_schedule_get_ctx(schedule); - isl_band_list *forest; - int *active; - - active = isl_alloc_array(ctx, int, schedule->n); - if (schedule->n && !active) - return NULL; - - for (i = 0; i < schedule->n; ++i) - active[i] = 1; - - forest = construct_band_list(schedule, NULL, 0, active, schedule->n); - - free(active); - - return forest; +error: + isl_union_set_free(domain); + isl_schedule_node_free(node); + return NULL; } /* Return the roots of a band forest representation of the schedule. + * The band forest is constructed from the schedule tree, + * but once such a band forest is + * constructed, we forget about the original schedule tree since + * the user may modify the schedule through the band forest. */ __isl_give isl_band_list *isl_schedule_get_band_forest( __isl_keep isl_schedule *schedule) { + isl_schedule_node *node; + isl_union_set *domain; + if (!schedule) return NULL; - if (!schedule->band_forest) - schedule->band_forest = construct_forest(schedule); + if (schedule->root) { + node = isl_schedule_get_root(schedule); + domain = isl_schedule_node_domain_get_domain(node); + domain = isl_union_set_universe(domain); + node = isl_schedule_node_child(node, 0); + + schedule->band_forest = construct_band_list(node, domain, NULL); + schedule->root = isl_schedule_tree_free(schedule->root); + } return isl_band_list_dup(schedule->band_forest); } @@ -644,11 +738,23 @@ static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p, return p; } +/* Print "schedule" to "p". + * + * If "schedule" was created from a schedule tree, then we print + * the schedule tree representation. Otherwise, we print + * the band forest representation. + */ __isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p, __isl_keep isl_schedule *schedule) { isl_band_list *forest; + if (!schedule) + return isl_printer_free(p); + + if (schedule->root) + return isl_printer_print_schedule_tree(p, schedule->root); + forest = isl_schedule_get_band_forest(schedule); p = print_band_list(p, forest); @@ -666,6 +772,7 @@ void isl_schedule_dump(__isl_keep isl_schedule *schedule) return; printer = isl_printer_to_file(isl_schedule_get_ctx(schedule), stderr); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); printer = isl_printer_print_schedule(printer, schedule); isl_printer_free(printer); diff --git a/polly/lib/External/isl/isl_schedule_band.c b/polly/lib/External/isl/isl_schedule_band.c new file mode 100644 index 00000000000..aae32f39a42 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_band.c @@ -0,0 +1,417 @@ +/* + * Copyright 2013-2014 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include <isl/schedule_node.h> +#include <isl_schedule_band.h> +#include <isl_schedule_private.h> + +isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band) +{ + return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL; +} + +/* Return a new uninitialized isl_schedule_band. + */ +static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx) +{ + isl_schedule_band *band; + + band = isl_calloc_type(ctx, isl_schedule_band); + if (!band) + return NULL; + + band->ref = 1; + + return band; +} + +/* Return a new isl_schedule_band with partial schedule "mupa". + * First replace "mupa" by its greatest integer part to ensure + * that the schedule is always integral. + * The band is not marked permutable and the dimensions are not + * marked coincident. + */ +__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa) +{ + isl_ctx *ctx; + isl_schedule_band *band; + + mupa = isl_multi_union_pw_aff_floor(mupa); + if (!mupa) + return NULL; + ctx = isl_multi_union_pw_aff_get_ctx(mupa); + band = isl_schedule_band_alloc(ctx); + if (!band) + goto error; + + band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); + band->coincident = isl_calloc_array(ctx, int, band->n); + band->mupa = mupa; + + if (band->n && !band->coincident) + return isl_schedule_band_free(band); + + return band; +error: + isl_multi_union_pw_aff_free(mupa); + return NULL; +} + +/* Create a duplicate of the given isl_schedule_band. + */ +__isl_give isl_schedule_band *isl_schedule_band_dup( + __isl_keep isl_schedule_band *band) +{ + int i; + isl_ctx *ctx; + isl_schedule_band *dup; + + if (!band) + return NULL; + + ctx = isl_schedule_band_get_ctx(band); + dup = isl_schedule_band_alloc(ctx); + if (!dup) + return NULL; + + dup->n = band->n; + dup->coincident = isl_alloc_array(ctx, int, band->n); + if (band->n && !dup->coincident) + return isl_schedule_band_free(dup); + + for (i = 0; i < band->n; ++i) + dup->coincident[i] = band->coincident[i]; + dup->permutable = band->permutable; + + dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); + if (!dup->mupa) + return isl_schedule_band_free(dup); + + return dup; +} + +/* Return an isl_schedule_band that is equal to "band" and that has only + * a single reference. + */ +__isl_give isl_schedule_band *isl_schedule_band_cow( + __isl_take isl_schedule_band *band) +{ + if (!band) + return NULL; + + if (band->ref == 1) + return band; + band->ref--; + return isl_schedule_band_dup(band); +} + +/* Return a new reference to "band". + */ +__isl_give isl_schedule_band *isl_schedule_band_copy( + __isl_keep isl_schedule_band *band) +{ + if (!band) + return NULL; + + band->ref++; + return band; +} + +/* Free a reference to "band" and return NULL. + */ +__isl_null isl_schedule_band *isl_schedule_band_free( + __isl_take isl_schedule_band *band) +{ + if (!band) + return NULL; + + if (--band->ref > 0) + return NULL; + + isl_multi_union_pw_aff_free(band->mupa); + free(band->coincident); + free(band); + + return NULL; +} + +/* Return the number of scheduling dimensions in the band. + */ +int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band) +{ + return band ? band->n : 0; +} + +/* Is the given scheduling dimension coincident within the band and + * with respect to the coincidence constraints? + */ +int isl_schedule_band_member_get_coincident(__isl_keep isl_schedule_band *band, + int pos) +{ + if (!band) + return -1; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", return -1); + + return band->coincident[pos]; +} + +/* Mark the given scheduling dimension as being coincident or not + * according to "coincident". + */ +__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( + __isl_take isl_schedule_band *band, int pos, int coincident) +{ + if (!band) + return NULL; + if (isl_schedule_band_member_get_coincident(band, pos) == coincident) + return band; + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + if (pos < 0 || pos >= band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, + "invalid member position", + isl_schedule_band_free(band)); + + band->coincident[pos] = coincident; + + return band; +} + +/* Is the schedule band mark permutable? + */ +int isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band) +{ + if (!band) + return -1; + return band->permutable; +} + +/* Mark the schedule band permutable or not according to "permutable"? + */ +__isl_give isl_schedule_band *isl_schedule_band_set_permutable( + __isl_take isl_schedule_band *band, int permutable) +{ + if (!band) + return NULL; + if (band->permutable == permutable) + return band; + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + band->permutable = permutable; + + return band; +} + +/* Return the schedule space of the band. + */ +__isl_give isl_space *isl_schedule_band_get_space( + __isl_keep isl_schedule_band *band) +{ + if (!band) + return NULL; + return isl_multi_union_pw_aff_get_space(band->mupa); +} + +/* Return the schedule of the band in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( + __isl_keep isl_schedule_band *band) +{ + return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL; +} + +/* Multiply the partial schedule of "band" with the factors in "mv". + * Replace the result by its greatest integer part to ensure + * that the schedule is always integral. + */ +__isl_give isl_schedule_band *isl_schedule_band_scale( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) +{ + band = isl_schedule_band_cow(band); + if (!band || !mv) + goto error; + band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv); + band->mupa = isl_multi_union_pw_aff_floor(band->mupa); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(mv); + return NULL; +} + +/* Divide the partial schedule of "band" by the factors in "mv". + * Replace the result by its greatest integer part to ensure + * that the schedule is always integral. + */ +__isl_give isl_schedule_band *isl_schedule_band_scale_down( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) +{ + band = isl_schedule_band_cow(band); + if (!band || !mv) + goto error; + band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa, + mv); + band->mupa = isl_multi_union_pw_aff_floor(band->mupa); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(mv); + return NULL; +} + +/* Given the schedule of a band, construct the corresponding + * schedule for the tile loops based on the given tile sizes + * and return the result. + * + * If the scale tile loops options is set, then the tile loops + * are scaled by the tile sizes. + * + * That is replace each schedule dimension "i" by either + * "floor(i/s)" or "s * floor(i/s)". + */ +static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile( + __isl_take isl_multi_union_pw_aff *sched, + __isl_take isl_multi_val *sizes) +{ + isl_ctx *ctx; + int i, n; + isl_val *v; + int scale; + + ctx = isl_multi_val_get_ctx(sizes); + scale = isl_options_get_tile_scale_tile_loops(ctx); + + n = isl_multi_union_pw_aff_dim(sched, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_aff *upa; + + upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i); + v = isl_multi_val_get_val(sizes, i); + + upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v)); + upa = isl_union_pw_aff_floor(upa); + if (scale) + upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v)); + isl_val_free(v); + + sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa); + } + + isl_multi_val_free(sizes); + return sched; +} + +/* Replace "band" by a band corresponding to the tile loops of a tiling + * with the given tile sizes. + */ +__isl_give isl_schedule_band *isl_schedule_band_tile( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes) +{ + band = isl_schedule_band_cow(band); + if (!band || !sizes) + goto error; + band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(sizes); + return NULL; +} + +/* Replace "band" by a band corresponding to the point loops of a tiling + * with the given tile sizes. + * "tile" is the corresponding tile loop band. + * + * If the shift point loops option is set, then the point loops + * are shifted to start at zero. That is, each schedule dimension "i" + * is replaced by "i - s * floor(i/s)". + * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from + * the tile band. + * + * Otherwise, the band is left untouched. + */ +__isl_give isl_schedule_band *isl_schedule_band_point( + __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, + __isl_take isl_multi_val *sizes) +{ + isl_ctx *ctx; + isl_multi_union_pw_aff *scaled; + + if (!band || !sizes) + goto error; + + ctx = isl_schedule_band_get_ctx(band); + if (!isl_options_get_tile_shift_point_loops(ctx)) { + isl_multi_val_free(sizes); + return band; + } + band = isl_schedule_band_cow(band); + if (!band) + goto error; + + scaled = isl_schedule_band_get_partial_schedule(tile); + if (!isl_options_get_tile_scale_tile_loops(ctx)) + scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes); + else + isl_multi_val_free(sizes); + band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled); + if (!band->mupa) + return isl_schedule_band_free(band); + return band; +error: + isl_schedule_band_free(band); + isl_multi_val_free(sizes); + return NULL; +} + +/* Drop the "n" dimensions starting at "pos" from "band". + * + * We apply the transformation even if "n" is zero to ensure consistent + * behavior with respect to changes in the schedule space. + */ +__isl_give isl_schedule_band *isl_schedule_band_drop( + __isl_take isl_schedule_band *band, int pos, int n) +{ + int i; + + if (pos < 0 || n < 0 || pos + n > band->n) + isl_die(isl_schedule_band_get_ctx(band), isl_error_internal, + "range out of bounds", + return isl_schedule_band_free(band)); + + band = isl_schedule_band_cow(band); + if (!band) + return NULL; + + band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa, + isl_dim_set, pos, n); + if (!band->mupa) + return isl_schedule_band_free(band); + + for (i = pos + n; i < band->n; ++i) + band->coincident[i - n] = band->coincident[i]; + + band->n -= n; + + return band; +} diff --git a/polly/lib/External/isl/isl_schedule_band.h b/polly/lib/External/isl/isl_schedule_band.h new file mode 100644 index 00000000000..1a476e3ce34 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_band.h @@ -0,0 +1,63 @@ +#ifndef ISL_SCHEDULE_BAND_H +#define ISL_SCHEDULE_BAND_H + +#include <isl/aff.h> +#include <isl/union_map.h> + +/* Information about a band within a schedule. + * + * n is the number of scheduling dimensions within the band. + * coincident is an array of length n, indicating whether a scheduling dimension + * satisfies the coincidence constraints in the sense that + * the corresponding dependence distances are zero. + * permutable is set if the band is permutable. + * mupa is the partial schedule corresponding to this band. The dimension + * of mupa is equal to n. + */ +struct isl_schedule_band { + int ref; + + int n; + int *coincident; + int permutable; + + isl_multi_union_pw_aff *mupa; +}; +typedef struct isl_schedule_band isl_schedule_band; + +__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( + __isl_take isl_multi_union_pw_aff *mupa); +__isl_give isl_schedule_band *isl_schedule_band_copy( + __isl_keep isl_schedule_band *band); +__isl_null isl_schedule_band *isl_schedule_band_free( + __isl_take isl_schedule_band *band); + +isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band); + +__isl_give isl_space *isl_schedule_band_get_space( + __isl_keep isl_schedule_band *band); +__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( + __isl_keep isl_schedule_band *band); + +int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band); +int isl_schedule_band_member_get_coincident( + __isl_keep isl_schedule_band *band, int pos); +__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( + __isl_take isl_schedule_band *band, int pos, int coincident); +int isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band); +__isl_give isl_schedule_band *isl_schedule_band_set_permutable( + __isl_take isl_schedule_band *band, int permutable); + +__isl_give isl_schedule_band *isl_schedule_band_scale( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_band *isl_schedule_band_scale_down( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_band *isl_schedule_band_tile( + __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_band *isl_schedule_band_point( + __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, + __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_band *isl_schedule_band_drop( + __isl_take isl_schedule_band *band, int pos, int n); + +#endif diff --git a/polly/lib/External/isl/isl_schedule_node.c b/polly/lib/External/isl/isl_schedule_node.c new file mode 100644 index 00000000000..253221b2ee2 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_node.c @@ -0,0 +1,1535 @@ +/* + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include <isl/set.h> +#include <isl_schedule_band.h> +#include <isl_schedule_private.h> +#include <isl_schedule_node_private.h> + +/* Create a new schedule node in the given schedule, point at the given + * tree with given ancestors and child positions. + * "child_pos" may be NULL if there are no ancestors. + */ +__isl_give isl_schedule_node *isl_schedule_node_alloc( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *ancestors, int *child_pos) +{ + isl_ctx *ctx; + isl_schedule_node *node; + int i, n; + + if (!schedule || !tree || !ancestors) + goto error; + n = isl_schedule_tree_list_n_schedule_tree(ancestors); + if (n > 0 && !child_pos) + goto error; + ctx = isl_schedule_get_ctx(schedule); + node = isl_calloc_type(ctx, isl_schedule_node); + if (!node) + goto error; + node->ref = 1; + node->schedule = schedule; + node->tree = tree; + node->ancestors = ancestors; + node->child_pos = isl_alloc_array(ctx, int, n); + if (n && !node->child_pos) + return isl_schedule_node_free(node); + for (i = 0; i < n; ++i) + node->child_pos[i] = child_pos[i]; + + return node; +error: + isl_schedule_free(schedule); + isl_schedule_tree_free(tree); + isl_schedule_tree_list_free(ancestors); + return NULL; +} + +/* Return a pointer to the root of a schedule tree with as single + * node a domain node with the given domain. + */ +__isl_give isl_schedule_node *isl_schedule_node_from_domain( + __isl_take isl_union_set *domain) +{ + isl_schedule *schedule; + isl_schedule_node *node; + + schedule = isl_schedule_from_domain(domain); + node = isl_schedule_get_root(schedule); + isl_schedule_free(schedule); + + return node; +} + +/* Return the isl_ctx to which "node" belongs. + */ +isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_get_ctx(node->schedule) : NULL; +} + +/* Return a pointer to the leaf of the schedule into which "node" points. + * + * Even though these leaves are not reference counted, we still + * indicate that this function does not return a copy. + */ +__isl_keep isl_schedule_tree *isl_schedule_node_peek_leaf( + __isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_peek_leaf(node->schedule) : NULL; +} + +/* Return a pointer to the leaf of the schedule into which "node" points. + * + * Even though these leaves are not reference counted, we still + * return a "copy" of the leaf here such that it can still be "freed" + * by the user. + */ +__isl_give isl_schedule_tree *isl_schedule_node_get_leaf( + __isl_keep isl_schedule_node *node) +{ + return isl_schedule_tree_copy(isl_schedule_node_peek_leaf(node)); +} + +/* Return the type of the node or isl_schedule_node_error on error. + */ +enum isl_schedule_node_type isl_schedule_node_get_type( + __isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_tree_get_type(node->tree) + : isl_schedule_node_error; +} + +/* Return the type of the parent of "node" or isl_schedule_node_error on error. + */ +enum isl_schedule_node_type isl_schedule_node_get_parent_type( + __isl_keep isl_schedule_node *node) +{ + int pos; + int has_parent; + isl_schedule_tree *parent; + enum isl_schedule_node_type type; + + if (!node) + return isl_schedule_node_error; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return isl_schedule_node_error; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", return isl_schedule_node_error); + + pos = isl_schedule_tree_list_n_schedule_tree(node->ancestors) - 1; + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, pos); + type = isl_schedule_tree_get_type(parent); + isl_schedule_tree_free(parent); + + return type; +} + +/* Return a copy of the subtree that this node points to. + */ +__isl_give isl_schedule_tree *isl_schedule_node_get_tree( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_copy(node->tree); +} + +/* Return a copy of the schedule into which "node" points. + */ +__isl_give isl_schedule *isl_schedule_node_get_schedule( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + return isl_schedule_copy(node->schedule); +} + +/* Return a fresh copy of "node". + */ +__isl_take isl_schedule_node *isl_schedule_node_dup( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_node_alloc(isl_schedule_copy(node->schedule), + isl_schedule_tree_copy(node->tree), + isl_schedule_tree_list_copy(node->ancestors), + node->child_pos); +} + +/* Return an isl_schedule_node that is equal to "node" and that has only + * a single reference. + */ +__isl_give isl_schedule_node *isl_schedule_node_cow( + __isl_take isl_schedule_node *node) +{ + if (!node) + return NULL; + + if (node->ref == 1) + return node; + node->ref--; + return isl_schedule_node_dup(node); +} + +/* Return a new reference to "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_copy( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + node->ref++; + return node; +} + +/* Free "node" and return NULL. + * + * Since the node may point to a leaf of its schedule, which + * point to a field inside the schedule, we need to make sure + * we free the tree before freeing the schedule. + */ +__isl_null isl_schedule_node *isl_schedule_node_free( + __isl_take isl_schedule_node *node) +{ + if (!node) + return NULL; + if (--node->ref > 0) + return NULL; + + isl_schedule_tree_list_free(node->ancestors); + free(node->child_pos); + isl_schedule_tree_free(node->tree); + isl_schedule_free(node->schedule); + free(node); + + return NULL; +} + +/* Internal data structure for + * isl_schedule_node_get_prefix_schedule_union_pw_multi_aff + * + * "initialized" is set if the filter field has been initialized. + * "universe_filter" is set if we are only collecting the universes of filters + * "collect_prefix" is set if we are collecting prefixes. + * "filter" collects all outer filters and is NULL until "initialized" is set. + * "prefix" collects all outer band partial schedules (if "collect_prefix" + * is set). If it is used, then it is initialized by the caller + * of collect_filter_prefix to a zero-dimensional function. + */ +struct isl_schedule_node_get_filter_prefix_data { + int initialized; + int universe_filter; + int collect_prefix; + isl_union_set *filter; + isl_multi_union_pw_aff *prefix; +}; + +/* Update "data" based on the tree node "tree" in case "data" has + * not been initialized yet. + * + * Return 0 on success and -1 on error. + * + * If "tree" is a filter, then we set data->filter to this filter + * (or its universe). + * If "tree" is a domain, then this means we have reached the root + * of the schedule tree without being able to extract any information. + * We therefore initialize data->filter to the universe of the domain. + * If "tree" is a band with at least one member, then we set data->filter + * to the universe of the schedule domain and replace the zero-dimensional + * data->prefix by the band schedule (if data->collect_prefix is set). + */ +static int collect_filter_prefix_init(__isl_keep isl_schedule_tree *tree, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + enum isl_schedule_node_type type; + isl_multi_union_pw_aff *mupa; + isl_union_set *filter; + + type = isl_schedule_tree_get_type(tree); + switch (type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_leaf: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + return 0; + case isl_schedule_node_domain: + filter = isl_schedule_tree_domain_get_domain(tree); + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + return 0; + mupa = isl_schedule_tree_band_get_partial_schedule(tree); + if (data->collect_prefix) { + isl_multi_union_pw_aff_free(data->prefix); + mupa = isl_multi_union_pw_aff_reset_tuple_id(mupa, + isl_dim_set); + data->prefix = isl_multi_union_pw_aff_copy(mupa); + } + filter = isl_multi_union_pw_aff_domain(mupa); + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + case isl_schedule_node_filter: + filter = isl_schedule_tree_filter_get_filter(tree); + if (data->universe_filter) + filter = isl_union_set_universe(filter); + data->filter = filter; + break; + } + + if ((data->collect_prefix && !data->prefix) || !data->filter) + return -1; + + data->initialized = 1; + + return 0; +} + +/* Update "data" based on the tree node "tree" in case "data" has + * already been initialized. + * + * Return 0 on success and -1 on error. + * + * If "tree" is a filter, then we intersect data->filter with this filter + * (or its universe). + * If "tree" is a band with at least one member and data->collect_prefix + * is set, then we extend data->prefix with the band schedule. + */ +static int collect_filter_prefix_update(__isl_keep isl_schedule_tree *tree, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + enum isl_schedule_node_type type; + isl_multi_union_pw_aff *mupa; + isl_union_set *filter; + + type = isl_schedule_tree_get_type(tree); + switch (type) { + case isl_schedule_node_error: + return -1; + case isl_schedule_node_domain: + case isl_schedule_node_leaf: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + break; + if (!data->collect_prefix) + break; + mupa = isl_schedule_tree_band_get_partial_schedule(tree); + data->prefix = isl_multi_union_pw_aff_flat_range_product(mupa, + data->prefix); + if (!data->prefix) + return -1; + break; + case isl_schedule_node_filter: + filter = isl_schedule_tree_filter_get_filter(tree); + if (data->universe_filter) + filter = isl_union_set_universe(filter); + data->filter = isl_union_set_intersect(data->filter, filter); + if (!data->filter) + return -1; + break; + } + + return 0; +} + +/* Collect filter and/or prefix information from the elements + * in "list" (which represent the ancestors of a node). + * Store the results in "data". + * + * Return 0 on success and -1 on error. + * + * We traverse the list from innermost ancestor (last element) + * to outermost ancestor (first element), calling collect_filter_prefix_init + * on each node as long as we have not been able to extract any information + * yet and collect_filter_prefix_update afterwards. + * On successful return, data->initialized will be set since the outermost + * ancestor is a domain node, which always results in an initialization. + */ +static int collect_filter_prefix(__isl_keep isl_schedule_tree_list *list, + struct isl_schedule_node_get_filter_prefix_data *data) +{ + int i, n; + + data->initialized = 0; + data->filter = NULL; + + if (!list) + return -1; + + n = isl_schedule_tree_list_n_schedule_tree(list); + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *tree; + int r; + + tree = isl_schedule_tree_list_get_schedule_tree(list, i); + if (!tree) + return -1; + if (!data->initialized) + r = collect_filter_prefix_init(tree, data); + else + r = collect_filter_prefix_update(tree, data); + isl_schedule_tree_free(tree); + if (r < 0) + return -1; + } + + return 0; +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" interesected with all outer filters + * as an isl_union_pw_multi_aff. + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * + * We collect all the filters and partial schedules in collect_filter_prefix. + * The partial schedules are collected as an isl_multi_union_pw_aff. + * If this isl_multi_union_pw_aff is zero-dimensional, then it does not + * contain any domain information, so we construct the isl_union_pw_multi_aff + * result as a zero-dimensional function on the collected filter. + * Otherwise, we convert the isl_multi_union_pw_aff to + * an isl_multi_union_pw_aff and intersect the domain with the filter. + */ +__isl_give isl_union_pw_multi_aff * +isl_schedule_node_get_prefix_schedule_union_pw_multi_aff( + __isl_keep isl_schedule_node *node) +{ + isl_space *space; + isl_union_pw_multi_aff *prefix; + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + space = isl_schedule_get_space(node->schedule); + if (node->tree == node->schedule->root) + return isl_union_pw_multi_aff_empty(space); + + space = isl_space_set_from_params(space); + data.universe_filter = 0; + data.collect_prefix = 1; + data.prefix = isl_multi_union_pw_aff_zero(space); + + if (collect_filter_prefix(node->ancestors, &data) < 0) + data.prefix = isl_multi_union_pw_aff_free(data.prefix); + + if (data.prefix && + isl_multi_union_pw_aff_dim(data.prefix, isl_dim_set) == 0) { + isl_multi_union_pw_aff_free(data.prefix); + prefix = isl_union_pw_multi_aff_from_domain(data.filter); + } else { + prefix = + isl_union_pw_multi_aff_from_multi_union_pw_aff(data.prefix); + prefix = isl_union_pw_multi_aff_intersect_domain(prefix, + data.filter); + } + + return prefix; +} + +/* Return the concatenation of the partial schedules of all outer band + * nodes of "node" interesected with all outer filters + * as an isl_union_map. + */ +__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_union_pw_multi_aff *upma; + + upma = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node); + return isl_union_map_from_union_pw_multi_aff(upma); +} + +/* Return the union of universe sets of the domain elements that reach "node". + * + * If "node" is pointing at the root of the schedule tree, then + * there are no domain elements reaching the current node, so + * we return an empty result. + * + * Otherwise, we collect the universes of all filters reaching the node + * in collect_filter_prefix. + */ +__isl_give isl_union_set *isl_schedule_node_get_universe_domain( + __isl_keep isl_schedule_node *node) +{ + struct isl_schedule_node_get_filter_prefix_data data; + + if (!node) + return NULL; + + if (node->tree == node->schedule->root) { + isl_space *space; + + space = isl_schedule_get_space(node->schedule); + return isl_union_set_empty(space); + } + + data.universe_filter = 1; + data.collect_prefix = 0; + data.prefix = NULL; + + if (collect_filter_prefix(node->ancestors, &data) < 0) + data.filter = isl_union_set_free(data.filter); + + return data.filter; +} + +/* Return the subtree schedule of "node". + * + * Since isl_schedule_tree_get_subtree_schedule_union_map does not handle + * trees that do not contain any schedule information, we first + * move down to the first relevant descendant and handle leaves ourselves. + */ +__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_schedule_tree *tree, *leaf; + isl_union_map *umap; + + tree = isl_schedule_node_get_tree(node); + leaf = isl_schedule_node_peek_leaf(node); + tree = isl_schedule_tree_first_schedule_descendant(tree, leaf); + if (!tree) + return NULL; + if (tree == leaf) { + isl_union_set *domain; + domain = isl_schedule_node_get_universe_domain(node); + isl_schedule_tree_free(tree); + return isl_union_map_from_domain(domain); + } + + umap = isl_schedule_tree_get_subtree_schedule_union_map(tree); + isl_schedule_tree_free(tree); + return umap; +} + +/* Return the number of ancestors of "node" in its schedule tree. + */ +int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node) +{ + if (!node) + return -1; + return isl_schedule_tree_list_n_schedule_tree(node->ancestors); +} + +/* Does "node" have a parent? + * + * That is, does it point to any node of the schedule other than the root? + */ +int isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node) +{ + if (!node) + return -1; + if (!node->ancestors) + return -1; + + return isl_schedule_tree_list_n_schedule_tree(node->ancestors) != 0; +} + +/* Return the position of "node" among the children of its parent. + */ +int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node) +{ + int n; + int has_parent; + + if (!node) + return -1; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return -1; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", return -1); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + return node->child_pos[n - 1]; +} + +/* Does the parent (if any) of "node" have any children with a smaller child + * position than this one? + */ +int isl_schedule_node_has_previous_sibling(__isl_keep isl_schedule_node *node) +{ + int n; + int has_parent; + + if (!node) + return -1; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0 || !has_parent) + return has_parent; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + + return node->child_pos[n - 1] > 0; +} + +/* Does the parent (if any) of "node" have any children with a greater child + * position than this one? + */ +int isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node) +{ + int n, n_child; + int has_parent; + isl_schedule_tree *tree; + + if (!node) + return -1; + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0 || !has_parent) + return has_parent; + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n - 1); + if (!tree) + return -1; + n_child = isl_schedule_tree_list_n_schedule_tree(tree->children); + isl_schedule_tree_free(tree); + + return node->child_pos[n - 1] + 1 < n_child; +} + +/* Does "node" have any children? + * + * Any node other than the leaf nodes is considered to have at least + * one child, even if the corresponding isl_schedule_tree does not + * have any children. + */ +int isl_schedule_node_has_children(__isl_keep isl_schedule_node *node) +{ + if (!node) + return -1; + return !isl_schedule_tree_is_leaf(node->tree); +} + +/* Return the number of children of "node"? + * + * Any node other than the leaf nodes is considered to have at least + * one child, even if the corresponding isl_schedule_tree does not + * have any children. That is, the number of children of "node" is + * only zero if its tree is the explicit empty tree. Otherwise, + * if the isl_schedule_tree has any children, then it is equal + * to the number of children of "node". If it has zero children, + * then "node" still has a leaf node as child. + */ +int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node) +{ + int n; + + if (!node) + return -1; + + if (isl_schedule_tree_is_leaf(node->tree)) + return 0; + + n = isl_schedule_tree_n_children(node->tree); + if (n == 0) + return 1; + + return n; +} + +/* Move the "node" pointer to the parent of the node it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_parent( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_parent(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no parent", + return isl_schedule_node_free(node)); + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n - 1); + isl_schedule_tree_free(node->tree); + node->tree = tree; + node->ancestors = isl_schedule_tree_list_drop(node->ancestors, + n - 1, 1); + if (!node->ancestors || !node->tree) + return isl_schedule_node_free(node); + + return node; +} + +/* Move the "node" pointer to the child at position "pos" of the node + * it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_child( + __isl_take isl_schedule_node *node, int pos) +{ + int n; + isl_ctx *ctx; + isl_schedule_tree *tree; + int *child_pos; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_children(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no children", + return isl_schedule_node_free(node)); + + ctx = isl_schedule_node_get_ctx(node); + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + child_pos = isl_realloc_array(ctx, node->child_pos, int, n + 1); + if (!child_pos) + return isl_schedule_node_free(node); + node->child_pos = child_pos; + node->child_pos[n] = pos; + + node->ancestors = isl_schedule_tree_list_add(node->ancestors, + isl_schedule_tree_copy(node->tree)); + tree = node->tree; + if (isl_schedule_tree_has_children(tree)) + tree = isl_schedule_tree_get_child(tree, pos); + else + tree = isl_schedule_node_get_leaf(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + if (!node->tree || !node->ancestors) + return isl_schedule_node_free(node); + + return node; +} + +/* Move the "node" pointer to the first child of the node + * it currently points to. + */ +__isl_give isl_schedule_node *isl_schedule_node_first_child( + __isl_take isl_schedule_node *node) +{ + return isl_schedule_node_child(node, 0); +} + +/* Move the "node" pointer to the child of this node's parent in + * the previous child position. + */ +__isl_give isl_schedule_node *isl_schedule_node_previous_sibling( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *parent, *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_previous_sibling(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no previous sibling", + return isl_schedule_node_free(node)); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n - 1); + if (!parent) + return isl_schedule_node_free(node); + node->child_pos[n - 1]--; + tree = isl_schedule_tree_list_get_schedule_tree(parent->children, + node->child_pos[n - 1]); + isl_schedule_tree_free(parent); + if (!tree) + return isl_schedule_node_free(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + return node; +} + +/* Move the "node" pointer to the child of this node's parent in + * the next child position. + */ +__isl_give isl_schedule_node *isl_schedule_node_next_sibling( + __isl_take isl_schedule_node *node) +{ + int n; + isl_schedule_tree *parent, *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + if (!isl_schedule_node_has_next_sibling(node)) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "node has no next sibling", + return isl_schedule_node_free(node)); + + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, + n - 1); + if (!parent) + return isl_schedule_node_free(node); + node->child_pos[n - 1]++; + tree = isl_schedule_tree_list_get_schedule_tree(parent->children, + node->child_pos[n - 1]); + isl_schedule_tree_free(parent); + if (!tree) + return isl_schedule_node_free(node); + isl_schedule_tree_free(node->tree); + node->tree = tree; + + return node; +} + +/* Return a copy to the child at position "pos" of "node". + */ +__isl_give isl_schedule_node *isl_schedule_node_get_child( + __isl_keep isl_schedule_node *node, int pos) +{ + return isl_schedule_node_child(isl_schedule_node_copy(node), pos); +} + +/* Traverse the descendant of "node" in depth-first order, including + * "node" itself. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. The callback "enter" is responsible + * for moving to the deepest initial subtree of its argument that + * should be traversed. + */ +static __isl_give isl_schedule_node *traverse( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*enter)( + __isl_take isl_schedule_node *node, void *user), + __isl_give isl_schedule_node *(*leave)( + __isl_take isl_schedule_node *node, void *user), + void *user) +{ + int depth; + + if (!node) + return NULL; + + depth = isl_schedule_node_get_tree_depth(node); + do { + node = enter(node, user); + node = leave(node, user); + while (node && isl_schedule_node_get_tree_depth(node) > depth && + !isl_schedule_node_has_next_sibling(node)) { + node = isl_schedule_node_parent(node); + node = leave(node, user); + } + if (node && isl_schedule_node_get_tree_depth(node) > depth) + node = isl_schedule_node_next_sibling(node); + } while (node && isl_schedule_node_get_tree_depth(node) > depth); + + return node; +} + +/* Internal data structure for isl_schedule_node_foreach_descendant. + * + * "fn" is the user-specified callback function. + * "user" is the user-specified argument for the callback. + */ +struct isl_schedule_node_preorder_data { + int (*fn)(__isl_keep isl_schedule_node *node, void *user); + void *user; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * for use in a preorder visit. + * + * If the user callback returns a negative value, then we abort + * the traversal. If this callback returns zero, then we skip + * the subtree rooted at the current node. Otherwise, we move + * down to the first child and repeat the process until a leaf + * is reached. + */ +static __isl_give isl_schedule_node *preorder_enter( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_schedule_node_preorder_data *data = user; + + if (!node) + return NULL; + + do { + int r; + + r = data->fn(node, data->user); + if (r < 0) + return isl_schedule_node_free(node); + if (r == 0) + return node; + } while (isl_schedule_node_has_children(node) && + (node = isl_schedule_node_first_child(node)) != NULL); + + return node; +} + +/* Callback for "traverse" to leave a node + * for use in a preorder visit. + * Since we already visited the node when we entered it, + * we do not need to do anything here. + */ +static __isl_give isl_schedule_node *preorder_leave( + __isl_take isl_schedule_node *node, void *user) +{ + return node; +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first preorder. + * + * If "fn" returns -1 on any of the nodes, then the traversal is aborted. + * If "fn" returns 0 on any of the nodes, then the subtree rooted + * at that node is skipped. + * + * Return 0 on success and -1 on failure. + */ +int isl_schedule_node_foreach_descendant(__isl_keep isl_schedule_node *node, + int (*fn)(__isl_keep isl_schedule_node *node, void *user), void *user) +{ + struct isl_schedule_node_preorder_data data = { fn, user }; + + node = isl_schedule_node_copy(node); + node = traverse(node, &preorder_enter, &preorder_leave, &data); + isl_schedule_node_free(node); + + return node ? 0 : -1; +} + +/* Internal data structure for isl_schedule_node_map_descendant. + * + * "fn" is the user-specified callback function. + * "user" is the user-specified argument for the callback. + */ +struct isl_schedule_node_postorder_data { + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user); + void *user; +}; + +/* Callback for "traverse" to enter a node and to move + * to the deepest initial subtree that should be traversed + * for use in a postorder visit. + * + * Since we are performing a postorder visit, we only need + * to move to the deepest initial leaf here. + */ +static __isl_give isl_schedule_node *postorder_enter( + __isl_take isl_schedule_node *node, void *user) +{ + while (node && isl_schedule_node_has_children(node)) + node = isl_schedule_node_first_child(node); + + return node; +} + +/* Callback for "traverse" to leave a node + * for use in a postorder visit. + * + * Since we are performing a postorder visit, we need + * to call the user callback here. + */ +static __isl_give isl_schedule_node *postorder_leave( + __isl_take isl_schedule_node *node, void *user) +{ + struct isl_schedule_node_postorder_data *data = user; + + return data->fn(node, data->user); +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first postorder, allowing the user to modify the visited node. + * The traversal continues from the node returned by the callback function. + * It is the responsibility of the user to ensure that this does not + * lead to an infinite loop. It is safest to always return a pointer + * to the same position (same ancestors and child positions) as the input node. + */ +__isl_give isl_schedule_node *isl_schedule_node_map_descendant( + __isl_take isl_schedule_node *node, + __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, + void *user), void *user) +{ + struct isl_schedule_node_postorder_data data = { fn, user }; + + return traverse(node, &postorder_enter, &postorder_leave, &data); +} + +/* Return the number of members in the given band node. + */ +unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node) +{ + return node ? isl_schedule_tree_band_n_member(node->tree) : 0; +} + +/* Is the band member at position "pos" of the band node "node" + * marked coincident? + */ +int isl_schedule_node_band_member_get_coincident( + __isl_keep isl_schedule_node *node, int pos) +{ + if (!node) + return -1; + return isl_schedule_tree_band_member_get_coincident(node->tree, pos); +} + +/* Mark the band member at position "pos" the band node "node" + * as being coincident or not according to "coincident". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident( + __isl_take isl_schedule_node *node, int pos, int coincident) +{ + int c; + isl_schedule_tree *tree; + + if (!node) + return NULL; + c = isl_schedule_node_band_member_get_coincident(node, pos); + if (c == coincident) + return node; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_member_set_coincident(tree, pos, + coincident); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Is the band node "node" marked permutable? + */ +int isl_schedule_node_band_get_permutable(__isl_keep isl_schedule_node *node) +{ + if (!node) + return -1; + + return isl_schedule_tree_band_get_permutable(node->tree); +} + +/* Mark the band node "node" permutable or not according to "permutable"? + */ +__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable( + __isl_take isl_schedule_node *node, int permutable) +{ + isl_schedule_tree *tree; + + if (!node) + return NULL; + if (isl_schedule_node_band_get_permutable(node) == permutable) + return node; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_band_set_permutable(tree, permutable); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Return the schedule space of the band node. + */ +__isl_give isl_space *isl_schedule_node_band_get_space( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_space(node->tree); +} + +/* Return the schedule of the band node in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_band_get_partial_schedule(node->tree); +} + +/* Return the schedule of the band node in isolation in the form of + * an isl_union_map. + * + * If the band does not have any members, then we construct a universe map + * with the universe of the domain elements reaching the node as domain. + * Otherwise, we extract an isl_multi_union_pw_aff representation and + * convert that to an isl_union_map. + */ +__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map( + __isl_keep isl_schedule_node *node) +{ + isl_multi_union_pw_aff *mupa; + + if (!node) + return NULL; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_band) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a band node", return NULL); + if (isl_schedule_node_band_n_member(node) == 0) { + isl_union_set *domain; + + domain = isl_schedule_node_get_universe_domain(node); + return isl_union_map_from_domain(domain); + } + + mupa = isl_schedule_node_band_get_partial_schedule(node); + return isl_union_map_from_multi_union_pw_aff(mupa); +} + +/* Make sure that that spaces of "node" and "mv" are the same. + * Return -1 on error, reporting the error to the user. + */ +static int check_space_multi_val(__isl_keep isl_schedule_node *node, + __isl_keep isl_multi_val *mv) +{ + isl_space *node_space, *mv_space; + int equal; + + node_space = isl_schedule_node_band_get_space(node); + mv_space = isl_multi_val_get_space(mv); + equal = isl_space_tuple_is_equal(node_space, isl_dim_set, + mv_space, isl_dim_set); + isl_space_free(mv_space); + isl_space_free(node_space); + if (equal < 0) + return -1; + if (!equal) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "spaces don't match", return -1); + + return 0; +} + +/* Multiply the partial schedule of the band node "node" + * with the factors in "mv". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_scale( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv) +{ + isl_schedule_tree *tree; + + if (!node || !mv) + goto error; + if (check_space_multi_val(node, mv) < 0) + goto error; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_scale(tree, mv); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(mv); + isl_schedule_node_free(node); + return NULL; +} + +/* Divide the partial schedule of the band node "node" + * by the factors in "mv". + */ +__isl_give isl_schedule_node *isl_schedule_node_band_scale_down( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv) +{ + isl_schedule_tree *tree; + + if (!node || !mv) + goto error; + if (check_space_multi_val(node, mv) < 0) + goto error; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_scale_down(tree, mv); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(mv); + isl_schedule_node_free(node); + return NULL; +} + +/* Tile "node" with tile sizes "sizes". + * + * The current node is replaced by two nested nodes corresponding + * to the tile dimensions and the point dimensions. + * + * Return a pointer to the outer (tile) node. + * + * 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) + */ +__isl_give isl_schedule_node *isl_schedule_node_band_tile( + __isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes) +{ + isl_schedule_tree *tree; + + if (!node || !sizes) + goto error; + + if (check_space_multi_val(node, sizes) < 0) + goto error; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_tile(tree, sizes); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_multi_val_free(sizes); + isl_schedule_node_free(node); + return NULL; +} + +/* Move the band node "node" down to all the leaves in the subtree + * rooted at "node". + * Return a pointer to the node in the resulting tree that is in the same + * position as the node pointed to by "node" in the original tree. + * + * If the node only has a leaf child, then nothing needs to be done. + * Otherwise, the child of the node is removed and the result is + * appended to all the leaves in the subtree rooted at the original child. + * The original node is then replaced by the result of this operation. + */ +__isl_give isl_schedule_node *isl_schedule_node_band_sink( + __isl_take isl_schedule_node *node) +{ + enum isl_schedule_node_type type; + isl_schedule_tree *tree, *child; + + if (!node) + return NULL; + + type = isl_schedule_node_get_type(node); + if (type != isl_schedule_node_band) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a band node", isl_schedule_node_free(node)); + if (isl_schedule_tree_n_children(node->tree) == 0) + return node; + + tree = isl_schedule_node_get_tree(node); + child = isl_schedule_tree_get_child(tree, 0); + tree = isl_schedule_tree_reset_children(tree); + tree = isl_schedule_tree_append_to_leaves(child, tree); + + return isl_schedule_node_graft_tree(node, tree); +} + +/* Split "node" into two nested band nodes, one with the first "pos" + * dimensions and one with the remaining dimensions. + * The schedules of the two band nodes live in anonymous spaces. + */ +__isl_give isl_schedule_node *isl_schedule_node_band_split( + __isl_take isl_schedule_node *node, int pos) +{ + isl_schedule_tree *tree; + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_band_split(tree, pos); + return isl_schedule_node_graft_tree(node, tree); +} + +/* Return the domain of the domain node "node". + */ +__isl_give isl_union_set *isl_schedule_node_domain_get_domain( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_domain_get_domain(node->tree); +} + +/* Return the filter of the filter node "node". + */ +__isl_give isl_union_set *isl_schedule_node_filter_get_filter( + __isl_keep isl_schedule_node *node) +{ + if (!node) + return NULL; + + return isl_schedule_tree_filter_get_filter(node->tree); +} + +/* Replace the filter of filter node "node" by "filter". + */ +__isl_give isl_schedule_node *isl_schedule_node_filter_set_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *tree; + + if (!node || !filter) + goto error; + + tree = isl_schedule_tree_copy(node->tree); + tree = isl_schedule_tree_filter_set_filter(tree, filter); + return isl_schedule_node_graft_tree(node, tree); +error: + isl_schedule_node_free(node); + isl_union_set_free(filter); + return NULL; +} + +/* Update the ancestors of "node" to point to the tree that "node" + * now points to. + * That is, replace the child in the original parent that corresponds + * to the current tree position by node->tree and continue updating + * the ancestors in the same way until the root is reached. + * + * If "node" originally points to a leaf of the schedule tree, then make sure + * that in the end it points to a leaf in the updated schedule tree. + */ +static __isl_give isl_schedule_node *update_ancestors( + __isl_take isl_schedule_node *node) +{ + int i, n; + int is_leaf; + isl_ctx *ctx; + isl_schedule_tree *tree; + + node = isl_schedule_node_cow(node); + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); + n = isl_schedule_tree_list_n_schedule_tree(node->ancestors); + tree = isl_schedule_tree_copy(node->tree); + + for (i = n - 1; i >= 0; --i) { + isl_schedule_tree *parent; + + parent = isl_schedule_tree_list_get_schedule_tree( + node->ancestors, i); + parent = isl_schedule_tree_replace_child(parent, + node->child_pos[i], tree); + node->ancestors = isl_schedule_tree_list_set_schedule_tree( + node->ancestors, i, isl_schedule_tree_copy(parent)); + + tree = parent; + } + + is_leaf = isl_schedule_tree_is_leaf(node->tree); + node->schedule = isl_schedule_set_root(node->schedule, tree); + if (is_leaf) { + isl_schedule_tree_free(node->tree); + node->tree = isl_schedule_node_get_leaf(node); + } + + if (!node->schedule || !node->ancestors) + return isl_schedule_node_free(node); + + return node; +} + +/* Replace the subtree that "pos" points to by "tree", updating + * the ancestors to maintain a consistent state. + */ +__isl_give isl_schedule_node *isl_schedule_node_graft_tree( + __isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree) +{ + if (!tree || !pos) + goto error; + if (pos->tree == tree) { + isl_schedule_tree_free(tree); + return pos; + } + + pos = isl_schedule_node_cow(pos); + if (!pos) + goto error; + + isl_schedule_tree_free(pos->tree); + pos->tree = tree; + + return update_ancestors(pos); +error: + isl_schedule_node_free(pos); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Make sure we can insert a node between "node" and its parent. + * Return -1 on error, reporting the reason why we cannot insert a node. + */ +static int check_insert(__isl_keep isl_schedule_node *node) +{ + int has_parent; + enum isl_schedule_node_type type; + + has_parent = isl_schedule_node_has_parent(node); + if (has_parent < 0) + return -1; + if (!has_parent) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert node outside of root", return -1); + + type = isl_schedule_node_get_parent_type(node); + if (type == isl_schedule_node_error) + return -1; + if (type == isl_schedule_node_set || type == isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "cannot insert node between set or sequence node " + "and its filter children", return -1); + + return 0; +} + +/* Insert a band node with partial schedule "mupa" between "node" and + * its parent. + * Return a pointer to the new band node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule( + __isl_take isl_schedule_node *node, + __isl_take isl_multi_union_pw_aff *mupa) +{ + isl_schedule_band *band; + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + band = isl_schedule_band_from_multi_union_pw_aff(mupa); + tree = isl_schedule_tree_insert_band(tree, band); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Insert a filter node with filter "filter" between "node" and its parent. + * Return a pointer to the new filter node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_filter( + __isl_take isl_schedule_node *node, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *tree; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + tree = isl_schedule_node_get_tree(node); + tree = isl_schedule_tree_insert_filter(tree, filter); + node = isl_schedule_node_graft_tree(node, tree); + + return node; +} + +/* Attach the current subtree of "node" to a sequence of filter tree nodes + * with filters described by "filters", attach this sequence + * of filter tree nodes as children to a new tree of type "type" and + * replace the original subtree of "node" by this new tree. + */ +static __isl_give isl_schedule_node *isl_schedule_node_insert_children( + __isl_take isl_schedule_node *node, + enum isl_schedule_node_type type, + __isl_take isl_union_set_list *filters) +{ + int i, n; + isl_ctx *ctx; + isl_schedule_tree *tree; + isl_schedule_tree_list *list; + + if (check_insert(node) < 0) + node = isl_schedule_node_free(node); + + if (!node || !filters) + goto error; + + ctx = isl_schedule_node_get_ctx(node); + n = isl_union_set_list_n_union_set(filters); + list = isl_schedule_tree_list_alloc(ctx, n); + for (i = 0; i < n; ++i) { + isl_schedule_tree *tree; + isl_union_set *filter; + + tree = isl_schedule_node_get_tree(node); + filter = isl_union_set_list_get_union_set(filters, i); + tree = isl_schedule_tree_insert_filter(tree, filter); + list = isl_schedule_tree_list_add(list, tree); + } + tree = isl_schedule_tree_from_children(type, list); + node = isl_schedule_node_graft_tree(node, tree); + + isl_union_set_list_free(filters); + return node; +error: + isl_union_set_list_free(filters); + isl_schedule_node_free(node); + return NULL; +} + +/* Insert a sequence node with child filters "filters" between "node" and + * its parent. That is, the tree that "node" points to is attached + * to each of the child nodes of the filter nodes. + * Return a pointer to the new sequence node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_sequence( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters) +{ + return isl_schedule_node_insert_children(node, + isl_schedule_node_sequence, filters); +} + +/* Insert a set node with child filters "filters" between "node" and + * its parent. That is, the tree that "node" points to is attached + * to each of the child nodes of the filter nodes. + * Return a pointer to the new set node. + */ +__isl_give isl_schedule_node *isl_schedule_node_insert_set( + __isl_take isl_schedule_node *node, + __isl_take isl_union_set_list *filters) +{ + return isl_schedule_node_insert_children(node, + isl_schedule_node_set, filters); +} + +/* Print "node" to "p". + */ +__isl_give isl_printer *isl_printer_print_schedule_node( + __isl_take isl_printer *p, __isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_printer_free(p); + return isl_printer_print_schedule_tree_mark(p, node->schedule->root, + isl_schedule_tree_list_n_schedule_tree(node->ancestors), + node->child_pos); +} + +void isl_schedule_node_dump(__isl_keep isl_schedule_node *node) +{ + isl_ctx *ctx; + isl_printer *printer; + + if (!node) + return; + + ctx = isl_schedule_node_get_ctx(node); + printer = isl_printer_to_file(ctx, stderr); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); + printer = isl_printer_print_schedule_node(printer, node); + + isl_printer_free(printer); +} diff --git a/polly/lib/External/isl/isl_schedule_node_private.h b/polly/lib/External/isl/isl_schedule_node_private.h new file mode 100644 index 00000000000..e8df4acd618 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_node_private.h @@ -0,0 +1,41 @@ +#ifndef ISL_SCHEDLUE_NODE_PRIVATE_H +#define ISL_SCHEDLUE_NODE_PRIVATE_H + +#include <isl/schedule_node.h> +#include <isl_schedule_band.h> + +/* An isl_schedule_node points to a particular location in a schedule tree. + * + * "schedule" is the schedule that the node is pointing to. + * "ancestors" is a list of the n ancestors of the node + * that is being pointed to. + * The first ancestor is the root of "schedule", while the last ancestor + * is the parent of the specified location. + * "child_pos" is an array of child positions of the same length as "ancestors", + * where ancestor i (i > 0) appears in child_pos[i - 1] of ancestor i - 1 and + * "tree" appears in child_pos[n - 1] of ancestor n - 1. + * "tree" is the subtree at the specified location. + * + * Note that the same isl_schedule_tree object may appear several times + * in a schedule tree and therefore does not uniquely identify a position + * in the schedule tree. + */ +struct isl_schedule_node { + int ref; + + isl_schedule *schedule; + isl_schedule_tree_list *ancestors; + int *child_pos; + isl_schedule_tree *tree; +}; + +__isl_give isl_schedule_node *isl_schedule_node_alloc( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *ancestors, int *child_pos); +__isl_give isl_schedule_node *isl_schedule_node_graft_tree( + __isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_node_get_tree( + __isl_keep isl_schedule_node *node); + +#endif diff --git a/polly/lib/External/isl/isl_schedule_private.h b/polly/lib/External/isl/isl_schedule_private.h index f40a72a0146..fd5c979a226 100644 --- a/polly/lib/External/isl/isl_schedule_private.h +++ b/polly/lib/External/isl/isl_schedule_private.h @@ -3,42 +3,39 @@ #include <isl/aff.h> #include <isl/schedule.h> +#include <isl_schedule_tree.h> -/* The schedule for an individual domain, plus information about the bands - * and scheduling dimensions. - * In particular, we keep track of the number of bands and for each - * band, the starting position of the next band. The first band starts at - * position 0. - * For each scheduling dimension, we keep track of whether it satisfies - * the coincidence constraints (within its band). - */ -struct isl_schedule_node { - isl_multi_aff *sched; - int n_band; - int *band_end; - int *band_id; - int *coincident; -}; - -/* Information about the computed schedule. - * n is the number of nodes/domains/statements. - * n_band is the maximal number of bands. - * n_total_row is the number of coordinates of the schedule. - * dim contains a description of the parameters. +/* A complete schedule tree. + * * band_forest points to a band forest representation of the schedule * and may be NULL if the forest hasn't been created yet. + * + * "root" is the root of the schedule tree and may be NULL if we + * have created a band forest corresponding to the schedule. + * + * A pointer to "leaf" may be used to represent a leaf of the schedule. + * It should not appear as a child to any other isl_schedule_tree objects, + * but an isl_schedule_node may point to "leaf" if it refers to + * a leaf of this schedule tree. */ struct isl_schedule { int ref; - int n; - int n_band; - int n_total_row; - isl_space *dim; - isl_band_list *band_forest; + isl_schedule_tree *root; - struct isl_schedule_node node[1]; + struct isl_schedule_tree leaf; }; +__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx, + __isl_take isl_schedule_tree *tree); +__isl_give isl_schedule *isl_schedule_set_root( + __isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree); +__isl_give isl_space *isl_schedule_get_space( + __isl_keep isl_schedule *schedule); +__isl_give isl_union_set *isl_schedule_get_domain( + __isl_keep isl_schedule *schedule); +__isl_keep isl_schedule_tree *isl_schedule_peek_leaf( + __isl_keep isl_schedule *schedule); + #endif diff --git a/polly/lib/External/isl/isl_schedule_read.c b/polly/lib/External/isl/isl_schedule_read.c new file mode 100644 index 00000000000..95000aeca70 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_read.c @@ -0,0 +1,488 @@ +#include <string.h> + +#include <isl/schedule.h> +#include <isl/stream.h> +#include <isl_schedule_private.h> +#include <isl_schedule_tree.h> + +/* An enumeration of the various keys that may appear in a YAML mapping + * of a schedule. + */ +enum isl_schedule_key { + isl_schedule_key_error = -1, + isl_schedule_key_child, + isl_schedule_key_coincident, + isl_schedule_key_domain, + isl_schedule_key_filter, + isl_schedule_key_leaf, + isl_schedule_key_permutable, + isl_schedule_key_schedule, + isl_schedule_key_sequence, + isl_schedule_key_set +}; + +/* Extract a mapping key from the token "tok". + * Return isl_schedule_key_error on error, i.e., if "tok" does not + * correspond to any known key. + */ +static enum isl_schedule_key extract_key(__isl_keep isl_stream *s, + struct isl_token *tok) +{ + int type; + char *name; + enum isl_schedule_key key; + isl_ctx *ctx; + + ctx = isl_stream_get_ctx(s); + type = isl_token_get_type(tok); + if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) { + isl_stream_error(s, tok, "expecting key"); + return isl_schedule_key_error; + } + name = isl_token_get_str(ctx, tok); + if (!strcmp(name, "child")) + key = isl_schedule_key_child; + else if (!strcmp(name, "coincident")) + key = isl_schedule_key_coincident; + else if (!strcmp(name, "domain")) + key = isl_schedule_key_domain; + else if (!strcmp(name, "filter")) + key = isl_schedule_key_filter; + else if (!strcmp(name, "leaf")) + key = isl_schedule_key_leaf; + else if (!strcmp(name, "schedule")) + key = isl_schedule_key_schedule; + else if (!strcmp(name, "sequence")) + key = isl_schedule_key_sequence; + else if (!strcmp(name, "set")) + key = isl_schedule_key_set; + else if (!strcmp(name, "permutable")) + key = isl_schedule_key_permutable; + else + isl_die(ctx, isl_error_invalid, "unknown key", + key = isl_schedule_key_error); + free(name); + return key; +} + +/* Read a key from "s" and return the corresponding enum. + * Return isl_schedule_key_error on error, i.e., if the first token + * on the stream does not correspond to any known key. + */ +static enum isl_schedule_key get_key(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + enum isl_schedule_key key; + + tok = isl_stream_next_token(s); + key = extract_key(s, tok); + isl_token_free(tok); + + return key; +} + +static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( + __isl_keep isl_stream *s); + +/* Read a subtree with domain root node from "s". + */ +static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s) +{ + isl_union_set *domain = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + domain = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_domain(domain); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_domain(tree, domain); + } + + return tree; +error: + isl_union_set_free(domain); + return NULL; +} + +/* Read a subtree with filter root node from "s". + */ +static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s) +{ + isl_union_set *filter = NULL; + isl_schedule_tree *tree; + isl_ctx *ctx; + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + int more; + + ctx = isl_stream_get_ctx(s); + + key = get_key(s); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + str = isl_token_get_str(ctx, tok); + filter = isl_union_set_read_from_str(ctx, str); + free(str); + isl_token_free(tok); + + more = isl_stream_yaml_next(s); + if (more < 0) + goto error; + if (!more) { + tree = isl_schedule_tree_from_filter(filter); + } else { + key = get_key(s); + if (key != isl_schedule_key_child) + isl_die(ctx, isl_error_invalid, "expecting child", + goto error); + if (isl_stream_yaml_next(s) < 0) + goto error; + tree = isl_stream_read_schedule_tree(s); + tree = isl_schedule_tree_insert_filter(tree, filter); + } + + return tree; +error: + isl_union_set_free(filter); + return NULL; +} + +/* Read a sequence of integers from "s" (representing the coincident + * property of a band node). + */ +static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s) +{ + isl_ctx *ctx; + isl_val_list *list; + int more; + + ctx = isl_stream_get_ctx(s); + + if (isl_stream_yaml_read_start_sequence(s) < 0) + return NULL; + + list = isl_val_list_alloc(ctx, 0); + while ((more = isl_stream_yaml_next(s)) > 0) { + isl_val *val; + + val = isl_stream_read_val(s); + list = isl_val_list_add(list, val); + } + + if (more < 0 || isl_stream_yaml_read_end_sequence(s)) + list = isl_val_list_free(list); + + return list; +} + +/* Set the (initial) coincident properties of "band" according to + * the (initial) elements of "coincident". + */ +static __isl_give isl_schedule_band *set_coincident( + __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident) +{ + int i; + int n, m; + + n = isl_schedule_band_n_member(band); + m = isl_val_list_n_val(coincident); + + for (i = 0; i < n && i < m; ++i) { + isl_val *v; + + v = isl_val_list_get_val(coincident, i); + if (!v) + band = isl_schedule_band_free(band); + band = isl_schedule_band_member_set_coincident(band, i, + !isl_val_is_zero(v)); + isl_val_free(v); + } + isl_val_list_free(coincident); + return band; +} + +/* Read a subtree with band root node from "s". + */ +static __isl_give isl_schedule_tree *read_band(isl_stream *s) +{ + isl_multi_union_pw_aff *schedule = NULL; + isl_schedule_tree *tree = NULL; + isl_val_list *coincident = NULL; + isl_ctx *ctx; + isl_schedule_band *band; + int permutable = 0; + int more; + + ctx = isl_stream_get_ctx(s); + + do { + struct isl_token *tok; + enum isl_schedule_key key; + char *str; + isl_val *v; + + key = get_key(s); + if (isl_stream_yaml_next(s) < 0) + goto error; + + switch (key) { + case isl_schedule_key_schedule: + isl_multi_union_pw_aff_free(schedule); + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + goto error; + } + str = isl_token_get_str(ctx, tok); + schedule = isl_multi_union_pw_aff_read_from_str(ctx, + str); + free(str); + isl_token_free(tok); + if (!schedule) + goto error; + break; + case isl_schedule_key_coincident: + coincident = read_coincident(s); + if (!coincident) + goto error; + break; + case isl_schedule_key_permutable: + v = isl_stream_read_val(s); + permutable = !isl_val_is_zero(v); + isl_val_free(v); + break; + case isl_schedule_key_child: + isl_schedule_tree_free(tree); + tree = isl_stream_read_schedule_tree(s); + if (!tree) + goto error; + break; + default: + isl_die(ctx, isl_error_invalid, "unexpected key", + goto error); + } + } while ((more = isl_stream_yaml_next(s)) > 0); + + if (more < 0) + goto error; + + if (!schedule) + isl_die(ctx, isl_error_invalid, "missing schedule", goto error); + + band = isl_schedule_band_from_multi_union_pw_aff(schedule); + band = isl_schedule_band_set_permutable(band, permutable); + if (coincident) + band = set_coincident(band, coincident); + if (tree) + tree = isl_schedule_tree_insert_band(tree, band); + else + tree = isl_schedule_tree_from_band(band); + + return tree; +error: + isl_val_list_free(coincident); + isl_schedule_tree_free(tree); + isl_multi_union_pw_aff_free(schedule); + return NULL; +} + +/* Read a subtree with root node of type "type" from "s". + * The node is represented by a sequence of children. + */ +static __isl_give isl_schedule_tree *read_children(isl_stream *s, + enum isl_schedule_node_type type) +{ + isl_ctx *ctx; + isl_schedule_tree_list *list; + int more; + + ctx = isl_stream_get_ctx(s); + + isl_token_free(isl_stream_next_token(s)); + + if (isl_stream_yaml_next(s) < 0) + return NULL; + + if (isl_stream_yaml_read_start_sequence(s)) + return NULL; + + list = isl_schedule_tree_list_alloc(ctx, 0); + while ((more = isl_stream_yaml_next(s)) > 0) { + isl_schedule_tree *tree; + + tree = isl_stream_read_schedule_tree(s); + list = isl_schedule_tree_list_add(list, tree); + } + + if (more < 0 || isl_stream_yaml_read_end_sequence(s)) + list = isl_schedule_tree_list_free(list); + + return isl_schedule_tree_from_children(type, list); +} + +/* Read a subtree with sequence root node from "s". + */ +static __isl_give isl_schedule_tree *read_sequence(isl_stream *s) +{ + return read_children(s, isl_schedule_node_sequence); +} + +/* Read a subtree with set root node from "s". + */ +static __isl_give isl_schedule_tree *read_set(isl_stream *s) +{ + return read_children(s, isl_schedule_node_set); +} + +/* Read a schedule (sub)tree from "s". + * + * We first determine the type of the root node based on the first + * mapping key and then hand over to a function tailored to reading + * nodes of this type. + */ +static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( + struct isl_stream *s) +{ + enum isl_schedule_key key; + struct isl_token *tok; + isl_schedule_tree *tree = NULL; + int more; + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + more = isl_stream_yaml_next(s); + if (more < 0) + return NULL; + if (!more) { + isl_stream_error(s, NULL, "missing key"); + return NULL; + } + + tok = isl_stream_next_token(s); + key = extract_key(s, tok); + isl_stream_push_token(s, tok); + if (key < 0) + return NULL; + switch (key) { + case isl_schedule_key_domain: + tree = read_domain(s); + break; + case isl_schedule_key_filter: + tree = read_filter(s); + break; + case isl_schedule_key_leaf: + isl_token_free(isl_stream_next_token(s)); + tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s)); + break; + case isl_schedule_key_sequence: + tree = read_sequence(s); + break; + case isl_schedule_key_set: + tree = read_set(s); + break; + case isl_schedule_key_schedule: + case isl_schedule_key_coincident: + case isl_schedule_key_permutable: + tree = read_band(s); + break; + case isl_schedule_key_child: + isl_die(isl_stream_get_ctx(s), isl_error_unsupported, + "cannot identity node type", return NULL); + case isl_schedule_key_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) { + isl_stream_error(s, NULL, "unexpected extra elements"); + return isl_schedule_tree_free(tree); + } + + return tree; +} + +/* Read an isl_schedule from "s". + */ +__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!s) + return NULL; + + ctx = isl_stream_get_ctx(s); + tree = isl_stream_read_schedule_tree(s); + return isl_schedule_from_schedule_tree(ctx, tree); +} + +/* Read an isl_schedule from "input". + */ +__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input) +{ + struct isl_stream *s; + isl_schedule *schedule; + + s = isl_stream_new_file(ctx, input); + if (!s) + return NULL; + schedule = isl_stream_read_schedule(s); + isl_stream_free(s); + + return schedule; +} + +/* Read an isl_schedule from "str". + */ +__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx, + const char *str) +{ + struct isl_stream *s; + isl_schedule *schedule; + + s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + schedule = isl_stream_read_schedule(s); + isl_stream_free(s); + + return schedule; +} diff --git a/polly/lib/External/isl/isl_schedule_tree.c b/polly/lib/External/isl/isl_schedule_tree.c new file mode 100644 index 00000000000..fffcd308149 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_tree.c @@ -0,0 +1,1423 @@ +/* + * Copyright 2013 Ecole Normale Superieure + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + */ + +#include <isl/map.h> +#include <isl_schedule_band.h> +#include <isl_schedule_private.h> + +#undef EL +#define EL isl_schedule_tree + +#include <isl_list_templ.h> + +#undef BASE +#define BASE schedule_tree + +#include <isl_list_templ.c> + +/* Is "tree" the leaf of a schedule tree? + */ +int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree) +{ + return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf; +} + +/* Create a new schedule tree of type "type". + * The caller is responsible for filling in the type specific fields and + * the children. + */ +static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx, + enum isl_schedule_node_type type) +{ + isl_schedule_tree *tree; + + if (type == isl_schedule_node_error) + return NULL; + + tree = isl_calloc_type(ctx, isl_schedule_tree); + if (!tree) + return NULL; + + tree->ref = 1; + tree->ctx = ctx; + isl_ctx_ref(ctx); + tree->type = type; + + return tree; +} + +/* Return a fresh copy of "tree". + */ +__isl_take isl_schedule_tree *isl_schedule_tree_dup( + __isl_keep isl_schedule_tree *tree) +{ + isl_ctx *ctx; + isl_schedule_tree *dup; + + if (!tree) + return NULL; + + ctx = isl_schedule_tree_get_ctx(tree); + dup = isl_schedule_tree_alloc(ctx, tree->type); + if (!dup) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + isl_die(ctx, isl_error_internal, + "allocation should have failed", + isl_schedule_tree_free(dup)); + case isl_schedule_node_band: + dup->band = isl_schedule_band_copy(tree->band); + if (!dup->band) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_domain: + dup->domain = isl_union_set_copy(tree->domain); + if (!dup->domain) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_filter: + dup->filter = isl_union_set_copy(tree->filter); + if (!dup->filter) + return isl_schedule_tree_free(dup); + break; + case isl_schedule_node_leaf: + case isl_schedule_node_sequence: + case isl_schedule_node_set: + break; + } + + if (tree->children) { + dup->children = isl_schedule_tree_list_copy(tree->children); + if (!dup->children) + return isl_schedule_tree_free(dup); + } + + return dup; +} + +/* Return an isl_schedule_tree that is equal to "tree" and that has only + * a single reference. + * + * This function is called before a tree is modified. + * A static tree (with negative reference count) should never be modified, + * so it is not allowed to call this function on a static tree. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_cow( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->ref < 0) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "static trees cannot be modified", + return isl_schedule_tree_free(tree)); + + if (tree->ref == 1) + return tree; + tree->ref--; + return isl_schedule_tree_dup(tree); +} + +/* Return a new reference to "tree". + * + * A static tree (with negative reference count) does not keep track + * of the number of references and should not be modified. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_copy( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->ref < 0) + return tree; + + tree->ref++; + return tree; +} + +/* Free "tree" and return NULL. + */ +__isl_null isl_schedule_tree *isl_schedule_tree_free( + __isl_take isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + if (tree->ref < 0) + return NULL; + if (--tree->ref > 0) + return NULL; + + switch (tree->type) { + case isl_schedule_node_band: + isl_schedule_band_free(tree->band); + break; + case isl_schedule_node_domain: + isl_union_set_free(tree->domain); + break; + case isl_schedule_node_filter: + isl_union_set_free(tree->filter); + break; + case isl_schedule_node_sequence: + case isl_schedule_node_set: + case isl_schedule_node_error: + case isl_schedule_node_leaf: + break; + } + isl_schedule_tree_list_free(tree->children); + isl_ctx_deref(tree->ctx); + free(tree); + + return NULL; +} + +/* Create and return a new leaf schedule tree. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx) +{ + return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf); +} + +/* Create a new band schedule tree referring to "band" + * with no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_band( + __isl_take isl_schedule_band *band) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!band) + return NULL; + + ctx = isl_schedule_band_get_ctx(band); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band); + if (!tree) + goto error; + + tree->band = band; + + return tree; +error: + isl_schedule_band_free(band); + return NULL; +} + +/* Create a new domain schedule tree with the given domain and no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_domain( + __isl_take isl_union_set *domain) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!domain) + return NULL; + + ctx = isl_union_set_get_ctx(domain); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain); + if (!tree) + goto error; + + tree->domain = domain; + + return tree; +error: + isl_union_set_free(domain); + return NULL; +} + +/* Create a new filter schedule tree with the given filter and no children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_filter( + __isl_take isl_union_set *filter) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!filter) + return NULL; + + ctx = isl_union_set_get_ctx(filter); + tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter); + if (!tree) + goto error; + + tree->filter = filter; + + return tree; +error: + isl_union_set_free(filter); + return NULL; +} + +/* Create a new tree of the given type (isl_schedule_node_sequence or + * isl_schedule_node_set) with the given children. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_from_children( + enum isl_schedule_node_type type, + __isl_take isl_schedule_tree_list *list) +{ + isl_ctx *ctx; + isl_schedule_tree *tree; + + if (!list) + return NULL; + + ctx = isl_schedule_tree_list_get_ctx(list); + tree = isl_schedule_tree_alloc(ctx, type); + if (!tree) + goto error; + + tree->children = list; + + return tree; +error: + isl_schedule_tree_list_free(list); + return NULL; +} + +/* Return the isl_ctx to which "tree" belongs. + */ +isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree) +{ + return tree ? tree->ctx : NULL; +} + +/* Return the type of the root of the tree or isl_schedule_node_error + * on error. + */ +enum isl_schedule_node_type isl_schedule_tree_get_type( + __isl_keep isl_schedule_tree *tree) +{ + return tree ? tree->type : isl_schedule_node_error; +} + +/* Does "tree" have any children, other than an implicit leaf. + */ +int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + return tree->children != NULL; +} + +/* Return the number of children of "tree", excluding implicit leaves. + */ +int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + return isl_schedule_tree_list_n_schedule_tree(tree->children); +} + +/* Return a copy of the (explicit) child at position "pos" of "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_get_child( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return NULL; + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "schedule tree has no explicit children", return NULL); + return isl_schedule_tree_list_get_schedule_tree(tree->children, pos); +} + +/* Return a copy of the (explicit) child at position "pos" of "tree" and + * free "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_child( + __isl_take isl_schedule_tree *tree, int pos) +{ + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree, pos); + isl_schedule_tree_free(tree); + return child; +} + +/* Remove all (explicit) children from "tree". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_reset_children( + __isl_take isl_schedule_tree *tree) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + tree->children = isl_schedule_tree_list_free(tree->children); + return tree; +} + +/* Replace the child at position "pos" of "tree" by "child". + * + * If the new child is a leaf, then it is not explicitly + * recorded in the list of children. Instead, the list of children + * (which is assumed to have only one element) is removed. + * Note that the children of set and sequence nodes are always + * filters, so they cannot be replaced by empty trees. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_replace_child( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *child) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !child) + goto error; + + if (isl_schedule_tree_is_leaf(child)) { + isl_schedule_tree_free(child); + if (!tree->children && pos == 0) + return tree; + if (isl_schedule_tree_n_children(tree) != 1) + isl_die(isl_schedule_tree_get_ctx(tree), + isl_error_internal, + "can only replace single child by leaf", + goto error); + return isl_schedule_tree_reset_children(tree); + } + + if (!tree->children && pos == 0) + tree->children = + isl_schedule_tree_list_from_schedule_tree(child); + else + tree->children = isl_schedule_tree_list_set_schedule_tree( + tree->children, pos, child); + + if (!tree->children) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_schedule_tree_free(child); + return NULL; +} + +/* Replace the (explicit) children of "tree" by "children"? + */ +__isl_give isl_schedule_tree *isl_schedule_tree_set_children( + __isl_take isl_schedule_tree *tree, + __isl_take isl_schedule_tree_list *children) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !children) + goto error; + isl_schedule_tree_list_free(tree->children); + tree->children = children; + return tree; +error: + isl_schedule_tree_free(tree); + isl_schedule_tree_list_free(children); + return NULL; +} + +/* Create a new band schedule tree referring to "band" + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_band( + __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_band(band); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new domain schedule tree with the given domain and + * with "tree" as single child. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) +{ + isl_schedule_tree *res; + + res = isl_schedule_tree_from_domain(domain); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Create a new filter schedule tree with the given filter and single child. + * + * If the root of "tree" is itself a filter node, then the two + * filter nodes are merged into one node. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) +{ + isl_schedule_tree *res; + + if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) { + isl_union_set *tree_filter; + + tree_filter = isl_schedule_tree_filter_get_filter(tree); + tree_filter = isl_union_set_intersect(tree_filter, filter); + tree = isl_schedule_tree_filter_set_filter(tree, tree_filter); + return tree; + } + + res = isl_schedule_tree_from_filter(filter); + return isl_schedule_tree_replace_child(res, 0, tree); +} + +/* Return the number of members in the band tree root. + */ +unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return 0; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return 0); + + return isl_schedule_band_n_member(tree->band); +} + +/* Is the band member at position "pos" of the band tree root + * marked coincident? + */ +int isl_schedule_tree_band_member_get_coincident( + __isl_keep isl_schedule_tree *tree, int pos) +{ + if (!tree) + return -1; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return -1); + + return isl_schedule_band_member_get_coincident(tree->band, pos); +} + +/* Mark the given band member as being coincident or not + * according to "coincident". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident( + __isl_take isl_schedule_tree *tree, int pos, int coincident) +{ + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + if (isl_schedule_tree_band_member_get_coincident(tree, pos) == + coincident) + return tree; + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + tree->band = isl_schedule_band_member_set_coincident(tree->band, pos, + coincident); + if (!tree->band) + return isl_schedule_tree_free(tree); + return tree; +} + +/* Is the band tree root marked permutable? + */ +int isl_schedule_tree_band_get_permutable(__isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return -1; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return -1); + + return isl_schedule_band_get_permutable(tree->band); +} + +/* Mark the band tree root permutable or not according to "permutable"? + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable( + __isl_take isl_schedule_tree *tree, int permutable) +{ + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + if (isl_schedule_tree_band_get_permutable(tree) == permutable) + return tree; + tree = isl_schedule_tree_cow(tree); + if (!tree) + return NULL; + + tree->band = isl_schedule_band_set_permutable(tree->band, permutable); + if (!tree->band) + return isl_schedule_tree_free(tree); + return tree; +} + +/* Return the schedule space of the band tree root. + */ +__isl_give isl_space *isl_schedule_tree_band_get_space( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_space(tree->band); +} + +/* Return the schedule of the band tree root in isolation. + */ +__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return NULL); + + return isl_schedule_band_get_partial_schedule(tree->band); +} + +/* Return the domain of the domain tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_domain_get_domain( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_domain) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a domain node", return NULL); + + return isl_union_set_copy(tree->domain); +} + +/* Replace the domain of domain tree root "tree" by "domain". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !domain) + goto error; + + if (tree->type != isl_schedule_node_domain) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a domain node", goto error); + + isl_union_set_free(tree->domain); + tree->domain = domain; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(domain); + return NULL; +} + +/* Return the filter of the filter tree root. + */ +__isl_give isl_union_set *isl_schedule_tree_filter_get_filter( + __isl_keep isl_schedule_tree *tree) +{ + if (!tree) + return NULL; + + if (tree->type != isl_schedule_node_filter) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a filter node", return NULL); + + return isl_union_set_copy(tree->filter); +} + +/* Replace the filter of the filter tree root by "filter". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) +{ + tree = isl_schedule_tree_cow(tree); + if (!tree || !filter) + goto error; + + if (tree->type != isl_schedule_node_filter) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a filter node", return NULL); + + isl_union_set_free(tree->filter); + tree->filter = filter; + + return tree; +error: + isl_schedule_tree_free(tree); + isl_union_set_free(filter); + return NULL; +} + +/* Set dim to the range dimension of "map" and abort the search. + */ +static int set_range_dim(__isl_take isl_map *map, void *user) +{ + int *dim = user; + + *dim = isl_map_dim(map, isl_dim_out); + isl_map_free(map); + + return -1; +} + +/* Return the dimension of the range of "umap". + * "umap" is assumed not to be empty and + * all maps inside "umap" are assumed to have the same range. + * + * We extract the range dimension from the first map in "umap". + */ +static int range_dim(__isl_keep isl_union_map *umap) +{ + int dim = -1; + + if (!umap) + return -1; + if (isl_union_map_n_map(umap) == 0) + isl_die(isl_union_map_get_ctx(umap), isl_error_internal, + "unexpected empty input", return -1); + + isl_union_map_foreach_map(umap, &set_range_dim, &dim); + + return dim; +} + +/* Append an "extra" number of zeros to the range of "umap" and + * return the result. + */ +static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap, + int extra) +{ + isl_union_set *dom; + isl_space *space; + isl_multi_val *mv; + isl_union_pw_multi_aff *suffix; + isl_union_map *universe; + isl_union_map *suffix_umap; + + universe = isl_union_map_universe(isl_union_map_copy(umap)); + dom = isl_union_map_domain(universe); + space = isl_union_set_get_space(dom); + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, extra); + mv = isl_multi_val_zero(space); + + suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv); + suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix); + umap = isl_union_map_flat_range_product(umap, suffix_umap); + + return umap; +} + +/* Move down to the first descendant of "tree" that contains any schedule + * information or return "leaf" if there is no such descendant. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf) +{ + while (isl_schedule_tree_get_type(tree) == isl_schedule_node_band && + isl_schedule_tree_band_n_member(tree) == 0) { + if (!isl_schedule_tree_has_children(tree)) { + isl_schedule_tree_free(tree); + return isl_schedule_tree_copy(leaf); + } + tree = isl_schedule_tree_child(tree, 0); + } + + return tree; +} + +static __isl_give isl_union_map *subtree_schedule_extend( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer); + +/* Extend the schedule map "outer" with the subtree schedule + * of the (single) child of "tree", if any. + * + * If "tree" does not have any descendants (apart from those that + * do not carry any schedule information), then we simply return "outer". + * Otherwise, we extend the schedule map "outer" with the subtree schedule + * of the single child. + */ +static __isl_give isl_union_map *subtree_schedule_extend_child( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + isl_schedule_tree *child; + isl_union_map *res; + + if (!tree) + return isl_union_map_free(outer); + if (!isl_schedule_tree_has_children(tree)) + return outer; + child = isl_schedule_tree_get_child(tree, 0); + if (!child) + return isl_union_map_free(outer); + res = subtree_schedule_extend(child, outer); + isl_schedule_tree_free(child); + return res; +} + +/* Extract the parameter space from one of the children of "tree", + * which are assumed to be filters. + */ +static __isl_give isl_space *extract_space_from_filter_child( + __isl_keep isl_schedule_tree *tree) +{ + isl_space *space; + isl_union_set *dom; + isl_schedule_tree *child; + + child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0); + dom = isl_schedule_tree_filter_get_filter(child); + space = isl_union_set_get_space(dom); + isl_union_set_free(dom); + isl_schedule_tree_free(child); + + return space; +} + +/* Extend the schedule map "outer" with the subtree schedule + * of a set or sequence node. + * + * The schedule for the set or sequence node itself is composed of + * pieces of the form + * + * filter -> [] + * + * or + * + * filter -> [index] + * + * The first form is used if there is only a single child or + * if the current node is a set node and the schedule_separate_components + * option is not set. + * + * Each of the pieces above is extended with the subtree schedule of + * the child of the corresponding filter, if any, padded with zeros + * to ensure that all pieces have the same range dimension. + */ +static __isl_give isl_union_map *subtree_schedule_extend_from_children( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + int i, n; + int dim; + int separate; + isl_ctx *ctx; + isl_val *v = NULL; + isl_multi_val *mv; + isl_space *space; + isl_union_map *umap; + + if (!tree) + return NULL; + + ctx = isl_schedule_tree_get_ctx(tree); + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + if (n == 0) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + + separate = n > 1 && (tree->type == isl_schedule_node_sequence || + isl_options_get_schedule_separate_components(ctx)); + + space = extract_space_from_filter_child(tree); + + umap = isl_union_map_empty(isl_space_copy(space)); + space = isl_space_set_from_params(space); + if (separate) { + space = isl_space_add_dims(space, isl_dim_set, 1); + v = isl_val_zero(ctx); + } + mv = isl_multi_val_zero(space); + + dim = isl_multi_val_dim(mv, isl_dim_set); + for (i = 0; i < n; ++i) { + isl_union_pw_multi_aff *upma; + isl_union_map *umap_i; + isl_union_set *dom; + isl_schedule_tree *child; + int dim_i; + int empty; + + child = isl_schedule_tree_list_get_schedule_tree( + tree->children, i); + dom = isl_schedule_tree_filter_get_filter(child); + + if (separate) { + mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v)); + v = isl_val_add_ui(v, 1); + } + upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, + isl_multi_val_copy(mv)); + umap_i = isl_union_map_from_union_pw_multi_aff(upma); + umap_i = isl_union_map_flat_range_product( + isl_union_map_copy(outer), umap_i); + umap_i = subtree_schedule_extend_child(child, umap_i); + isl_schedule_tree_free(child); + + empty = isl_union_map_is_empty(umap_i); + if (empty < 0) + umap_i = isl_union_map_free(umap_i); + else if (empty) { + isl_union_map_free(umap_i); + continue; + } + + dim_i = range_dim(umap_i); + if (dim_i < 0) { + umap = isl_union_map_free(umap); + } else if (dim < dim_i) { + umap = append_range(umap, dim_i - dim); + dim = dim_i; + } else if (dim_i < dim) { + umap_i = append_range(umap_i, dim - dim_i); + } + umap = isl_union_map_union(umap, umap_i); + } + + isl_val_free(v); + isl_multi_val_free(mv); + isl_union_map_free(outer); + + return umap; +} + +/* Extend the schedule map "outer" with the subtree schedule of "tree". + * + * If the root of the tree is a set or a sequence, then we extend + * the schedule map in subtree_schedule_extend_from_children. + * Otherwise, we extend the schedule map with the partial schedule + * corresponding to the root of the tree and then continue with + * the single child of this root. + */ +static __isl_give isl_union_map *subtree_schedule_extend( + __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) +{ + isl_multi_union_pw_aff *mupa; + isl_union_map *umap; + isl_union_set *domain; + + if (!tree) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + return isl_union_map_free(outer); + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + return subtree_schedule_extend_child(tree, outer); + mupa = isl_schedule_band_get_partial_schedule(tree->band); + umap = isl_union_map_from_multi_union_pw_aff(mupa); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_domain: + domain = isl_schedule_tree_domain_get_domain(tree); + umap = isl_union_map_from_domain(domain); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_filter: + domain = isl_schedule_tree_filter_get_filter(tree); + umap = isl_union_map_from_domain(domain); + outer = isl_union_map_flat_range_product(outer, umap); + umap = subtree_schedule_extend_child(tree, outer); + break; + case isl_schedule_node_leaf: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "leaf node should be handled by caller", return NULL); + case isl_schedule_node_set: + case isl_schedule_node_sequence: + umap = subtree_schedule_extend_from_children(tree, outer); + break; + } + + return umap; +} + +static __isl_give isl_union_set *initial_domain( + __isl_keep isl_schedule_tree *tree); + +/* Extract a universe domain from the children of the tree root "tree", + * which is a set or sequence, meaning that its children are filters. + * In particular, return the union of the universes of the filters. + */ +static __isl_give isl_union_set *initial_domain_from_children( + __isl_keep isl_schedule_tree *tree) +{ + int i, n; + isl_space *space; + isl_union_set *domain; + + if (!tree->children) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + if (n == 0) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "missing children", return NULL); + + space = extract_space_from_filter_child(tree); + domain = isl_union_set_empty(space); + + for (i = 0; i < n; ++i) { + isl_schedule_tree *child; + isl_union_set *domain_i; + + child = isl_schedule_tree_get_child(tree, i); + domain_i = initial_domain(child); + domain = isl_union_set_union(domain, domain_i); + isl_schedule_tree_free(child); + } + + return domain; +} + +/* Extract a universe domain from the tree root "tree". + * The caller is responsible for making sure that this node + * would not be skipped by isl_schedule_tree_first_schedule_descendant + * and that it is not a leaf node. + */ +static __isl_give isl_union_set *initial_domain( + __isl_keep isl_schedule_tree *tree) +{ + isl_multi_union_pw_aff *mupa; + isl_union_set *domain; + + if (!tree) + return NULL; + + switch (tree->type) { + case isl_schedule_node_error: + return NULL; + case isl_schedule_node_band: + if (isl_schedule_tree_band_n_member(tree) == 0) + isl_die(isl_schedule_tree_get_ctx(tree), + isl_error_internal, + "0D band should be handled by caller", + return NULL); + mupa = isl_schedule_band_get_partial_schedule(tree->band); + domain = isl_multi_union_pw_aff_domain(mupa); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_domain: + domain = isl_schedule_tree_domain_get_domain(tree); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_filter: + domain = isl_schedule_tree_filter_get_filter(tree); + domain = isl_union_set_universe(domain); + break; + case isl_schedule_node_leaf: + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, + "leaf node should be handled by caller", return NULL); + case isl_schedule_node_set: + case isl_schedule_node_sequence: + domain = initial_domain_from_children(tree); + break; + } + + return domain; +} + +/* Return the subtree schedule of a node that contains some schedule + * information, i.e., a node that would not be skipped by + * isl_schedule_tree_first_schedule_descendant and that is not a leaf. + * + * We start with an initial zero-dimensional subtree schedule based + * on the domain information in the root node and then extend it + * based on the schedule information in the root node and its descendants. + */ +__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map( + __isl_keep isl_schedule_tree *tree) +{ + isl_union_set *domain; + isl_union_map *umap; + + domain = initial_domain(tree); + umap = isl_union_map_from_domain(domain); + return subtree_schedule_extend(tree, umap); +} + +/* Multiply the partial schedule of the band root node of "tree" + * with the factors in "mv". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) +{ + if (!tree || !mv) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_scale(tree->band, mv); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_val_free(mv); + return NULL; +} + +/* Divide the partial schedule of the band root node of "tree" + * by the factors in "mv". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) +{ + if (!tree || !mv) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + tree = isl_schedule_tree_cow(tree); + if (!tree) + goto error; + + tree->band = isl_schedule_band_scale_down(tree->band, mv); + if (!tree->band) + return isl_schedule_tree_free(tree); + + return tree; +error: + isl_schedule_tree_free(tree); + isl_multi_val_free(mv); + return NULL; +} + +/* Tile the band root node of "tree" with tile sizes "sizes". + * + * We duplicate the band node, change the schedule of one of them + * to the tile schedule and the other to the point schedule and then + * attach the point band as a child to the tile band. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_tile( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes) +{ + isl_schedule_tree *child = NULL; + + if (!tree || !sizes) + goto error; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", goto error); + + child = isl_schedule_tree_copy(tree); + tree = isl_schedule_tree_cow(tree); + child = isl_schedule_tree_cow(child); + if (!tree || !child) + goto error; + + tree->band = isl_schedule_band_tile(tree->band, + isl_multi_val_copy(sizes)); + if (!tree->band) + goto error; + child->band = isl_schedule_band_point(child->band, tree->band, sizes); + if (!child->band) + child = isl_schedule_tree_free(child); + + tree = isl_schedule_tree_replace_child(tree, 0, child); + + return tree; +error: + isl_schedule_tree_free(child); + isl_schedule_tree_free(tree); + isl_multi_val_free(sizes); + return NULL; +} + +/* Split the band root node of "tree" into two nested band nodes, + * one with the first "pos" dimensions and + * one with the remaining dimensions. + */ +__isl_give isl_schedule_tree *isl_schedule_tree_band_split( + __isl_take isl_schedule_tree *tree, int pos) +{ + int n; + isl_schedule_tree *child; + + if (!tree) + return NULL; + if (tree->type != isl_schedule_node_band) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "not a band node", return isl_schedule_tree_free(tree)); + + n = isl_schedule_tree_band_n_member(tree); + if (pos < 0 || pos > n) + isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, + "position out of bounds", + return isl_schedule_tree_free(tree)); + + child = isl_schedule_tree_copy(tree); + tree = isl_schedule_tree_cow(tree); + child = isl_schedule_tree_cow(child); + if (!tree || !child) + goto error; + + child->band = isl_schedule_band_drop(child->band, 0, pos); + tree->band = isl_schedule_band_drop(tree->band, pos, n - pos); + if (!child->band || !tree->band) + goto error; + + tree = isl_schedule_tree_replace_child(tree, 0, child); + + return tree; +error: + isl_schedule_tree_free(child); + isl_schedule_tree_free(tree); + return NULL; +} + +/* Attach "tree2" at each of the leaves of "tree1". + * + * If "tree1" does not have any explicit children, then make "tree2" + * its single child. Otherwise, attach "tree2" to the leaves of + * each of the children of "tree1". + */ +__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2) +{ + int i, n; + + if (!tree1 || !tree2) + goto error; + n = isl_schedule_tree_n_children(tree1); + if (n == 0) { + isl_schedule_tree_list *list; + list = isl_schedule_tree_list_from_schedule_tree(tree2); + tree1 = isl_schedule_tree_set_children(tree1, list); + return tree1; + } + for (i = 0; i < n; ++i) { + isl_schedule_tree *child; + + child = isl_schedule_tree_get_child(tree1, i); + child = isl_schedule_tree_append_to_leaves(child, + isl_schedule_tree_copy(tree2)); + tree1 = isl_schedule_tree_replace_child(tree1, i, child); + } + + isl_schedule_tree_free(tree2); + return tree1; +error: + isl_schedule_tree_free(tree1); + isl_schedule_tree_free(tree2); + return NULL; +} + +/* Are any members in "band" marked coincident? + */ +static int any_coincident(__isl_keep isl_schedule_band *band) +{ + int i, n; + + n = isl_schedule_band_n_member(band); + for (i = 0; i < n; ++i) + if (isl_schedule_band_member_get_coincident(band, i)) + return 1; + + return 0; +} + +/* Print the band node "band" to "p". + * + * The permutable and coincident properties are only printed if they + * are different from the defaults. + * The coincident property is always printed in YAML flow style. + */ +static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p, + __isl_keep isl_schedule_band *band) +{ + p = isl_printer_print_str(p, "schedule"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_multi_union_pw_aff(p, band->mupa); + p = isl_printer_print_str(p, "\""); + if (isl_schedule_band_get_permutable(band)) { + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "permutable"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_int(p, 1); + } + if (any_coincident(band)) { + int i, n; + int style; + + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "coincident"); + p = isl_printer_yaml_next(p); + style = isl_printer_get_yaml_style(p); + p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); + p = isl_printer_yaml_start_sequence(p); + n = isl_schedule_band_n_member(band); + for (i = 0; i < n; ++i) { + p = isl_printer_print_int(p, + isl_schedule_band_member_get_coincident(band, i)); + p = isl_printer_yaml_next(p); + } + p = isl_printer_yaml_end_sequence(p); + p = isl_printer_set_yaml_style(p, style); + } + + return p; +} + +/* Print "tree" to "p". + * + * If "n_ancestor" is non-negative, then "child_pos" contains the child + * positions of a descendant of the current node that should be marked + * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor" + * is zero, then the current node should be marked. + * The marking is only printed in YAML block format. + * + * Implicit leaf nodes are not printed, except if they correspond + * to the node that should be marked. + */ +__isl_give isl_printer *isl_printer_print_schedule_tree_mark( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree, + int n_ancestor, int *child_pos) +{ + int i, n; + int sequence = 0; + int block; + + block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK; + + p = isl_printer_yaml_start_mapping(p); + if (n_ancestor == 0 && block) { + p = isl_printer_print_str(p, "# YOU ARE HERE"); + p = isl_printer_end_line(p); + p = isl_printer_start_line(p); + } + switch (tree->type) { + case isl_schedule_node_error: + p = isl_printer_print_str(p, "ERROR"); + break; + case isl_schedule_node_leaf: + p = isl_printer_print_str(p, "leaf"); + break; + case isl_schedule_node_sequence: + p = isl_printer_print_str(p, "sequence"); + sequence = 1; + break; + case isl_schedule_node_set: + p = isl_printer_print_str(p, "set"); + sequence = 1; + break; + case isl_schedule_node_domain: + p = isl_printer_print_str(p, "domain"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, tree->domain); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_filter: + p = isl_printer_print_str(p, "filter"); + p = isl_printer_yaml_next(p); + p = isl_printer_print_str(p, "\""); + p = isl_printer_print_union_set(p, tree->filter); + p = isl_printer_print_str(p, "\""); + break; + case isl_schedule_node_band: + p = print_tree_band(p, tree->band); + break; + } + p = isl_printer_yaml_next(p); + + if (!tree->children) { + if (n_ancestor > 0 && block) { + isl_schedule_tree *leaf; + + p = isl_printer_print_str(p, "child"); + p = isl_printer_yaml_next(p); + leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p)); + p = isl_printer_print_schedule_tree_mark(p, + leaf, 0, NULL); + isl_schedule_tree_free(leaf); + p = isl_printer_yaml_next(p); + } + return isl_printer_yaml_end_mapping(p); + } + + if (sequence) { + p = isl_printer_yaml_start_sequence(p); + } else { + p = isl_printer_print_str(p, "child"); + p = isl_printer_yaml_next(p); + } + + n = isl_schedule_tree_list_n_schedule_tree(tree->children); + for (i = 0; i < n; ++i) { + isl_schedule_tree *t; + + t = isl_schedule_tree_get_child(tree, i); + if (n_ancestor > 0 && child_pos[0] == i) + p = isl_printer_print_schedule_tree_mark(p, t, + n_ancestor - 1, child_pos + 1); + else + p = isl_printer_print_schedule_tree_mark(p, t, + -1, NULL); + isl_schedule_tree_free(t); + + p = isl_printer_yaml_next(p); + } + + if (sequence) + p = isl_printer_yaml_end_sequence(p); + p = isl_printer_yaml_end_mapping(p); + + return p; +} + +/* Print "tree" to "p". + */ +__isl_give isl_printer *isl_printer_print_schedule_tree( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree) +{ + return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL); +} + +void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree) +{ + isl_ctx *ctx; + isl_printer *printer; + + if (!tree) + return; + + ctx = isl_schedule_tree_get_ctx(tree); + printer = isl_printer_to_file(ctx, stderr); + printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); + printer = isl_printer_print_schedule_tree(printer, tree); + + isl_printer_free(printer); +} diff --git a/polly/lib/External/isl/isl_schedule_tree.h b/polly/lib/External/isl/isl_schedule_tree.h new file mode 100644 index 00000000000..34a439b0183 --- /dev/null +++ b/polly/lib/External/isl/isl_schedule_tree.h @@ -0,0 +1,134 @@ +#ifndef ISL_SCHEDLUE_TREE_H +#define ISL_SCHEDLUE_TREE_H + +#include <isl_schedule_band.h> +#include <isl/schedule.h> +#include <isl/set.h> +#include <isl/union_set.h> + +struct isl_schedule_tree; +typedef struct isl_schedule_tree isl_schedule_tree; + +ISL_DECLARE_LIST(schedule_tree) + +/* A schedule (sub)tree. + * + * The leaves of a tree are not explicitly represented inside + * the isl_schedule_tree. If a tree consists of only a leaf, + * then it is equal to the static object isl_schedule_tree_empty. + * + * ctx may be NULL if type is isl_schedule_node_leaf. + * In this case, ref has a negative value. + * + * The "band" field is valid when type is isl_schedule_node_band. + * The "domain" field is valid when type is isl_schedule_node_domain + * and introduces the statement instances scheduled by the tree. + * The "filter" field is valid when type is isl_schedule_node_filter + * and represents the statement instances selected by the node. + * + * The "children" field is valid for all types except + * isl_schedule_node_leaf. This field is NULL if there are + * no children (except for the implicit leaves). + */ +struct isl_schedule_tree { + int ref; + isl_ctx *ctx; + enum isl_schedule_node_type type; + union { + isl_schedule_band *band; + isl_union_set *domain; + isl_union_set *filter; + }; + isl_schedule_tree_list *children; +}; + +isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree); +enum isl_schedule_node_type isl_schedule_tree_get_type( + __isl_keep isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx); +int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_copy( + __isl_keep isl_schedule_tree *tree); +__isl_null isl_schedule_tree *isl_schedule_tree_free( + __isl_take isl_schedule_tree *tree); + +__isl_give isl_schedule_tree *isl_schedule_tree_from_band( + __isl_take isl_schedule_band *band); +__isl_give isl_schedule_tree *isl_schedule_tree_from_domain( + __isl_take isl_union_set *domain); +__isl_give isl_schedule_tree *isl_schedule_tree_from_filter( + __isl_take isl_union_set *filter); +__isl_give isl_schedule_tree *isl_schedule_tree_from_children( + enum isl_schedule_node_type type, + __isl_take isl_schedule_tree_list *list); + +__isl_give isl_space *isl_schedule_tree_band_get_space( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_union_set *isl_schedule_tree_domain_get_domain( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain); +__isl_give isl_union_set *isl_schedule_tree_filter_get_filter( + __isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter); + +__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant( + __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf); +__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map( + __isl_keep isl_schedule_tree *tree); + +unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree); + +int isl_schedule_tree_band_member_get_coincident( + __isl_keep isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident( + __isl_take isl_schedule_tree *tree, int pos, int coincident); +int isl_schedule_tree_band_get_permutable(__isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable( + __isl_take isl_schedule_tree *tree, int permutable); + +int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree); +int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_get_child( + __isl_keep isl_schedule_tree *tree, int pos); + +__isl_give isl_schedule_tree *isl_schedule_tree_insert_band( + __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain); +__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter( + __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter); + +__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves( + __isl_take isl_schedule_tree *tree1, + __isl_take isl_schedule_tree *tree2); + +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv); +__isl_give isl_schedule_tree *isl_schedule_tree_band_tile( + __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes); +__isl_give isl_schedule_tree *isl_schedule_tree_band_split( + __isl_take isl_schedule_tree *tree, int pos); + +__isl_give isl_schedule_tree *isl_schedule_tree_child( + __isl_take isl_schedule_tree *tree, int pos); +__isl_give isl_schedule_tree *isl_schedule_tree_reset_children( + __isl_take isl_schedule_tree *tree); +__isl_give isl_schedule_tree *isl_schedule_tree_replace_child( + __isl_take isl_schedule_tree *tree, int pos, + __isl_take isl_schedule_tree *new_child); + +__isl_give isl_printer *isl_printer_print_schedule_tree( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree); +__isl_give isl_printer *isl_printer_print_schedule_tree_mark( + __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree, + int n_ancestor, int *child_pos); + +#endif diff --git a/polly/lib/External/isl/isl_scheduler.c b/polly/lib/External/isl/isl_scheduler.c index 4a7428045e0..c552f51c6b4 100644 --- a/polly/lib/External/isl/isl_scheduler.c +++ b/polly/lib/External/isl/isl_scheduler.c @@ -17,6 +17,7 @@ #include <isl/hash.h> #include <isl/constraint.h> #include <isl/schedule.h> +#include <isl/schedule_node.h> #include <isl_mat_private.h> #include <isl_vec_private.h> #include <isl/set.h> @@ -25,7 +26,6 @@ #include <isl_dim_map.h> #include <isl/map_to_basic_set.h> #include <isl_sort.h> -#include <isl_schedule_private.h> #include <isl_options_private.h> #include <isl_tarjan.h> #include <isl_morph.h> @@ -48,6 +48,8 @@ enum isl_edge_type { /* The constraints that need to be satisfied by a schedule on "domain". * + * "context" specifies extra constraints on the parameters. + * * "validity" constraints map domain elements i to domain elements * that should be scheduled after i. (Hard constraint) * "proximity" constraints map domain elements i to domains elements @@ -67,6 +69,7 @@ enum isl_edge_type { */ struct isl_schedule_constraints { isl_union_set *domain; + isl_set *context; isl_union_map *constraint[isl_edge_last + 1]; }; @@ -84,7 +87,8 @@ struct isl_schedule_constraints { return NULL; sc_copy->domain = isl_union_set_copy(sc->domain); - if (!sc_copy->domain) + sc_copy->context = isl_set_copy(sc->context); + if (!sc_copy->domain || !sc_copy->context) return isl_schedule_constraints_free(sc_copy); for (i = isl_edge_first; i <= isl_edge_last; ++i) { @@ -119,6 +123,7 @@ __isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain( space = isl_union_set_get_space(domain); sc->domain = domain; + sc->context = isl_set_universe(isl_space_copy(space)); empty = isl_union_map_empty(space); for (i = isl_edge_first; i <= isl_edge_last; ++i) { sc->constraint[i] = isl_union_map_copy(empty); @@ -127,7 +132,7 @@ __isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain( } isl_union_map_free(empty); - if (!sc->domain) + if (!sc->domain || !sc->context) return isl_schedule_constraints_free(sc); return sc; @@ -136,6 +141,24 @@ error: return NULL; } +/* Replace the context of "sc" by "context". + */ +__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context( + __isl_take isl_schedule_constraints *sc, __isl_take isl_set *context) +{ + if (!sc || !context) + goto error; + + isl_set_free(sc->context); + sc->context = context; + + return sc; +error: + isl_schedule_constraints_free(sc); + isl_set_free(context); + return NULL; +} + /* Replace the validity constraints of "sc" by "validity". */ __isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity( @@ -227,6 +250,7 @@ __isl_null isl_schedule_constraints *isl_schedule_constraints_free( return NULL; isl_union_set_free(sc->domain); + isl_set_free(sc->context); for (i = isl_edge_first; i <= isl_edge_last; ++i) isl_union_map_free(sc->constraint[i]); @@ -248,6 +272,8 @@ void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc) fprintf(stderr, "domain: "); isl_union_set_dump(sc->domain); + fprintf(stderr, "context: "); + isl_set_dump(sc->context); fprintf(stderr, "validity: "); isl_union_map_dump(sc->constraint[isl_edge_validity]); fprintf(stderr, "proximity: "); @@ -272,6 +298,7 @@ isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc) return NULL; space = isl_union_set_get_space(sc->domain); + space = isl_space_align_params(space, isl_set_get_space(sc->context)); for (i = isl_edge_first; i <= isl_edge_last; ++i) space = isl_space_align_params(space, isl_union_map_get_space(sc->constraint[i])); @@ -282,8 +309,9 @@ isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc) if (!sc->constraint[i]) space = isl_space_free(space); } + sc->context = isl_set_align_params(sc->context, isl_space_copy(space)); sc->domain = isl_union_set_align_params(sc->domain, space); - if (!sc->domain) + if (!sc->context || !sc->domain) return isl_schedule_constraints_free(sc); return sc; @@ -331,10 +359,6 @@ static __isl_give int isl_schedule_constraints_n_map( * * scc is the index of SCC (or WCC) this node belongs to * - * band contains the band index for each of the rows of the schedule. - * band_id is used to differentiate between separate bands at the same - * level within the same parent band, i.e., bands that are separated - * by the parent band or bands that are independent of each other. * coincident contains a boolean for each of the rows of the schedule, * indicating whether the corresponding scheduling dimension satisfies * the coincidence constraints in the sense that the corresponding @@ -357,8 +381,6 @@ struct isl_sched_node { int scc; - int *band; - int *band_id; int *coincident; }; @@ -370,6 +392,21 @@ static int node_has_space(const void *entry, const void *val) return isl_space_is_equal(node->space, dim); } +static int node_scc_exactly(struct isl_sched_node *node, int scc) +{ + return node->scc == scc; +} + +static int node_scc_at_most(struct isl_sched_node *node, int scc) +{ + return node->scc <= scc; +} + +static int node_scc_at_least(struct isl_sched_node *node, int scc) +{ + return node->scc >= scc; +} + /* An edge in the dependence graph. An edge may be used to * ensure validity of the generated schedule, to minimize the dependence * distance or both @@ -434,7 +471,6 @@ struct isl_sched_edge { * n_row is the current (maximal) number of linearly independent * rows in the node schedules * n_total_row is the current number of rows in the node schedules - * n_band is the current number of completed bands * band_start is the starting row in the node schedules of the current band * root is set if this graph is the original dependence graph, * without any splitting @@ -462,6 +498,7 @@ struct isl_sched_edge { * conflicting constraints * * scc represents the number of components + * weak is set if the components are weakly connected */ struct isl_sched_graph { isl_map_to_basic_set *intra_hmap; @@ -475,7 +512,6 @@ struct isl_sched_graph { int *sorted; - int n_band; int n_total_row; int band_start; @@ -495,6 +531,7 @@ struct isl_sched_graph { int dst_scc; int scc; + int weak; }; /* Initialize node_table based on the list of nodes. @@ -775,11 +812,8 @@ static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph) isl_map_free(graph->node[i].sched_map); isl_mat_free(graph->node[i].cmap); isl_mat_free(graph->node[i].cinv); - if (graph->root) { - free(graph->node[i].band); - free(graph->node[i].band_id); + if (graph->root) free(graph->node[i].coincident); - } } free(graph->node); free(graph->sorted); @@ -827,15 +861,10 @@ static int add_n_basic_map(__isl_take isl_map *map, void *user) } /* Compute the number of rows that should be allocated for the schedule. - * The graph can be split at most "n - 1" times, there can be at most - * one row for each dimension in the iteration domains plus two rows - * for each basic map in the dependences (in particular, - * we usually have one row, but it may be split by split_scaled), - * and there can be one extra row for ordering the statements. - * Note that if we have actually split "n - 1" times, then no ordering - * is needed, so in principle we could use "graph->n + 2 * graph->maxvar - 1". - * It is also practically impossible to exhaust both the number of dependences - * and the number of variables. + * In particular, we need one row for each variable or one row + * for each basic map in the dependences. + * Note that it is practically impossible to exhaust both + * the number of dependences and the number of variables. */ static int compute_max_row(struct isl_sched_graph *graph, __isl_keep isl_schedule_constraints *sc) @@ -852,7 +881,7 @@ static int compute_max_row(struct isl_sched_graph *graph, if (isl_union_map_foreach_map(sc->constraint[i], &add_n_basic_map, &n_edge) < 0) return -1; - graph->max_row = graph->n + 2 * n_edge + graph->maxvar; + graph->max_row = n_edge + graph->maxvar; return 0; } @@ -898,7 +927,7 @@ static int add_node(struct isl_sched_graph *graph, __isl_take isl_space *space, int nparam; isl_ctx *ctx; isl_mat *sched; - int *band, *band_id, *coincident; + int *coincident; if (!space) return -1; @@ -913,10 +942,6 @@ static int add_node(struct isl_sched_graph *graph, __isl_take isl_space *space, graph->node[graph->n].nparam = nparam; graph->node[graph->n].sched = sched; graph->node[graph->n].sched_map = NULL; - band = isl_alloc_array(ctx, int, graph->max_row); - graph->node[graph->n].band = band; - band_id = isl_calloc_array(ctx, int, graph->max_row); - graph->node[graph->n].band_id = band_id; coincident = isl_calloc_array(ctx, int, graph->max_row); graph->node[graph->n].coincident = coincident; graph->node[graph->n].compressed = compressed; @@ -925,8 +950,7 @@ static int add_node(struct isl_sched_graph *graph, __isl_take isl_space *space, graph->node[graph->n].decompress = decompress; graph->n++; - if (!space || !sched || - (graph->max_row && (!band || !band_id || !coincident))) + if (!space || !sched || (graph->max_row && !coincident)) return -1; if (compressed && (!hull || !compress || !decompress)) return -1; @@ -1247,6 +1271,7 @@ static int detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, int weak) if (!g) return -1; + graph->weak = weak; graph->scc = 0; i = 0; n = graph->n; @@ -2281,7 +2306,6 @@ static int update_schedule(struct isl_sched_graph *graph, for (j = 0; j < node->nvar; ++j) node->sched = isl_mat_set_element(node->sched, row, 1 + node->nparam + j, csol->el[j]); - node->band[graph->n_total_row] = graph->n_band; node->coincident[graph->n_total_row] = coincident; } isl_vec_free(sol); @@ -2326,12 +2350,13 @@ static __isl_give isl_aff *extract_schedule_row(__isl_take isl_local_space *ls, return aff; } -/* Convert node->sched into a multi_aff and return this multi_aff. +/* Convert the "n" rows starting at "first" of node->sched into a multi_aff + * and return this multi_aff. * * The result is defined over the uncompressed node domain. */ -static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( - struct isl_sched_node *node) +static __isl_give isl_multi_aff *node_extract_partial_schedule_multi_aff( + struct isl_sched_node *node, int first, int n) { int i; isl_space *space; @@ -2348,12 +2373,12 @@ static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( space = isl_space_copy(node->space); ls = isl_local_space_from_space(isl_space_copy(space)); space = isl_space_from_domain(space); - space = isl_space_add_dims(space, isl_dim_out, nrow); + space = isl_space_add_dims(space, isl_dim_out, n); ma = isl_multi_aff_zero(space); - for (i = 0; i < nrow; ++i) { + for (i = first; i < first + n; ++i) { aff = extract_schedule_row(isl_local_space_copy(ls), node, i); - ma = isl_multi_aff_set_aff(ma, i, aff); + ma = isl_multi_aff_set_aff(ma, i - first, aff); } isl_local_space_free(ls); @@ -2365,6 +2390,19 @@ static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( return ma; } +/* Convert node->sched into a multi_aff and return this multi_aff. + * + * The result is defined over the uncompressed node domain. + */ +static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( + struct isl_sched_node *node) +{ + int nrow; + + nrow = isl_mat_rows(node->sched); + return node_extract_partial_schedule_multi_aff(node, 0, nrow); +} + /* Convert node->sched into a map and return this map. * * The result is cached in node->sched_map, which needs to be released @@ -2472,126 +2510,115 @@ static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph) static void next_band(struct isl_sched_graph *graph) { graph->band_start = graph->n_total_row; - graph->n_band++; } -/* Topologically sort statements mapped to the same schedule iteration - * and add a row to the schedule corresponding to this order. +/* Return the union of the universe domains of the nodes in "graph" + * that satisfy "pred". */ -static int sort_statements(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_union_set *isl_sched_graph_domain(isl_ctx *ctx, + struct isl_sched_graph *graph, + int (*pred)(struct isl_sched_node *node, int data), int data) { - int i, j; + int i; + isl_set *set; + isl_union_set *dom; - if (graph->n <= 1) - return 0; + for (i = 0; i < graph->n; ++i) + if (pred(&graph->node[i], data)) + break; - if (update_edges(ctx, graph) < 0) - return -1; + if (i >= graph->n) + isl_die(ctx, isl_error_internal, + "empty component", return NULL); - if (graph->n_edge == 0) - return 0; + set = isl_set_universe(isl_space_copy(graph->node[i].space)); + dom = isl_union_set_from_set(set); - if (detect_sccs(ctx, graph) < 0) - return -1; + for (i = i + 1; i < graph->n; ++i) { + if (!pred(&graph->node[i], data)) + continue; + set = isl_set_universe(isl_space_copy(graph->node[i].space)); + dom = isl_union_set_union(dom, isl_union_set_from_set(set)); + } - if (graph->n_total_row >= graph->max_row) - isl_die(ctx, isl_error_internal, - "too many schedule rows", return -1); + return dom; +} - for (i = 0; i < graph->n; ++i) { - struct isl_sched_node *node = &graph->node[i]; - int row = isl_mat_rows(node->sched); - int cols = isl_mat_cols(node->sched); +/* Return a list of unions of universe domains, where each element + * in the list corresponds to an SCC (or WCC) indexed by node->scc. + */ +static __isl_give isl_union_set_list *extract_sccs(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + int i; + isl_union_set_list *filters; - isl_map_free(node->sched_map); - node->sched_map = NULL; - node->sched = isl_mat_add_rows(node->sched, 1); - if (!node->sched) - return -1; - node->sched = isl_mat_set_element_si(node->sched, row, 0, - node->scc); - for (j = 1; j < cols; ++j) - node->sched = isl_mat_set_element_si(node->sched, - row, j, 0); - node->band[graph->n_total_row] = graph->n_band; + filters = isl_union_set_list_alloc(ctx, graph->scc); + for (i = 0; i < graph->scc; ++i) { + isl_union_set *dom; + + dom = isl_sched_graph_domain(ctx, graph, &node_scc_exactly, i); + filters = isl_union_set_list_add(filters, dom); } - graph->n_total_row++; - next_band(graph); + return filters; +} - return 0; +/* Return a list of two unions of universe domains, one for the SCCs up + * to and including graph->src_scc and another for the other SCCS. + */ +static __isl_give isl_union_set_list *extract_split(isl_ctx *ctx, + struct isl_sched_graph *graph) +{ + isl_union_set *dom; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(ctx, 2); + dom = isl_sched_graph_domain(ctx, graph, + &node_scc_at_most, graph->src_scc); + filters = isl_union_set_list_add(filters, dom); + dom = isl_sched_graph_domain(ctx, graph, + &node_scc_at_least, graph->src_scc + 1); + filters = isl_union_set_list_add(filters, dom); + + return filters; } -/* Construct an isl_schedule based on the computed schedule stored - * in graph and with parameters specified by dim. +/* Topologically sort statements mapped to the same schedule iteration + * and add insert a sequence node in front of "node" + * corresponding to this order. */ -static __isl_give isl_schedule *extract_schedule(struct isl_sched_graph *graph, - __isl_take isl_space *dim) +static __isl_give isl_schedule_node *sort_statements( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) { - int i; isl_ctx *ctx; - isl_schedule *sched = NULL; + isl_union_set_list *filters; - if (!dim) + if (!node) return NULL; - ctx = isl_space_get_ctx(dim); - sched = isl_calloc(ctx, struct isl_schedule, - sizeof(struct isl_schedule) + - (graph->n - 1) * sizeof(struct isl_schedule_node)); - if (!sched) - goto error; - - sched->ref = 1; - sched->n = graph->n; - sched->n_band = graph->n_band; - sched->n_total_row = graph->n_total_row; - - for (i = 0; i < sched->n; ++i) { - int r, b; - int *band_end, *band_id, *coincident; + ctx = isl_schedule_node_get_ctx(node); + if (graph->n < 1) + isl_die(ctx, isl_error_internal, + "graph should have at least one node", + return isl_schedule_node_free(node)); - sched->node[i].sched = - node_extract_schedule_multi_aff(&graph->node[i]); - if (!sched->node[i].sched) - goto error; + if (graph->n == 1) + return node; - sched->node[i].n_band = graph->n_band; - if (graph->n_band == 0) - continue; + if (update_edges(ctx, graph) < 0) + return isl_schedule_node_free(node); - band_end = isl_alloc_array(ctx, int, graph->n_band); - band_id = isl_alloc_array(ctx, int, graph->n_band); - coincident = isl_alloc_array(ctx, int, graph->n_total_row); - sched->node[i].band_end = band_end; - sched->node[i].band_id = band_id; - sched->node[i].coincident = coincident; - if (!band_end || !band_id || !coincident) - goto error; + if (graph->n_edge == 0) + return node; - for (r = 0; r < graph->n_total_row; ++r) - coincident[r] = graph->node[i].coincident[r]; - for (r = b = 0; r < graph->n_total_row; ++r) { - if (graph->node[i].band[r] == b) - continue; - band_end[b++] = r; - if (graph->node[i].band[r] == -1) - break; - } - if (r == graph->n_total_row) - band_end[b++] = r; - sched->node[i].n_band = b; - for (--b; b >= 0; --b) - band_id[b] = graph->node[i].band_id[b]; - } + if (detect_sccs(ctx, graph) < 0) + return isl_schedule_node_free(node); - sched->dim = dim; + filters = extract_sccs(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); - return sched; -error: - isl_space_free(dim); - isl_schedule_free(sched); - return NULL; + return node; } /* Copy nodes that satisfy node_pred from the src dependence graph @@ -2621,8 +2648,6 @@ static int copy_nodes(struct isl_sched_graph *dst, struct isl_sched_graph *src, dst->node[j].nparam = src->node[i].nparam; dst->node[j].sched = isl_mat_copy(src->node[i].sched); dst->node[j].sched_map = isl_map_copy(src->node[i].sched_map); - dst->node[j].band = src->node[i].band; - dst->node[j].band_id = src->node[i].band_id; dst->node[j].coincident = src->node[i].coincident; dst->n++; @@ -2709,35 +2734,6 @@ static int copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst, return 0; } -/* Given a "src" dependence graph that contains the nodes from "dst" - * that satisfy node_pred, copy the schedule computed in "src" - * for those nodes back to "dst". - */ -static int copy_schedule(struct isl_sched_graph *dst, - struct isl_sched_graph *src, - int (*node_pred)(struct isl_sched_node *node, int data), int data) -{ - int i; - - src->n = 0; - for (i = 0; i < dst->n; ++i) { - if (!node_pred(&dst->node[i], data)) - continue; - isl_mat_free(dst->node[i].sched); - isl_map_free(dst->node[i].sched_map); - dst->node[i].sched = isl_mat_copy(src->node[src->n].sched); - dst->node[i].sched_map = - isl_map_copy(src->node[src->n].sched_map); - src->n++; - } - - dst->max_row = src->max_row; - dst->n_total_row = src->n_total_row; - dst->n_band = src->n_band; - - return 0; -} - /* Compute the maximal number of variables over all nodes. * This is the maximal number of linearly independent schedule * rows that we need to compute. @@ -2764,8 +2760,10 @@ static int compute_maxvar(struct isl_sched_graph *graph) return 0; } -static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph); -static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph); +static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node, + struct isl_sched_graph *graph); +static __isl_give isl_schedule_node *compute_schedule_wcc( + isl_schedule_node *node, struct isl_sched_graph *graph); /* Compute a schedule for a subgraph of "graph". In particular, for * the graph composed of nodes that satisfy node_pred and edges that @@ -2776,8 +2774,12 @@ static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph); * be set and then we call compute_schedule_wcc on the constructed subgraph. * Otherwise, we call compute_schedule, which will check whether the subgraph * is connected. + * + * The schedule is inserted at "node" and the updated schedule node + * is returned. */ -static int compute_sub_schedule(isl_ctx *ctx, +static __isl_give isl_schedule_node *compute_sub_schedule( + __isl_take isl_schedule_node *node, isl_ctx *ctx, struct isl_sched_graph *graph, int n, int n_edge, int (*node_pred)(struct isl_sched_node *node, int data), int (*edge_pred)(struct isl_sched_edge *edge, int data), @@ -2801,36 +2803,18 @@ static int compute_sub_schedule(isl_ctx *ctx, split.n_row = graph->n_row; split.max_row = graph->max_row; split.n_total_row = graph->n_total_row; - split.n_band = graph->n_band; split.band_start = graph->band_start; - if (wcc && compute_schedule_wcc(ctx, &split) < 0) - goto error; - if (!wcc && compute_schedule(ctx, &split) < 0) - goto error; - - copy_schedule(graph, &split, node_pred, data); + if (wcc) + node = compute_schedule_wcc(node, &split); + else + node = compute_schedule(node, &split); graph_free(ctx, &split); - return 0; + return node; error: graph_free(ctx, &split); - return -1; -} - -static int node_scc_exactly(struct isl_sched_node *node, int scc) -{ - return node->scc == scc; -} - -static int node_scc_at_most(struct isl_sched_node *node, int scc) -{ - return node->scc <= scc; -} - -static int node_scc_at_least(struct isl_sched_node *node, int scc) -{ - return node->scc >= scc; + return isl_schedule_node_free(node); } static int edge_scc_exactly(struct isl_sched_edge *edge, int scc) @@ -2848,32 +2832,6 @@ static int edge_src_scc_at_least(struct isl_sched_edge *edge, int scc) return edge->src->scc >= scc; } -/* Pad the schedules of all nodes with zero rows such that in the end - * they all have graph->n_total_row rows. - * The extra rows don't belong to any band, so they get assigned band number -1. - */ -static int pad_schedule(struct isl_sched_graph *graph) -{ - int i, j; - - for (i = 0; i < graph->n; ++i) { - struct isl_sched_node *node = &graph->node[i]; - int row = isl_mat_rows(node->sched); - if (graph->n_total_row > row) { - isl_map_free(node->sched_map); - node->sched_map = NULL; - } - node->sched = isl_mat_add_zero_rows(node->sched, - graph->n_total_row - row); - if (!node->sched) - return -1; - for (j = row; j < graph->n_total_row; ++j) - node->band[j] = -1; - } - - return 0; -} - /* Reset the current band by dropping all its schedule rows. */ static int reset_band(struct isl_sched_graph *graph) @@ -2904,58 +2862,35 @@ static int reset_band(struct isl_sched_graph *graph) /* Split the current graph into two parts and compute a schedule for each * part individually. In particular, one part consists of all SCCs up * to and including graph->src_scc, while the other part contains the other - * SCCS. + * SCCS. The split is enforced by a sequence node inserted at position "node" + * in the schedule tree. Return the updated schedule node. * - * The split is enforced in the schedule by constant rows with two different - * values (0 and 1). These constant rows replace the previously computed rows - * in the current band. - * It would be possible to reuse them as the first rows in the next + * The current band is reset. It would be possible to reuse + * the previously computed rows as the first rows in the next * band, but recomputing them may result in better rows as we are looking * at a smaller part of the dependence graph. - * - * Since we do not enforce coincidence, we conservatively mark the - * splitting row as not coincident. - * - * The band_id of the second group is set to n, where n is the number - * of nodes in the first group. This ensures that the band_ids over - * the two groups remain disjoint, even if either or both of the two - * groups contain independent components. */ -static int compute_split_schedule(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *compute_split_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) { - int i, j, n, e1, e2; - int n_total_row, orig_total_row; - int n_band, orig_band; + int i, n, e1, e2; + int orig_total_row; + isl_ctx *ctx; + isl_union_set_list *filters; - if (graph->n_total_row >= graph->max_row) - isl_die(ctx, isl_error_internal, - "too many schedule rows", return -1); + if (!node) + return NULL; if (reset_band(graph) < 0) - return -1; + return isl_schedule_node_free(node); n = 0; for (i = 0; i < graph->n; ++i) { struct isl_sched_node *node = &graph->node[i]; - int row = isl_mat_rows(node->sched); - int cols = isl_mat_cols(node->sched); int before = node->scc <= graph->src_scc; if (before) n++; - - isl_map_free(node->sched_map); - node->sched_map = NULL; - node->sched = isl_mat_add_rows(node->sched, 1); - if (!node->sched) - return -1; - node->sched = isl_mat_set_element_si(node->sched, row, 0, - !before); - for (j = 1; j < cols; ++j) - node->sched = isl_mat_set_element_si(node->sched, - row, j, 0); - node->band[graph->n_total_row] = graph->n_band; - node->coincident[graph->n_total_row] = 0; } e1 = e2 = 0; @@ -2966,47 +2901,108 @@ static int compute_split_schedule(isl_ctx *ctx, struct isl_sched_graph *graph) e2++; } - graph->n_total_row++; next_band(graph); - for (i = 0; i < graph->n; ++i) { - struct isl_sched_node *node = &graph->node[i]; - if (node->scc > graph->src_scc) - node->band_id[graph->n_band] = n; - } + ctx = isl_schedule_node_get_ctx(node); + filters = extract_split(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); + node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_child(node, 0); orig_total_row = graph->n_total_row; - orig_band = graph->n_band; - if (compute_sub_schedule(ctx, graph, n, e1, + node = compute_sub_schedule(node, ctx, graph, n, e1, &node_scc_at_most, &edge_dst_scc_at_most, - graph->src_scc, 0) < 0) - return -1; - n_total_row = graph->n_total_row; + graph->src_scc, 0); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_next_sibling(node); + node = isl_schedule_node_child(node, 0); graph->n_total_row = orig_total_row; - n_band = graph->n_band; - graph->n_band = orig_band; - if (compute_sub_schedule(ctx, graph, graph->n - n, e2, + node = compute_sub_schedule(node, ctx, graph, graph->n - n, e2, &node_scc_at_least, &edge_src_scc_at_least, - graph->src_scc + 1, 0) < 0) - return -1; - if (n_total_row > graph->n_total_row) - graph->n_total_row = n_total_row; - if (n_band > graph->n_band) - graph->n_band = n_band; + graph->src_scc + 1, 0); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); - return pad_schedule(graph); + return node; } -/* Compute the next band of the schedule after updating the dependence - * relations based on the the current schedule. +/* Insert a band node at position "node" in the schedule tree corresponding + * to the current band in "graph". Mark the band node permutable + * if "permutable" is set. + * The partial schedules and the coincidence property are extracted + * from the graph nodes. + * Return the updated schedule node. */ -static int compute_next_band(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *insert_current_band( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int permutable) { + int i; + int start, end, n; + isl_multi_aff *ma; + isl_multi_pw_aff *mpa; + isl_multi_union_pw_aff *mupa; + + if (!node) + return NULL; + + if (graph->n < 1) + isl_die(isl_schedule_node_get_ctx(node), isl_error_internal, + "graph should have at least one node", + return isl_schedule_node_free(node)); + + start = graph->band_start; + end = graph->n_total_row; + n = end - start; + + ma = node_extract_partial_schedule_multi_aff(&graph->node[0], start, n); + mpa = isl_multi_pw_aff_from_multi_aff(ma); + mupa = isl_multi_union_pw_aff_from_multi_pw_aff(mpa); + + for (i = 1; i < graph->n; ++i) { + isl_multi_union_pw_aff *mupa_i; + + ma = node_extract_partial_schedule_multi_aff(&graph->node[i], + start, n); + mpa = isl_multi_pw_aff_from_multi_aff(ma); + mupa_i = isl_multi_union_pw_aff_from_multi_pw_aff(mpa); + mupa = isl_multi_union_pw_aff_union_add(mupa, mupa_i); + } + node = isl_schedule_node_insert_partial_schedule(node, mupa); + + for (i = 0; i < n; ++i) + node = isl_schedule_node_band_member_set_coincident(node, i, + graph->node[0].coincident[start + i]); + node = isl_schedule_node_band_set_permutable(node, permutable); + + return node; +} + +/* Update the dependence relations based on the current schedule, + * add the current band to "node" and the continue with the computation + * of the next band. + * Return the updated schedule node. + */ +static __isl_give isl_schedule_node *compute_next_band( + __isl_take isl_schedule_node *node, + struct isl_sched_graph *graph, int permutable) +{ + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); if (update_edges(ctx, graph) < 0) - return -1; + return isl_schedule_node_free(node); + node = insert_current_band(node, graph, permutable); next_band(graph); - return compute_schedule(ctx, graph); + node = isl_schedule_node_child(node, 0); + node = compute_schedule(node, graph); + node = isl_schedule_node_parent(node); + + return node; } /* Add constraints to graph->lp that force the dependence "map" (which @@ -3302,27 +3298,56 @@ static int setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph) return 0; } +static __isl_give isl_schedule_node *compute_component_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int wcc); + +/* Comparison function for sorting the statements based on + * the corresponding value in "r". + */ +static int smaller_value(const void *a, const void *b, void *data) +{ + isl_vec *r = data; + const int *i1 = a; + const int *i2 = b; + + return isl_int_cmp(r->el[*i1], r->el[*i2]); +} + /* If the schedule_split_scaled option is set and if the linear * parts of the scheduling rows for all nodes in the graphs have - * non-trivial common divisor, then split off the constant term - * from the linear part. - * The constant term is then placed in a separate band and - * the linear part is reduced. + * a non-trivial common divisor, then split off the remainder of the + * constant term modulo this common divisor from the linear part. + * Otherwise, insert a band node directly and continue with + * the construction of the schedule. + * + * If a non-trivial common divisor is found, then + * the linear part is reduced and the remainder is enforced + * by a sequence node with the children placed in the order + * of this remainder. + * In particular, we assign an scc index based on the remainder and + * then rely on compute_component_schedule to insert the sequence and + * to continue the schedule construction on each part. */ -static int split_scaled(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *split_scaled( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) { int i; int row; + int scc; + isl_ctx *ctx; isl_int gcd, gcd_i; + isl_vec *r; + int *order; + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); if (!ctx->opt->schedule_split_scaled) - return 0; + return compute_next_band(node, graph, 0); if (graph->n <= 1) - return 0; - - if (graph->n_total_row >= graph->max_row) - isl_die(ctx, isl_error_internal, - "too many schedule rows", return -1); + return compute_next_band(node, graph, 0); isl_int_init(gcd); isl_int_init(gcd_i); @@ -3343,21 +3368,19 @@ static int split_scaled(isl_ctx *ctx, struct isl_sched_graph *graph) if (isl_int_cmp_si(gcd, 1) <= 0) { isl_int_clear(gcd); - return 0; + return compute_next_band(node, graph, 0); } - next_band(graph); + r = isl_vec_alloc(ctx, graph->n); + order = isl_calloc_array(ctx, int, graph->n); + if (!r || !order) + goto error; for (i = 0; i < graph->n; ++i) { struct isl_sched_node *node = &graph->node[i]; - isl_map_free(node->sched_map); - node->sched_map = NULL; - node->sched = isl_mat_add_zero_rows(node->sched, 1); - if (!node->sched) - goto error; - isl_int_fdiv_r(node->sched->row[row + 1][0], - node->sched->row[row][0], gcd); + order[i] = i; + isl_int_fdiv_r(r->el[i], node->sched->row[row][0], gcd); isl_int_fdiv_q(node->sched->row[row][0], node->sched->row[row][0], gcd); isl_int_mul(node->sched->row[row][0], @@ -3365,21 +3388,41 @@ static int split_scaled(isl_ctx *ctx, struct isl_sched_graph *graph) node->sched = isl_mat_scale_down_row(node->sched, row, gcd); if (!node->sched) goto error; - node->band[graph->n_total_row] = graph->n_band; } - graph->n_total_row++; + if (isl_sort(order, graph->n, sizeof(order[0]), &smaller_value, r) < 0) + goto error; + + scc = 0; + for (i = 0; i < graph->n; ++i) { + if (i > 0 && isl_int_ne(r->el[order[i - 1]], r->el[order[i]])) + ++scc; + graph->node[order[i]].scc = scc; + } + graph->scc = ++scc; + graph->weak = 0; isl_int_clear(gcd); - return 0; + isl_vec_free(r); + free(order); + + if (update_edges(ctx, graph) < 0) + return isl_schedule_node_free(node); + node = insert_current_band(node, graph, 0); + next_band(graph); + + node = isl_schedule_node_child(node, 0); + node = compute_component_schedule(node, graph, 0); + node = isl_schedule_node_parent(node); + + return node; error: + isl_vec_free(r); + free(order); isl_int_clear(gcd); - return -1; + return isl_schedule_node_free(node); } -static int compute_component_schedule(isl_ctx *ctx, - struct isl_sched_graph *graph); - /* Is the schedule row "sol" trivial on node "node"? * That is, is the solution zero on the dimensions orthogonal to * the previously found solutions? @@ -3469,38 +3512,51 @@ static int is_any_trivial(struct isl_sched_graph *graph, * graph->maxvar is computed based on these ranks. The test for * whether more schedule rows are required in compute_schedule_wcc * is therefore not affected. + * + * Insert a band corresponding to the schedule row at position "node" + * of the schedule tree and continue with the construction of the schedule. + * This insertion and the continued construction is performed by split_scaled + * after optionally checking for non-trivial common divisors. */ -static int carry_dependences(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *carry_dependences( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) { int i; int n_edge; int trivial; + isl_ctx *ctx; isl_vec *sol; isl_basic_set *lp; + if (!node) + return NULL; + n_edge = 0; for (i = 0; i < graph->n_edge; ++i) n_edge += graph->edge[i].map->n; + ctx = isl_schedule_node_get_ctx(node); if (setup_carry_lp(ctx, graph) < 0) - return -1; + return isl_schedule_node_free(node); lp = isl_basic_set_copy(graph->lp); sol = isl_tab_basic_set_non_neg_lexmin(lp); if (!sol) - return -1; + return isl_schedule_node_free(node); if (sol->size == 0) { isl_vec_free(sol); isl_die(ctx, isl_error_internal, - "error in schedule construction", return -1); + "error in schedule construction", + return isl_schedule_node_free(node)); } isl_int_divexact(sol->el[1], sol->el[1], sol->el[0]); if (isl_int_cmp_si(sol->el[1], n_edge) >= 0) { isl_vec_free(sol); isl_die(ctx, isl_error_unknown, - "unable to carry dependences", return -1); + "unable to carry dependences", + return isl_schedule_node_free(node)); } trivial = is_any_trivial(graph, sol); @@ -3508,18 +3564,15 @@ static int carry_dependences(isl_ctx *ctx, struct isl_sched_graph *graph) sol = isl_vec_free(sol); } else if (trivial && graph->scc > 1) { isl_vec_free(sol); - return compute_component_schedule(ctx, graph); + return compute_component_schedule(node, graph, 1); } if (update_schedule(graph, sol, 0, 0) < 0) - return -1; + return isl_schedule_node_free(node); if (trivial) graph->n_row--; - if (split_scaled(ctx, graph) < 0) - return -1; - - return compute_next_band(ctx, graph); + return split_scaled(node, graph); } /* Are there any (non-empty) (conditional) validity edges in the graph? @@ -3557,7 +3610,8 @@ static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph) } /* Compute a schedule for a connected dependence graph using Feautrier's - * multi-dimensional scheduling algorithm. + * multi-dimensional scheduling algorithm and return the updated schedule node. + * * The original algorithm is described in [1]. * The main idea is to minimize the number of scheduling dimensions, by * trying to satisfy as many dependences as possible per scheduling dimension. @@ -3566,10 +3620,10 @@ static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph) * Problem, Part II: Multi-Dimensional Time. * In Intl. Journal of Parallel Programming, 1992. */ -static int compute_schedule_wcc_feautrier(isl_ctx *ctx, - struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *compute_schedule_wcc_feautrier( + isl_schedule_node *node, struct isl_sched_graph *graph) { - return carry_dependences(ctx, graph); + return carry_dependences(node, graph); } /* Turn off the "local" bit on all (condition) edges. @@ -3827,7 +3881,9 @@ error: return -1; } -/* Compute a schedule for a connected dependence graph. +/* Compute a schedule for a connected dependence graph and return + * the updated schedule node. + * * We try to find a sequence of as many schedule rows as possible that result * in non-negative dependence distances (independent of the previous rows * in the sequence, i.e., such that the sequence is tilable), with as @@ -3839,12 +3895,15 @@ error: * one row) * - try to carry as many dependences as possible and continue with the next * band + * In each case, we first insert a band node in the schedule tree + * if any rows have been computed. * * If Feautrier's algorithm is selected, we first recursively try to satisfy * as many validity dependences as possible. When all validity dependences * are satisfied we extend the schedule to a full-dimensional schedule. * - * If we manage to complete the schedule, we finish off by topologically + * If we manage to complete the schedule, we insert a band node + * (if any schedule rows were computed) and we finish off by topologically * sorting the statements based on the remaining dependences. * * If ctx->opt->schedule_outer_coincidence is set, then we force the @@ -3868,23 +3927,29 @@ error: * Since there are only a finite number of dependences, * there will only be a finite number of iterations. */ -static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *compute_schedule_wcc( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) { int has_coincidence; int use_coincidence; int force_coincidence = 0; int check_conditional; + isl_ctx *ctx; + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); if (detect_sccs(ctx, graph) < 0) - return -1; + return isl_schedule_node_free(node); if (sort_sccs(graph) < 0) - return -1; + return isl_schedule_node_free(node); if (compute_maxvar(graph) < 0) - return -1; + return isl_schedule_node_free(node); if (need_feautrier_step(ctx, graph)) - return compute_schedule_wcc_feautrier(ctx, graph); + return compute_schedule_wcc_feautrier(node, graph); clear_local_edges(graph); check_conditional = need_condition_check(graph); @@ -3903,10 +3968,10 @@ static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph) graph->dst_scc = -1; if (setup_lp(ctx, graph, use_coincidence) < 0) - return -1; + return isl_schedule_node_free(node); sol = solve_lp(graph); if (!sol) - return -1; + return isl_schedule_node_free(node); if (sol->size == 0) { int empty = graph->n_total_row == graph->band_start; @@ -3916,123 +3981,98 @@ static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph) continue; } if (!ctx->opt->schedule_maximize_band_depth && !empty) - return compute_next_band(ctx, graph); + return compute_next_band(node, graph, 1); if (graph->src_scc >= 0) - return compute_split_schedule(ctx, graph); + return compute_split_schedule(node, graph); if (!empty) - return compute_next_band(ctx, graph); - return carry_dependences(ctx, graph); + return compute_next_band(node, graph, 1); + return carry_dependences(node, graph); } coincident = !has_coincidence || use_coincidence; if (update_schedule(graph, sol, 1, coincident) < 0) - return -1; + return isl_schedule_node_free(node); if (!check_conditional) continue; violated = has_violated_conditional_constraint(ctx, graph); if (violated < 0) - return -1; + return isl_schedule_node_free(node); if (!violated) continue; if (reset_band(graph) < 0) - return -1; + return isl_schedule_node_free(node); use_coincidence = has_coincidence; } - if (graph->n_total_row > graph->band_start) - next_band(graph); - return sort_statements(ctx, graph); -} - -/* Add a row to the schedules that separates the SCCs and move - * to the next band. - */ -static int split_on_scc(isl_ctx *ctx, struct isl_sched_graph *graph) -{ - int i; - - if (graph->n_total_row >= graph->max_row) - isl_die(ctx, isl_error_internal, - "too many schedule rows", return -1); - - for (i = 0; i < graph->n; ++i) { - struct isl_sched_node *node = &graph->node[i]; - int row = isl_mat_rows(node->sched); - - isl_map_free(node->sched_map); - node->sched_map = NULL; - node->sched = isl_mat_add_zero_rows(node->sched, 1); - node->sched = isl_mat_set_element_si(node->sched, row, 0, - node->scc); - if (!node->sched) - return -1; - node->band[graph->n_total_row] = graph->n_band; + if (graph->n_total_row > graph->band_start) { + node = insert_current_band(node, graph, 1); + node = isl_schedule_node_child(node, 0); } + node = sort_statements(node, graph); + if (graph->n_total_row > graph->band_start) + node = isl_schedule_node_parent(node); - graph->n_total_row++; - next_band(graph); - - return 0; + return node; } -/* Compute a schedule for each component (identified by node->scc) - * of the dependence graph separately and then combine the results. - * Depending on the setting of schedule_fuse, a component may be - * either weakly or strongly connected. +/* Compute a schedule for each group of nodes identified by node->scc + * separately and then combine them in a sequence node (or as set node + * if graph->weak is set) inserted at position "node" of the schedule tree. + * Return the updated schedule node. * - * The band_id is adjusted such that each component has a separate id. - * Note that the band_id may have already been set to a value different - * from zero by compute_split_schedule. + * If "wcc" is set then each of the groups belongs to a single + * weakly connected component in the dependence graph so that + * there is no need for compute_sub_schedule to look for weakly + * connected components. */ -static int compute_component_schedule(isl_ctx *ctx, - struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *compute_component_schedule( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int wcc) { - int wcc, i; + int component, i; int n, n_edge; - int n_total_row, orig_total_row; - int n_band, orig_band; + int orig_total_row; + isl_ctx *ctx; + isl_union_set_list *filters; - if (ctx->opt->schedule_fuse == ISL_SCHEDULE_FUSE_MIN || - ctx->opt->schedule_separate_components) - if (split_on_scc(ctx, graph) < 0) - return -1; + if (!node) + return NULL; + ctx = isl_schedule_node_get_ctx(node); + + filters = extract_sccs(ctx, graph); + if (graph->weak) + node = isl_schedule_node_insert_set(node, filters); + else + node = isl_schedule_node_insert_sequence(node, filters); - n_total_row = 0; orig_total_row = graph->n_total_row; - n_band = 0; - orig_band = graph->n_band; - for (i = 0; i < graph->n; ++i) - graph->node[i].band_id[graph->n_band] += graph->node[i].scc; - for (wcc = 0; wcc < graph->scc; ++wcc) { + for (component = 0; component < graph->scc; ++component) { n = 0; for (i = 0; i < graph->n; ++i) - if (graph->node[i].scc == wcc) + if (graph->node[i].scc == component) n++; n_edge = 0; for (i = 0; i < graph->n_edge; ++i) - if (graph->edge[i].src->scc == wcc && - graph->edge[i].dst->scc == wcc) + if (graph->edge[i].src->scc == component && + graph->edge[i].dst->scc == component) n_edge++; - if (compute_sub_schedule(ctx, graph, n, n_edge, + node = isl_schedule_node_child(node, component); + node = isl_schedule_node_child(node, 0); + node = compute_sub_schedule(node, ctx, graph, n, n_edge, &node_scc_exactly, - &edge_scc_exactly, wcc, 1) < 0) - return -1; - if (graph->n_total_row > n_total_row) - n_total_row = graph->n_total_row; + &edge_scc_exactly, component, wcc); + node = isl_schedule_node_parent(node); + node = isl_schedule_node_parent(node); graph->n_total_row = orig_total_row; - if (graph->n_band > n_band) - n_band = graph->n_band; - graph->n_band = orig_band; } - graph->n_total_row = n_total_row; - graph->n_band = n_band; - - return pad_schedule(graph); + return node; } -/* Compute a schedule for the given dependence graph. +/* Compute a schedule for the given dependence graph and insert it at "node". + * Return the updated schedule node. + * * We first check if the graph is connected (through validity and conditional * validity dependences) and, if not, compute a schedule * for each component separately. @@ -4040,20 +4080,27 @@ static int compute_component_schedule(isl_ctx *ctx, * connected components instead and compute a separate schedule for * each such strongly connected component. */ -static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph) +static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node, + struct isl_sched_graph *graph) { + isl_ctx *ctx; + + if (!node) + return NULL; + + ctx = isl_schedule_node_get_ctx(node); if (ctx->opt->schedule_fuse == ISL_SCHEDULE_FUSE_MIN) { if (detect_sccs(ctx, graph) < 0) - return -1; + return isl_schedule_node_free(node); } else { if (detect_wccs(ctx, graph) < 0) - return -1; + return isl_schedule_node_free(node); } if (graph->scc > 1) - return compute_component_schedule(ctx, graph); + return compute_component_schedule(node, graph, 1); - return compute_schedule_wcc(ctx, graph); + return compute_schedule_wcc(node, graph); } /* Compute a schedule on sc->domain that respects the given schedule @@ -4070,6 +4117,12 @@ static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph) * then the conditional validity dependences may be violated inside * a tilable band, provided they have no adjacent non-local * condition dependences. + * + * The context is included in the domain before the nodes of + * the graphs are extracted in order to be able to exploit + * any possible additional equalities. + * However, the returned schedule contains the original domain + * (before this intersection). */ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( __isl_take isl_schedule_constraints *sc) @@ -4077,16 +4130,22 @@ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( isl_ctx *ctx = isl_schedule_constraints_get_ctx(sc); struct isl_sched_graph graph = { 0 }; isl_schedule *sched; + isl_schedule_node *node; + isl_union_set *domain; struct isl_extract_edge_data data; enum isl_edge_type i; + int r; sc = isl_schedule_constraints_align_params(sc); if (!sc) return NULL; graph.n = isl_union_set_n_set(sc->domain); - if (graph.n == 0) - goto empty; + if (graph.n == 0) { + isl_union_set *domain = isl_union_set_copy(sc->domain); + sched = isl_schedule_from_domain(domain); + goto done; + } if (graph_alloc(ctx, &graph, graph.n, isl_schedule_constraints_n_map(sc)) < 0) goto error; @@ -4094,7 +4153,12 @@ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( goto error; graph.root = 1; graph.n = 0; - if (isl_union_set_foreach_set(sc->domain, &extract_node, &graph) < 0) + domain = isl_union_set_copy(sc->domain); + domain = isl_union_set_intersect_params(domain, + isl_set_copy(sc->context)); + r = isl_union_set_foreach_set(domain, &extract_node, &graph); + isl_union_set_free(domain); + if (r < 0) goto error; if (graph_init_table(ctx, &graph) < 0) goto error; @@ -4111,12 +4175,13 @@ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( goto error; } - if (compute_schedule(ctx, &graph) < 0) - goto error; - -empty: - sched = extract_schedule(&graph, isl_union_set_get_space(sc->domain)); + node = isl_schedule_node_from_domain(isl_union_set_copy(sc->domain)); + node = isl_schedule_node_child(node, 0); + node = compute_schedule(node, &graph); + sched = isl_schedule_node_get_schedule(node); + isl_schedule_node_free(node); +done: graph_free(ctx, &graph); isl_schedule_constraints_free(sc); diff --git a/polly/lib/External/isl/isl_set_list.c b/polly/lib/External/isl/isl_set_list.c index b27982748a7..9f77c41578d 100644 --- a/polly/lib/External/isl/isl_set_list.c +++ b/polly/lib/External/isl/isl_set_list.c @@ -10,6 +10,11 @@ #include <isl_list_templ.h> +#undef EL +#define EL isl_union_set + +#include <isl_list_templ.h> + #undef BASE #define BASE basic_set @@ -19,3 +24,8 @@ #define BASE set #include <isl_list_templ.c> + +#undef BASE +#define BASE union_set + +#include <isl_list_templ.c> diff --git a/polly/lib/External/isl/isl_stream.c b/polly/lib/External/isl/isl_stream.c index c5b15115668..0957751fe43 100644 --- a/polly/lib/External/isl/isl_stream.c +++ b/polly/lib/External/isl/isl_stream.c @@ -28,7 +28,7 @@ static int same_name(const void *entry, const void *val) return !strcmp(keyword->name, val); } -enum isl_token_type isl_stream_register_keyword(struct isl_stream *s, +enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, const char *name) { struct isl_hash_table_entry *entry; @@ -101,14 +101,15 @@ __isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok) return isl_val_int_from_isl_int(ctx, tok->u.v); } -/* Given a token of type ISL_TOKEN_STRING, return the string it represents. +/* Given a token with a string representation, return a copy of this string. */ __isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok) { if (!tok) return NULL; - if (tok->type != ISL_TOKEN_STRING) - isl_die(ctx, isl_error_invalid, "not a string token", + if (!tok->u.s) + isl_die(ctx, isl_error_invalid, + "token does not have a string representation", return NULL); return strdup(tok->u.s); @@ -129,7 +130,8 @@ void isl_token_free(struct isl_token *tok) free(tok); } -void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg) +void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok, + char *msg) { int line = tok ? tok->line : s->line; int col = tok ? tok->col : s->col; @@ -166,10 +168,10 @@ void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg) } } -static struct isl_stream* isl_stream_new(struct isl_ctx *ctx) +static __isl_give isl_stream* isl_stream_new(struct isl_ctx *ctx) { int i; - struct isl_stream *s = isl_alloc_type(ctx, struct isl_stream); + isl_stream *s = isl_calloc_type(ctx, struct isl_stream); if (!s) return NULL; s->ctx = ctx; @@ -178,8 +180,9 @@ static struct isl_stream* isl_stream_new(struct isl_ctx *ctx) s->str = NULL; s->len = 0; s->line = 1; - s->col = 0; + s->col = 1; s->eof = 0; + s->last_line = 0; s->c = -1; s->n_un = 0; for (i = 0; i < 5; ++i) @@ -196,18 +199,18 @@ error: return NULL; } -struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file) +__isl_give isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file) { - struct isl_stream *s = isl_stream_new(ctx); + isl_stream *s = isl_stream_new(ctx); if (!s) return NULL; s->file = file; return s; } -struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str) +__isl_give isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str) { - struct isl_stream *s; + isl_stream *s; if (!str) return NULL; s = isl_stream_new(ctx); @@ -217,7 +220,10 @@ struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str) return s; } -static int stream_getc(struct isl_stream *s) +/* Read a character from the stream and advance s->line and s->col + * to point to the next character. + */ +static int stream_getc(__isl_keep isl_stream *s) { int c; if (s->eof) @@ -233,29 +239,33 @@ static int stream_getc(struct isl_stream *s) } if (c == -1) s->eof = 1; - if (!s->eof) { - if (s->c == '\n') { - s->line++; - s->col = 0; - } else - s->col++; - } + else if (c == '\n') { + s->line++; + s->col = 1; + } else + s->col++; s->c = c; return c; } -static void isl_stream_ungetc(struct isl_stream *s, int c) +static void isl_stream_ungetc(__isl_keep isl_stream *s, int c) { isl_assert(s->ctx, s->n_un < 5, return); s->un[s->n_un++] = c; s->c = -1; } -static int isl_stream_getc(struct isl_stream *s) +/* Read a character from the stream, skipping pairs of '\\' and '\n'. + * Set s->start_line and s->start_col to the line and column + * of the returned character. + */ +static int isl_stream_getc(__isl_keep isl_stream *s) { int c; do { + s->start_line = s->line; + s->start_col = s->col; c = stream_getc(s); if (c != '\\') return c; @@ -267,7 +277,7 @@ static int isl_stream_getc(struct isl_stream *s) return '\\'; } -static int isl_stream_push_char(struct isl_stream *s, int c) +static int isl_stream_push_char(__isl_keep isl_stream *s, int c) { if (s->len >= s->size) { char *buffer; @@ -281,13 +291,13 @@ static int isl_stream_push_char(struct isl_stream *s, int c) return 0; } -void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok) +void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok) { isl_assert(s->ctx, s->n_token < 5, return); s->tokens[s->n_token++] = tok; } -static enum isl_token_type check_keywords(struct isl_stream *s) +static enum isl_token_type check_keywords(__isl_keep isl_stream *s) { struct isl_hash_table_entry *entry; struct isl_keyword *keyword; @@ -344,7 +354,7 @@ static enum isl_token_type check_keywords(struct isl_stream *s) return ISL_TOKEN_IDENT; } -int isl_stream_skip_line(struct isl_stream *s) +int isl_stream_skip_line(__isl_keep isl_stream *s) { int c; @@ -355,12 +365,12 @@ int isl_stream_skip_line(struct isl_stream *s) return c == -1 ? -1 : 0; } -static struct isl_token *next_token(struct isl_stream *s, int same_line) +static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line) { int c; struct isl_token *tok = NULL; int line, col; - int old_line = s->line; + int old_line = s->last_line; if (s->n_token) { if (same_line && s->tokens[s->n_token - 1]->on_new_line) @@ -385,11 +395,13 @@ static struct isl_token *next_token(struct isl_stream *s, int same_line) break; } - line = s->line; - col = s->col; + line = s->start_line; + col = s->start_col; if (c == -1 || (same_line && c == '\n')) return NULL; + s->last_line = line; + if (c == '(' || c == ')' || c == '+' || @@ -655,17 +667,17 @@ error: return NULL; } -struct isl_token *isl_stream_next_token(struct isl_stream *s) +struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s) { return next_token(s, 0); } -struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s) +struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s) { return next_token(s, 1); } -int isl_stream_eat_if_available(struct isl_stream *s, int type) +int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type) { struct isl_token *tok; @@ -680,7 +692,7 @@ int isl_stream_eat_if_available(struct isl_stream *s, int type) return 0; } -int isl_stream_next_token_is(struct isl_stream *s, int type) +int isl_stream_next_token_is(__isl_keep isl_stream *s, int type) { struct isl_token *tok; int r; @@ -693,7 +705,7 @@ int isl_stream_next_token_is(struct isl_stream *s, int type) return r; } -char *isl_stream_read_ident_if_available(struct isl_stream *s) +char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s) { struct isl_token *tok; @@ -709,7 +721,7 @@ char *isl_stream_read_ident_if_available(struct isl_stream *s) return NULL; } -int isl_stream_eat(struct isl_stream *s, int type) +int isl_stream_eat(__isl_keep isl_stream *s, int type) { struct isl_token *tok; @@ -725,7 +737,7 @@ int isl_stream_eat(struct isl_stream *s, int type) return -1; } -int isl_stream_is_empty(struct isl_stream *s) +int isl_stream_is_empty(__isl_keep isl_stream *s) { struct isl_token *tok; @@ -748,7 +760,7 @@ static int free_keyword(void **p, void *user) return 0; } -void isl_stream_flush_tokens(struct isl_stream *s) +void isl_stream_flush_tokens(__isl_keep isl_stream *s) { int i; @@ -759,7 +771,12 @@ void isl_stream_flush_tokens(struct isl_stream *s) s->n_token = 0; } -void isl_stream_free(struct isl_stream *s) +isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s) +{ + return s ? s->ctx : NULL; +} + +void isl_stream_free(__isl_take isl_stream *s) { if (!s) return; @@ -773,6 +790,382 @@ void isl_stream_free(struct isl_stream *s) isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL); isl_hash_table_free(s->ctx, s->keywords); } + free(s->yaml_state); + free(s->yaml_indent); isl_ctx_deref(s->ctx); free(s); } + +/* Push "state" onto the stack of currently active YAML elements. + * The caller is responsible for setting the corresponding indentation. + * Return 0 on success and -1 on failure. + */ +static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state) +{ + if (s->yaml_size < s->yaml_depth + 1) { + int *indent; + enum isl_yaml_state *state; + + state = isl_realloc_array(s->ctx, s->yaml_state, + enum isl_yaml_state, s->yaml_depth + 1); + if (!state) + return -1; + s->yaml_state = state; + + indent = isl_realloc_array(s->ctx, s->yaml_indent, + int, s->yaml_depth + 1); + if (!indent) + return -1; + s->yaml_indent = indent; + + s->yaml_size = s->yaml_depth + 1; + } + + s->yaml_state[s->yaml_depth] = state; + s->yaml_depth++; + + return 0; +} + +/* Remove the innermost active YAML element from the stack. + * Return 0 on success and -1 on failure. + */ +static int pop_state(__isl_keep isl_stream *s) +{ + if (!s) + return -1; + if (s->yaml_depth < 1) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "not in YAML construct", return -1); + + s->yaml_depth--; + + return 0; +} + +/* Set the state of the innermost active YAML element to "state". + * Return 0 on success and -1 on failure. + */ +static int update_state(__isl_keep isl_stream *s, enum isl_yaml_state state) +{ + if (!s) + return -1; + if (s->yaml_depth < 1) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "not in YAML construct", return -1); + + s->yaml_state[s->yaml_depth - 1] = state; + + return 0; +} + +/* Return the state of the innermost active YAML element. + * Return isl_yaml_none if we are not inside any YAML element. + */ +static enum isl_yaml_state current_state(__isl_keep isl_stream *s) +{ + if (!s) + return isl_yaml_none; + if (s->yaml_depth < 1) + return isl_yaml_none; + return s->yaml_state[s->yaml_depth - 1]; +} + +/* Set the indentation of the innermost active YAML element to "indent". + * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means + * that the current elemient is in flow format. + */ +static int set_yaml_indent(__isl_keep isl_stream *s, int indent) +{ + if (s->yaml_depth < 1) + isl_die(s->ctx, isl_error_internal, + "not in YAML element", return -1); + + s->yaml_indent[s->yaml_depth - 1] = indent; + + return 0; +} + +/* Return the indentation of the innermost active YAML element + * of -1 on error. + */ +static int get_yaml_indent(__isl_keep isl_stream *s) +{ + if (s->yaml_depth < 1) + isl_die(s->ctx, isl_error_internal, + "not in YAML element", return -1); + + return s->yaml_indent[s->yaml_depth - 1]; +} + +/* Move to the next state at the innermost level. + * Return 1 if successful. + * Return 0 if we are at the end of the innermost level. + * Return -1 on error. + * + * If we are in state isl_yaml_mapping_key_start, then we have just + * started a mapping and we are expecting a key. If the mapping started + * with a '{', then we check if the next token is a '}'. If so, + * then the mapping is empty and there is no next state at this level. + * Otherwise, we assume that there is at least one key (the one from + * which we derived the indentation in isl_stream_yaml_read_start_mapping. + * + * If we are in state isl_yaml_mapping_key, then the we expect a colon + * followed by a value, so there is always a next state unless + * some error occurs. + * + * If we are in state isl_yaml_mapping_val, then there may or may + * not be a subsequent key in the same mapping. + * In flow format, the next key is preceded by a comma. + * In block format, the next key has the same indentation as the first key. + * If the first token has a smaller indentation, then we have reached + * the end of the current mapping. + * + * If we are in state isl_yaml_sequence_start, then we have just + * started a sequence. If the sequence started with a '[', + * then we check if the next token is a ']'. If so, then the sequence + * is empty and there is no next state at this level. + * Otherwise, we assume that there is at least one element in the sequence + * (the one from which we derived the indentation in + * isl_stream_yaml_read_start_sequence. + * + * If we are in state isl_yaml_sequence, then there may or may + * not be a subsequent element in the same sequence. + * In flow format, the next element is preceded by a comma. + * In block format, the next element is introduced by a dash with + * the same indentation as that of the first element. + * If the first token is not a dash or if it has a smaller indentation, + * then we have reached the end of the current sequence. + */ +int isl_stream_yaml_next(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + enum isl_yaml_state state; + int indent; + + state = current_state(s); + if (state == isl_yaml_none) + isl_die(s->ctx, isl_error_invalid, + "not in YAML element", return -1); + switch (state) { + case isl_yaml_mapping_key_start: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW && + isl_stream_next_token_is(s, '}')) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + case isl_yaml_mapping_key: + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (tok->type == ':') { + isl_token_free(tok); + if (update_state(s, isl_yaml_mapping_val) < 0) + return -1; + return 1; + } + isl_stream_error(s, tok, "expecting ':'"); + isl_stream_push_token(s, tok); + return -1; + case isl_yaml_mapping_val: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (!isl_stream_eat_if_available(s, ',')) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + } + tok = isl_stream_next_token(s); + if (!tok) + return 0; + indent = tok->col - 1; + isl_stream_push_token(s, tok); + if (indent < get_yaml_indent(s)) + return 0; + if (update_state(s, isl_yaml_mapping_key) < 0) + return -1; + return 1; + case isl_yaml_sequence_start: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_next_token_is(s, ']')) + return 0; + if (update_state(s, isl_yaml_sequence) < 0) + return -1; + return 1; + } + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (tok->type == '-') { + isl_token_free(tok); + if (update_state(s, isl_yaml_sequence) < 0) + return -1; + return 1; + } + isl_stream_error(s, tok, "expecting '-'"); + isl_stream_push_token(s, tok); + return 0; + case isl_yaml_sequence: + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) + return isl_stream_eat_if_available(s, ','); + tok = isl_stream_next_token(s); + if (!tok) + return 0; + indent = tok->col - 1; + if (indent < get_yaml_indent(s) || tok->type != '-') { + isl_stream_push_token(s, tok); + return 0; + } + isl_token_free(tok); + return 1; + default: + isl_die(s->ctx, isl_error_internal, + "unexpected state", return 0); + } +} + +/* Start reading a YAML mapping. + * Return 0 on success and -1 on error. + * + * If the first token on the stream is a '{' then we remove this token + * from the stream and keep track of the fact that the mapping + * is given in flow format. + * Otherwise, we assume the first token is the first key of the mapping and + * keep track of its indentation, but keep the token on the stream. + * In both cases, the next token we expect is the first key of the mapping. + */ +int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (push_state(s, isl_yaml_mapping_key_start) < 0) + return -1; + + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (isl_token_get_type(tok) == '{') { + isl_token_free(tok); + return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); + } + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + return set_yaml_indent(s, indent); +} + +/* Finish reading a YAML mapping. + * Return 0 on success and -1 on error. + * + * If the mapping started with a '{', then we expect a '}' to close + * the mapping. + * Otherwise, we double-check that the next token (if any) + * has a smaller indentation than that of the current mapping. + */ +int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_eat(s, '}') < 0) + return -1; + return pop_state(s); + } + + tok = isl_stream_next_token(s); + if (!tok) + return pop_state(s); + + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + if (indent >= get_yaml_indent(s)) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "mapping not finished", return -1); + + return pop_state(s); +} + +/* Start reading a YAML sequence. + * Return 0 on success and -1 on error. + * + * If the first token on the stream is a '[' then we remove this token + * from the stream and keep track of the fact that the sequence + * is given in flow format. + * Otherwise, we assume the first token is the dash that introduces + * the first element of the sequence and keep track of its indentation, + * but keep the token on the stream. + * In both cases, the next token we expect is the first element + * of the sequence. + */ +int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + + if (push_state(s, isl_yaml_sequence_start) < 0) + return -1; + + tok = isl_stream_next_token(s); + if (!tok) { + if (s->eof) + isl_stream_error(s, NULL, "unexpected EOF"); + return -1; + } + if (isl_token_get_type(tok) == '[') { + isl_token_free(tok); + return set_yaml_indent(s, ISL_YAML_INDENT_FLOW); + } + indent = tok->col - 1; + isl_stream_push_token(s, tok); + + return set_yaml_indent(s, indent); +} + +/* Finish reading a YAML sequence. + * Return 0 on success and -1 on error. + * + * If the sequence started with a '[', then we expect a ']' to close + * the sequence. + * Otherwise, we double-check that the next token (if any) + * is not a dash or that it has a smaller indentation than + * that of the current sequence. + */ +int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int indent; + int dash; + + if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { + if (isl_stream_eat(s, ']') < 0) + return -1; + return pop_state(s); + } + + tok = isl_stream_next_token(s); + if (!tok) + return pop_state(s); + + indent = tok->col - 1; + dash = tok->type == '-'; + isl_stream_push_token(s, tok); + + if (indent >= get_yaml_indent(s) && dash) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "sequence not finished", return -1); + + return pop_state(s); +} diff --git a/polly/lib/External/isl/isl_stream_private.h b/polly/lib/External/isl/isl_stream_private.h index d5d4422127f..b199ec64dc2 100644 --- a/polly/lib/External/isl/isl_stream_private.h +++ b/polly/lib/External/isl/isl_stream_private.h @@ -1,5 +1,6 @@ #include <isl_int.h> #include <isl/stream.h> +#include <isl_yaml.h> struct isl_token { int type; @@ -19,3 +20,50 @@ struct isl_token { struct isl_token *isl_token_new(isl_ctx *ctx, int line, int col, unsigned on_new_line); + +/* An input stream that may be either a file or a string. + * + * line and col are the line and column number of the next character (1-based). + * start_line and start_col are set by isl_stream_getc to point + * to the position of the returned character. + * last_line is the line number of the previous token. + * + * yaml_state and yaml_indent keep track of the currently active YAML + * elements. yaml_size is the size of these arrays, while yaml_depth + * is the number of elements currently in use. + * yaml_state and yaml_indent may be NULL if no YAML parsing is being + * performed. + * yaml_state keeps track of what is expected next at each level. + * yaml_indent keeps track of the indentation at each level, with + * ISL_YAML_INDENT_FLOW meaning that the element is in flow format + * (such that the indentation is not relevant). + */ +struct isl_stream { + struct isl_ctx *ctx; + FILE *file; + const char *str; + int line; + int col; + int start_line; + int start_col; + int last_line; + int eof; + + char *buffer; + size_t size; + size_t len; + int c; + int un[5]; + int n_un; + + struct isl_token *tokens[5]; + int n_token; + + struct isl_hash_table *keywords; + enum isl_token_type next_type; + + int yaml_depth; + int yaml_size; + enum isl_yaml_state *yaml_state; + int *yaml_indent; +}; diff --git a/polly/lib/External/isl/isl_tab.c b/polly/lib/External/isl/isl_tab.c index 915521036a6..a1258d0a8cd 100644 --- a/polly/lib/External/isl/isl_tab.c +++ b/polly/lib/External/isl/isl_tab.c @@ -1,12 +1,15 @@ /* * Copyright 2008-2009 Katholieke Universiteit Leuven * Copyright 2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt * * 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 Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France */ #include <isl_ctx_private.h> @@ -957,6 +960,22 @@ int isl_tab_mark_redundant(struct isl_tab *tab, int row) } } +/* Mark "tab" as a rational tableau. + * If it wasn't marked as a rational tableau already and if we may + * need to undo changes, then arrange for the marking to be undone + * during the undo. + */ +int isl_tab_mark_rational(struct isl_tab *tab) +{ + if (!tab) + return -1; + if (!tab->rational && tab->need_undo) + if (isl_tab_push(tab, isl_tab_undo_rational) < 0) + return -1; + tab->rational = 1; + return 0; +} + int isl_tab_mark_empty(struct isl_tab *tab) { if (!tab) @@ -1409,7 +1428,8 @@ static int row_at_most_neg_one(struct isl_tab *tab, int row) /* Return 1 if "var" can attain values <= -1. * Return 0 otherwise. * - * The sample value of "var" is assumed to be non-negative when the + * If the variable "var" is supposed to be non-negative (is_nonneg is set), + * then the sample value of "var" is assumed to be non-negative when the * the function is called. If 1 is returned then the constraint * is not redundant and the sample value is made non-negative again before * the function returns. @@ -1447,7 +1467,7 @@ int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var) do { find_pivot(tab, var, var, -1, &row, &col); if (row == var->index) { - if (restore_row(tab, var) < -1) + if (var->is_nonneg && restore_row(tab, var) < -1) return -1; return 1; } @@ -1643,19 +1663,75 @@ int isl_tab_allocate_con(struct isl_tab *tab) return r; } -/* Add a variable to the tableau and allocate a column for it. - * Return the index into the variable array "var". +/* Move the entries in tab->var up one position, starting at "first", + * creating room for an extra entry at position "first". + * Since some of the entries of tab->row_var and tab->col_var contain + * indices into this array, they have to be updated accordingly. */ -int isl_tab_allocate_var(struct isl_tab *tab) +static int var_insert_entry(struct isl_tab *tab, int first) +{ + int i; + + if (tab->n_var >= tab->max_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "not enough room for new variable", return -1); + if (first > tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "invalid initial position", return -1); + + for (i = tab->n_var - 1; i >= first; --i) { + tab->var[i + 1] = tab->var[i]; + if (tab->var[i + 1].is_row) + tab->row_var[tab->var[i + 1].index]++; + else + tab->col_var[tab->var[i + 1].index]++; + } + + tab->n_var++; + + return 0; +} + +/* Drop the entry at position "first" in tab->var, moving all + * subsequent entries down. + * Since some of the entries of tab->row_var and tab->col_var contain + * indices into this array, they have to be updated accordingly. + */ +static int var_drop_entry(struct isl_tab *tab, int first) +{ + int i; + + if (first >= tab->n_var) + isl_die(isl_tab_get_ctx(tab), isl_error_internal, + "invalid initial position", return -1); + + tab->n_var--; + + for (i = first; i < tab->n_var; ++i) { + tab->var[i] = tab->var[i + 1]; + if (tab->var[i + 1].is_row) + tab->row_var[tab->var[i].index]--; + else + tab->col_var[tab->var[i].index]--; + } + + return 0; +} + +/* Add a variable to the tableau at position "r" and allocate a column for it. + * Return the index into the variable array "var", i.e., "r", + * or -1 on error. + */ +int isl_tab_insert_var(struct isl_tab *tab, int r) { - int r; int i; unsigned off = 2 + tab->M; isl_assert(tab->mat->ctx, tab->n_col < tab->mat->n_col, return -1); - isl_assert(tab->mat->ctx, tab->n_var < tab->max_var, return -1); - r = tab->n_var; + if (var_insert_entry(tab, r) < 0) + return -1; + tab->var[r].index = tab->n_col; tab->var[r].is_row = 0; tab->var[r].is_nonneg = 0; @@ -1668,7 +1744,6 @@ int isl_tab_allocate_var(struct isl_tab *tab) for (i = 0; i < tab->n_row; ++i) isl_int_set_si(tab->mat->row[i][off + tab->n_col], 0); - tab->n_var++; tab->n_col++; if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->var[r]) < 0) return -1; @@ -1676,6 +1751,17 @@ int isl_tab_allocate_var(struct isl_tab *tab) return r; } +/* Add a variable to the tableau and allocate a column for it. + * Return the index into the variable array "var". + */ +int isl_tab_allocate_var(struct isl_tab *tab) +{ + if (!tab) + return -1; + + return isl_tab_insert_var(tab, tab->n_var); +} + /* Add a row to the tableau. The row is given as an affine combination * of the original variables and needs to be expressed in terms of the * column variables. @@ -1753,13 +1839,22 @@ static int drop_row(struct isl_tab *tab, int row) return 0; } +/* Drop the variable in column "col" along with the column. + * The column is removed first because it may need to be moved + * into the last position and this process requires + * the contents of the col_var array in a state + * before the removal of the variable. + */ static int drop_col(struct isl_tab *tab, int col) { - isl_assert(tab->mat->ctx, tab->col_var[col] == tab->n_var - 1, return -1); + int var; + + var = tab->col_var[col]; if (col != tab->n_col - 1) swap_cols(tab, col, tab->n_col - 1); tab->n_col--; - tab->n_var--; + if (var_drop_entry(tab, var) < 0) + return -1; return 0; } @@ -1982,12 +2077,9 @@ int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq) var = &tab->con[r]; row = var->index; if (row_is_manifestly_zero(tab, row)) { - if (snap) { - if (isl_tab_rollback(tab, snap) < 0) - return -1; - } else - drop_row(tab, row); - return 0; + if (snap) + return isl_tab_rollback(tab, snap); + return drop_row(tab, row); } if (tab->bmap) { @@ -2545,37 +2637,37 @@ static int cut_to_hyperplane(struct isl_tab *tab, struct isl_tab_var *var) * even after the relaxation, so we need to restore it. * We therefore prefer to pivot a column up to a row, if possible. */ -struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) +int isl_tab_relax(struct isl_tab *tab, int con) { struct isl_tab_var *var; - unsigned off = 2 + tab->M; if (!tab) - return NULL; + return -1; var = &tab->con[con]; if (var->is_row && (var->index < 0 || var->index < tab->n_redundant)) isl_die(tab->mat->ctx, isl_error_invalid, - "cannot relax redundant constraint", goto error); + "cannot relax redundant constraint", return -1); if (!var->is_row && (var->index < 0 || var->index < tab->n_dead)) isl_die(tab->mat->ctx, isl_error_invalid, - "cannot relax dead constraint", goto error); + "cannot relax dead constraint", return -1); if (!var->is_row && !max_is_manifestly_unbounded(tab, var)) if (to_row(tab, var, 1) < 0) - goto error; + return -1; if (!var->is_row && !min_is_manifestly_unbounded(tab, var)) if (to_row(tab, var, -1) < 0) - goto error; + return -1; if (var->is_row) { isl_int_add(tab->mat->row[var->index][1], tab->mat->row[var->index][1], tab->mat->row[var->index][0]); if (restore_row(tab, var) < 0) - goto error; + return -1; } else { int i; + unsigned off = 2 + tab->M; for (i = 0; i < tab->n_row; ++i) { if (isl_int_is_zero(tab->mat->row[i][off + var->index])) @@ -2587,12 +2679,67 @@ struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) } if (isl_tab_push_var(tab, isl_tab_undo_relax, var) < 0) - goto error; + return -1; - return tab; -error: - isl_tab_free(tab); - return NULL; + return 0; +} + +/* Replace the variable v at position "pos" in the tableau "tab" + * by v' = v + shift. + * + * If the variable is in a column, then we first check if we can + * simply plug in v = v' - shift. The effect on a row with + * coefficient f/d for variable v is that the constant term c/d + * is replaced by (c - f * shift)/d. If shift is positive and + * f is negative for each row that needs to remain non-negative, + * then this is clearly safe. In other words, if the minimum of v + * is manifestly unbounded, then we can keep v in a column position. + * Otherwise, we can pivot it down to a row. + * Similarly, if shift is negative, we need to check if the maximum + * of is manifestly unbounded. + * + * If the variable is in a row (from the start or after pivoting), + * then the constant term c/d is replaced by (c + d * shift)/d. + */ +int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift) +{ + struct isl_tab_var *var; + + if (!tab) + return -1; + if (isl_int_is_zero(shift)) + return 0; + + var = &tab->var[pos]; + if (!var->is_row) { + if (isl_int_is_neg(shift)) { + if (!max_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, 1) < 0) + return -1; + } else { + if (!min_is_manifestly_unbounded(tab, var)) + if (to_row(tab, var, -1) < 0) + return -1; + } + } + + if (var->is_row) { + isl_int_addmul(tab->mat->row[var->index][1], + shift, tab->mat->row[var->index][0]); + } else { + int i; + unsigned off = 2 + tab->M; + + for (i = 0; i < tab->n_row; ++i) { + if (isl_int_is_zero(tab->mat->row[i][off + var->index])) + continue; + isl_int_submul(tab->mat->row[i][1], + shift, tab->mat->row[i][off + var->index]); + } + + } + + return 0; } /* Remove the sign constraint from constraint "con". @@ -3014,10 +3161,21 @@ enum isl_lp_result isl_tab_min(struct isl_tab *tab, return res; } +/* Is the constraint at position "con" marked as being redundant? + * If it is marked as representing an equality, then it is not + * considered to be redundant. + * Note that isl_tab_mark_redundant marks both the isl_tab_var as + * redundant and moves the corresponding row into the first + * tab->n_redundant positions (or removes the row, assigning it index -1), + * so the final test is actually redundant itself. + */ int isl_tab_is_redundant(struct isl_tab *tab, int con) { if (!tab) return -1; + if (con < 0 || con >= tab->n_con) + isl_die(isl_tab_get_ctx(tab), isl_error_invalid, + "position out of bounds", return -1); if (tab->con[con].is_zero) return 0; if (tab->con[con].is_redundant) @@ -3108,8 +3266,7 @@ static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) case isl_tab_undo_allocate: if (undo->u.var_index >= 0) { isl_assert(tab->mat->ctx, !var->is_row, return -1); - drop_col(tab, var->index); - break; + return drop_col(tab, var->index); } if (!var->is_row) { if (!max_is_manifestly_unbounded(tab, var)) { @@ -3122,8 +3279,7 @@ static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) if (to_row(tab, var, 0) < 0) return -1; } - drop_row(tab, var->index); - break; + return drop_row(tab, var->index); case isl_tab_undo_relax: return unrelax(tab, var); case isl_tab_undo_unrestrict: @@ -3219,6 +3375,9 @@ static int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNU static int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) { switch (undo->type) { + case isl_tab_undo_rational: + tab->rational = 0; + break; case isl_tab_undo_empty: tab->empty = 0; break; diff --git a/polly/lib/External/isl/isl_tab.h b/polly/lib/External/isl/isl_tab.h index cfae0c919f8..0b1ee4abe90 100644 --- a/polly/lib/External/isl/isl_tab.h +++ b/polly/lib/External/isl/isl_tab.h @@ -29,6 +29,7 @@ struct isl_tab_var { enum isl_tab_undo_type { isl_tab_undo_bottom, + isl_tab_undo_rational, isl_tab_undo_empty, isl_tab_undo_nonneg, isl_tab_undo_redundant, @@ -235,7 +236,7 @@ enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq); struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab); int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED; -struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED; +int isl_tab_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; @@ -267,6 +268,7 @@ __isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin( struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i); int isl_tab_mark_redundant(struct isl_tab *tab, int row) WARN_UNUSED; +int isl_tab_mark_rational(struct isl_tab *tab) WARN_UNUSED; int isl_tab_mark_empty(struct isl_tab *tab) WARN_UNUSED; struct isl_tab *isl_tab_dup(struct isl_tab *tab); struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2); @@ -274,6 +276,7 @@ int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new) WARN_UNUSED; int isl_tab_allocate_con(struct isl_tab *tab) WARN_UNUSED; int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new) WARN_UNUSED; int isl_tab_allocate_var(struct isl_tab *tab) WARN_UNUSED; +int isl_tab_insert_var(struct isl_tab *tab, int pos) WARN_UNUSED; int isl_tab_pivot(struct isl_tab *tab, int row, int col) WARN_UNUSED; int isl_tab_add_row(struct isl_tab *tab, isl_int *line) WARN_UNUSED; int isl_tab_row_is_redundant(struct isl_tab *tab, int row); @@ -301,4 +304,6 @@ int isl_tab_push_callback(struct isl_tab *tab, int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div, int (*add_ineq)(void *user, isl_int *), void *user); +int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift) WARN_UNUSED; + #endif diff --git a/polly/lib/External/isl/isl_test.c b/polly/lib/External/isl/isl_test.c index cb9075ad94b..1a4b7b0ecdf 100644 --- a/polly/lib/External/isl/isl_test.c +++ b/polly/lib/External/isl/isl_test.c @@ -28,6 +28,7 @@ #include <isl/union_map.h> #include <isl_factorization.h> #include <isl/schedule.h> +#include <isl/schedule_node.h> #include <isl_options_private.h> #include <isl/vertices.h> #include <isl/ast_build.h> @@ -104,11 +105,30 @@ static void test_parse_pwaff(isl_ctx *ctx, const char *str) isl_pw_aff_free(pwaff); } +/* Check that we can read an isl_multi_val from "str" without errors. + */ +static int test_parse_multi_val(isl_ctx *ctx, const char *str) +{ + isl_multi_val *mv; + + mv = isl_multi_val_read_from_str(ctx, str); + isl_multi_val_free(mv); + + return mv ? 0 : -1; +} + int test_parse(struct isl_ctx *ctx) { isl_map *map, *map2; const char *str, *str2; + if (test_parse_multi_val(ctx, "{ A[B[2] -> C[5, 7]] }") < 0) + return -1; + if (test_parse_multi_val(ctx, "[n] -> { [2] }") < 0) + return -1; + if (test_parse_multi_val(ctx, "{ A[4, infty, NaN, -1/2, 2/3] }") < 0) + return -1; + str = "{ [i] -> [-i] }"; map = isl_map_read_from_str(ctx, str); assert(map); @@ -1167,6 +1187,12 @@ struct { { "{ : 1 = 0 }", "{ : 1 = 0 }", "{ : }" }, { "[M] -> { [x] : exists (e0 = floor((-2 + x)/3): 3e0 = -2 + x) }", "[M] -> { [3M] }" , "[M] -> { [x] : 1 = 0 }" }, + { "{ [m, n, a, b] : a <= 2147 + n }", + "{ [m, n, a, b] : (m >= 1 and n >= 1 and a <= 2148 - m and " + "b <= 2148 - n and b >= 0 and b >= 2149 - n - a) or " + "(n >= 1 and a >= 0 and b <= 2148 - n - a and " + "b >= 0) }", + "{ [m, n, ku, kl] }" }, }; static int test_gist(struct isl_ctx *ctx) @@ -1179,20 +1205,20 @@ static int test_gist(struct isl_ctx *ctx) for (i = 0; i < ARRAY_SIZE(gist_tests); ++i) { int equal_input; - isl_basic_set *copy; + isl_set *set1, *set2, *copy; - bset1 = isl_basic_set_read_from_str(ctx, gist_tests[i].set); - bset2 = isl_basic_set_read_from_str(ctx, gist_tests[i].context); - copy = isl_basic_set_copy(bset1); - bset1 = isl_basic_set_gist(bset1, bset2); - bset2 = isl_basic_set_read_from_str(ctx, gist_tests[i].gist); - equal = isl_basic_set_is_equal(bset1, bset2); - isl_basic_set_free(bset1); - isl_basic_set_free(bset2); - bset1 = isl_basic_set_read_from_str(ctx, gist_tests[i].set); - equal_input = isl_basic_set_is_equal(bset1, copy); - isl_basic_set_free(bset1); - isl_basic_set_free(copy); + set1 = isl_set_read_from_str(ctx, gist_tests[i].set); + set2 = isl_set_read_from_str(ctx, gist_tests[i].context); + copy = isl_set_copy(set1); + set1 = isl_set_gist(set1, set2); + set2 = isl_set_read_from_str(ctx, gist_tests[i].gist); + equal = isl_set_is_equal(set1, set2); + isl_set_free(set1); + isl_set_free(set2); + set1 = isl_set_read_from_str(ctx, gist_tests[i].set); + equal_input = isl_set_is_equal(set1, copy); + isl_set_free(set1); + isl_set_free(copy); if (equal < 0 || equal_input < 0) return -1; if (!equal) @@ -1281,31 +1307,45 @@ int test_coalesce_set(isl_ctx *ctx, const char *str, int check_one) return 0; } +/* Inputs for coalescing tests with unbounded wrapping. + * "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; +} coalesce_unbounded_tests[] = { + { 1, "{ [x,y,z] : y + 2 >= 0 and x - y + 1 >= 0 and " + "-x - y + 1 >= 0 and -3 <= z <= 3;" + "[x,y,z] : -x+z + 20 >= 0 and -x-z + 20 >= 0 and " + "x-z + 20 >= 0 and x+z + 20 >= 0 and " + "-10 <= y <= 0}" }, + { 1, "{ [x,y] : 0 <= x,y <= 10; [5,y]: 4 <= y <= 11 }" }, + { 1, "{ [x,0,0] : -5 <= x <= 5; [0,y,1] : -5 <= y <= 5 }" }, + { 1, "{ [x,y] : 0 <= x <= 10 and 0 >= y >= -1 and x+y >= 0; [0,1] }" }, + { 1, "{ [x,y] : (0 <= x,y <= 4) or (2 <= x,y <= 5 and x + y <= 9) }" }, +}; + +/* Test the functionality of isl_set_coalesce with the bounded wrapping + * option turned off. + */ int test_coalesce_unbounded_wrapping(isl_ctx *ctx) { + int i; int r = 0; int bounded; bounded = isl_options_get_coalesce_bounded_wrapping(ctx); isl_options_set_coalesce_bounded_wrapping(ctx, 0); - if (test_coalesce_set(ctx, - "{[x,y,z] : y + 2 >= 0 and x - y + 1 >= 0 and " - "-x - y + 1 >= 0 and -3 <= z <= 3;" - "[x,y,z] : -x+z + 20 >= 0 and -x-z + 20 >= 0 and " - "x-z + 20 >= 0 and x+z + 20 >= 0 and " - "-10 <= y <= 0}", 1) < 0) - goto error; - if (test_coalesce_set(ctx, - "{[x,y] : 0 <= x,y <= 10; [5,y]: 4 <=y <= 11}", 1) < 0) - goto error; - if (test_coalesce_set(ctx, - "{[x,0,0] : -5 <= x <= 5; [0,y,1] : -5 <= y <= 5 }", 1) < 0) - goto error; - - if (0) { -error: + for (i = 0; i < ARRAY_SIZE(coalesce_unbounded_tests); ++i) { + const char *str = coalesce_unbounded_tests[i].str; + int check_one = coalesce_unbounded_tests[i].single_disjunct; + if (test_coalesce_set(ctx, str, check_one) >= 0) + continue; r = -1; + break; } isl_options_set_coalesce_bounded_wrapping(ctx, bounded); @@ -1431,11 +1471,106 @@ struct { "[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 " + { 1, "{ [i0, i1] : i0 <= 122 and i0 >= 1 and 128i1 >= -249 + i0 and " "i1 <= 0; " "[i0, 0] : i0 >= 123 and i0 <= 124 }" }, + { 1, "{ [0,0]; [1,1] }" }, + { 1, "[n] -> { [k] : 16k <= -1 + n and k >= 1; [0] : n >= 2 }" }, + { 1, "{ [k, ii, k - ii] : ii >= -6 + k and ii <= 6 and ii >= 1 and " + "ii <= k;" + "[k, 0, k] : k <= 6 and k >= 1 }" }, + { 1, "{ [i,j] : i = 4 j and 0 <= i <= 100;" + "[i,j] : 1 <= i <= 100 and i >= 4j + 1 and i <= 4j + 2 }" }, + { 1, "{ [x,y] : x % 2 = 0 and y % 2 = 0; [x,x] : x % 2 = 0 }" }, + { 1, "[n] -> { [1] : n >= 0;" + "[x] : exists (e0 = floor((x)/2): x >= 2 and " + "2e0 >= -1 + x and 2e0 <= x and 2e0 <= n) }" }, + { 1, "[n] -> { [x, y] : exists (e0 = floor((x)/2), e1 = floor((y)/3): " + "3e1 = y and x >= 2 and 2e0 >= -1 + x and " + "2e0 <= x and 2e0 <= n);" + "[1, y] : exists (e0 = floor((y)/3): 3e0 = y and " + "n >= 0) }" }, + { 1, "[t1] -> { [i0] : (exists (e0 = floor((63t1)/64): " + "128e0 >= -134 + 127t1 and t1 >= 2 and " + "64e0 <= 63t1 and 64e0 >= -63 + 63t1)) or " + "t1 = 1 }" }, + { 1, "{ [i, i] : exists (e0 = floor((1 + 2i)/3): 3e0 <= 2i and " + "3e0 >= -1 + 2i and i <= 9 and i >= 1);" + "[0, 0] }" }, + { 1, "{ [t1] : exists (e0 = floor((-11 + t1)/2): 2e0 = -11 + t1 and " + "t1 >= 13 and t1 <= 16);" + "[t1] : t1 <= 15 and t1 >= 12 }" }, + { 1, "{ [x,y] : x = 3y and 0 <= y <= 2; [-3,-1] }" }, + { 1, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-2] }" }, + { 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-2,-2] }" }, + { 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-1] }" }, + { 1, "{ [i] : exists j : i = 4 j and 0 <= i <= 100;" + "[i] : exists j : 1 <= i <= 100 and i >= 4j + 1 and " + "i <= 4j + 2 }" }, + { 1, "{ [c0] : (exists (e0 : c0 - 1 <= 3e0 <= c0)) or " + "(exists (e0 : 3e0 = -2 + c0)) }" }, + { 0, "[n, b0, t0] -> " + "{ [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12] : " + "(exists (e0 = floor((-32b0 + i4)/1048576), " + "e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and " + "n <= 2147483647 and b0 <= 32767 and b0 >= 0 and " + "32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 >= 8 + n and " + "3i4 <= -96 + 3t0 + i0 and 3i4 >= -95 - n + 3t0 + i0 and " + "i8 >= -157 + i0 - 4i4 and i8 >= 0 and " + "i8 <= -33 + i0 - 4i4 and 3i8 <= -91 + 4n - i0)) or " + "(exists (e0 = floor((-32b0 + i4)/1048576), " + "e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and " + "n <= 2147483647 and b0 <= 32767 and b0 >= 0 and " + "32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 <= 7 + n and " + "4i4 <= -3 + i0 and 3i4 <= -96 + 3t0 + i0 and " + "3i4 >= -95 - n + 3t0 + i0 and i8 >= -157 + i0 - 4i4 and " + "i8 >= 0 and i8 <= -4 + i0 - 3i4 and i8 <= -41 + i0));" + "[i0, i1, i2, i3, 0, i5, i6, i7, i8, i9, i10, i11, i12] : " + "(exists (e0 = floor((i8)/32): b0 = 0 and 32e0 = i8 and " + "n <= 2147483647 and t0 <= 31 and t0 >= 0 and i0 >= 11 and " + "i0 >= 96 - 3t0 and i0 <= 95 + n - 3t0 and i0 <= 7 + n and " + "i8 >= -40 + i0 and i8 <= -10 + i0)) }" }, }; +/* A specialized coalescing test case that would result + * in a segmentation fault or a failed assertion in earlier versions of isl. + */ +static int test_coalesce_special(struct isl_ctx *ctx) +{ + const char *str; + isl_map *map1, *map2; + + str = "[y] -> { [S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[1, o1]] : " + "(y = 201 and o1 <= 239 and o1 >= 212) or " + "(exists (e0 = [(y)/3]: 3e0 = y and y <= 198 and y >= 3 and " + "o1 <= 239 and o1 >= 212)) or " + "(exists (e0 = [(y)/3]: 3e0 = y and y <= 201 and y >= 3 and " + "o1 <= 241 and o1 >= 240));" + "[S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[0, o1]] : " + "(y = 2 and o1 <= 241 and o1 >= 212) or " + "(exists (e0 = [(-2 + y)/3]: 3e0 = -2 + y and y <= 200 and " + "y >= 5 and o1 <= 241 and o1 >= 212)) }"; + map1 = isl_map_read_from_str(ctx, str); + map1 = isl_map_align_divs(map1); + map1 = isl_map_coalesce(map1); + str = "[y] -> { [S_L220_OUT[] -> T7[]] -> " + "[[S_L309_IN[] -> T11[]] -> ce_imag2[o0, o1]] : " + "exists (e0 = [(-1 - y + o0)/3]: 3e0 = -1 - y + o0 and " + "y <= 201 and o0 <= 2 and o1 >= 212 and o1 <= 241 and " + "o0 >= 3 - y and o0 <= -2 + y and o0 >= 0) }"; + map2 = isl_map_read_from_str(ctx, str); + map2 = isl_map_union(map2, map1); + map2 = isl_map_align_divs(map2); + map2 = isl_map_coalesce(map2); + isl_map_free(map2); + if (!map2) + return -1; + + return 0; +} + /* 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. @@ -1453,6 +1588,8 @@ static int test_coalesce(struct isl_ctx *ctx) if (test_coalesce_unbounded_wrapping(ctx) < 0) return -1; + if (test_coalesce_special(ctx) < 0) + return -1; return 0; } @@ -2461,6 +2598,7 @@ static int test_subtract(isl_ctx *ctx) { int i; isl_union_map *umap1, *umap2; + isl_union_pw_multi_aff *upma1, *upma2; isl_union_set *uset; int equal; @@ -2482,6 +2620,24 @@ static int test_subtract(isl_ctx *ctx) "incorrect subtract domain result", return -1); } + for (i = 0; i < ARRAY_SIZE(subtract_domain_tests); ++i) { + upma1 = isl_union_pw_multi_aff_read_from_str(ctx, + subtract_domain_tests[i].minuend); + uset = isl_union_set_read_from_str(ctx, + subtract_domain_tests[i].subtrahend); + upma2 = isl_union_pw_multi_aff_read_from_str(ctx, + subtract_domain_tests[i].difference); + upma1 = isl_union_pw_multi_aff_subtract_domain(upma1, uset); + equal = isl_union_pw_multi_aff_plain_is_equal(upma1, upma2); + isl_union_pw_multi_aff_free(upma1); + isl_union_pw_multi_aff_free(upma2); + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "incorrect subtract domain result", return -1); + } + return 0; } @@ -2857,7 +3013,7 @@ struct { }; /* Test schedule construction based on conditional constraints. - * In particular, check the number of members in the outer band + * In particular, check the number of members in the outer band node * as an indication of whether tiling is possible or not. */ static int test_conditional_schedule_constraints(isl_ctx *ctx) @@ -2869,8 +3025,7 @@ static int test_conditional_schedule_constraints(isl_ctx *ctx) isl_union_map *validity; isl_schedule_constraints *sc; isl_schedule *schedule; - isl_band_list *list; - isl_band *band; + isl_schedule_node *node; int n_member; for (i = 0; i < ARRAY_SIZE(live_range_tests); ++i) { @@ -2889,11 +3044,12 @@ static int test_conditional_schedule_constraints(isl_ctx *ctx) sc = isl_schedule_constraints_set_conditional_validity(sc, condition, validity); schedule = isl_schedule_constraints_compute_schedule(sc); - list = isl_schedule_get_band_forest(schedule); - band = isl_band_list_get_band(list, 0); - n_member = isl_band_n_member(band); - isl_band_free(band); - isl_band_list_free(list); + node = isl_schedule_get_root(schedule); + while (node && + isl_schedule_node_get_type(node) != isl_schedule_node_band) + node = isl_schedule_node_first_child(node); + n_member = isl_schedule_node_band_n_member(node); + isl_schedule_node_free(node); isl_schedule_free(schedule); if (!schedule) @@ -5085,6 +5241,112 @@ static int test_dual(isl_ctx *ctx) } struct { + int scale_tile; + int shift_point; + const char *domain; + const char *schedule; + const char *sizes; + const char *tile; + const char *point; +} tile_tests[] = { + { 0, 0, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + }, + { 1, 0, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + }, + { 0, 1, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]", + "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]", + }, + { 1, 1, "[n] -> { S[i,j] : 0 <= i,j < n }", + "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]", + "{ [32,32] }", + "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]", + "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]", + }, +}; + +/* Basic tiling tests. Create a schedule tree with a domain and a band node, + * tile the band and then check if the tile and point bands have the + * expected partial schedule. + */ +static int test_tile(isl_ctx *ctx) +{ + int i; + int scale; + int shift; + + scale = isl_options_get_tile_scale_tile_loops(ctx); + shift = isl_options_get_tile_shift_point_loops(ctx); + + for (i = 0; i < ARRAY_SIZE(tile_tests); ++i) { + int opt; + int equal; + const char *str; + isl_union_set *domain; + isl_multi_union_pw_aff *mupa, *mupa2; + isl_schedule_node *node; + isl_multi_val *sizes; + + opt = tile_tests[i].scale_tile; + isl_options_set_tile_scale_tile_loops(ctx, opt); + opt = tile_tests[i].shift_point; + isl_options_set_tile_shift_point_loops(ctx, opt); + + str = tile_tests[i].domain; + domain = isl_union_set_read_from_str(ctx, str); + node = isl_schedule_node_from_domain(domain); + node = isl_schedule_node_child(node, 0); + str = tile_tests[i].schedule; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + node = isl_schedule_node_insert_partial_schedule(node, mupa); + str = tile_tests[i].sizes; + sizes = isl_multi_val_read_from_str(ctx, str); + node = isl_schedule_node_band_tile(node, sizes); + + str = tile_tests[i].tile; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + mupa2 = isl_schedule_node_band_get_partial_schedule(node); + equal = isl_multi_union_pw_aff_plain_is_equal(mupa, mupa2); + isl_multi_union_pw_aff_free(mupa); + isl_multi_union_pw_aff_free(mupa2); + + node = isl_schedule_node_child(node, 0); + + str = tile_tests[i].point; + mupa = isl_multi_union_pw_aff_read_from_str(ctx, str); + mupa2 = isl_schedule_node_band_get_partial_schedule(node); + if (equal >= 0 && equal) + equal = isl_multi_union_pw_aff_plain_is_equal(mupa, + mupa2); + isl_multi_union_pw_aff_free(mupa); + isl_multi_union_pw_aff_free(mupa2); + + isl_schedule_node_free(node); + + if (equal < 0) + return -1; + if (!equal) + isl_die(ctx, isl_error_unknown, + "unexpected result", return -1); + } + + isl_options_set_tile_scale_tile_loops(ctx, scale); + isl_options_set_tile_shift_point_loops(ctx, shift); + + return 0; +} + +struct { const char *name; int (*fn)(isl_ctx *ctx); } tests [] = { @@ -5121,6 +5383,7 @@ struct { { "affine", &test_aff }, { "injective", &test_injective }, { "schedule", &test_schedule }, + { "tile", &test_tile }, { "union_pw", &test_union_pw }, { "parse", &test_parse }, { "single-valued", &test_sv }, diff --git a/polly/lib/External/isl/isl_union_map.c b/polly/lib/External/isl/isl_union_map.c index be39088c8a9..0f19110db08 100644 --- a/polly/lib/External/isl/isl_union_map.c +++ b/polly/lib/External/isl/isl_union_map.c @@ -14,13 +14,13 @@ #define ISL_DIM_H #include <isl_map_private.h> +#include <isl_union_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> -#include <isl_union_map_private.h> #include <isl/union_set.h> #include <isl/deprecated/union_map_int.h> @@ -705,10 +705,28 @@ error: return NULL; } +/* Intersect "umap" with the parameter domain "set". + * + * If "set" does not have any constraints, then we can return immediately. + */ __isl_give isl_union_map *isl_union_map_intersect_params( __isl_take isl_union_map *umap, __isl_take isl_set *set) { + int is_universe; + + is_universe = isl_set_plain_is_universe(set); + if (is_universe < 0) + goto error; + if (is_universe) { + isl_set_free(set); + return umap; + } + return gen_bin_set_op(umap, set, &intersect_params_entry); +error: + isl_union_map_free(umap); + isl_set_free(set); + return NULL; } __isl_give isl_union_set *isl_union_set_intersect_params( @@ -1421,6 +1439,34 @@ __isl_give isl_union_map *isl_union_map_range_product( return bin_op(umap1, umap2, &range_product_entry); } +/* If data->map A -> B and "map2" C -> D have the same range space, + * then add (A, C) -> (B * D) to data->res. + */ +static int flat_domain_product_entry(void **entry, void *user) +{ + struct isl_union_map_bin_data *data = user; + isl_map *map2 = *entry; + + if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out, + map2->dim, isl_dim_out)) + return 0; + + map2 = isl_map_flat_domain_product(isl_map_copy(data->map), + isl_map_copy(map2)); + + data->res = isl_union_map_add_map(data->res, map2); + + return 0; +} + +/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D). + */ +__isl_give isl_union_map *isl_union_map_flat_domain_product( + __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) +{ + return bin_op(umap1, umap2, &flat_domain_product_entry); +} + static int flat_range_product_entry(void **entry, void *user) { struct isl_union_map_bin_data *data = user; @@ -1606,6 +1652,24 @@ error: return NULL; } +/* Remove redundant constraints in each of the basic maps of "umap". + * Since removing redundant constraints does not change the meaning + * or the space, the operation can be performed in-place. + */ +__isl_give isl_union_map *isl_union_map_remove_redundancies( + __isl_take isl_union_map *umap) +{ + return inplace(umap, &isl_map_remove_redundancies); +} + +/* Remove redundant constraints in each of the basic sets of "uset". + */ +__isl_give isl_union_set *isl_union_set_remove_redundancies( + __isl_take isl_union_set *uset) +{ + return isl_union_map_remove_redundancies(uset); +} + __isl_give isl_union_map *isl_union_map_coalesce( __isl_take isl_union_map *umap) { @@ -1805,6 +1869,39 @@ __isl_give isl_union_map *isl_union_map_domain_map( return cond_un_op(umap, &domain_map_entry); } +/* Construct an isl_pw_multi_aff that maps "map" to its domain and + * add the result to "res". + */ +static int domain_map_upma(__isl_take isl_map *map, void *user) +{ + isl_union_pw_multi_aff **res = user; + isl_multi_aff *ma; + isl_pw_multi_aff *pma; + + ma = isl_multi_aff_domain_map(isl_map_get_space(map)); + pma = isl_pw_multi_aff_alloc(isl_map_wrap(map), ma); + *res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma); + + return *res ? 0 : -1; + +} + +/* Return an isl_union_pw_multi_aff that maps a wrapped copy of "umap" + * to its domain. + */ +__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff( + __isl_take isl_union_map *umap) +{ + isl_union_pw_multi_aff *res; + + res = isl_union_pw_multi_aff_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &domain_map_upma, &res) < 0) + res = isl_union_pw_multi_aff_free(res); + + isl_union_map_free(umap); + return res; +} + static int range_map_entry(void **entry, void *user) { isl_map *map = *entry; @@ -1907,6 +2004,38 @@ __isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset) return cond_un_op(uset, &identity_entry); } +/* Construct an identity isl_pw_multi_aff on "set" and add it to *res. + */ +static int identity_upma(__isl_take isl_set *set, void *user) +{ + isl_union_pw_multi_aff **res = user; + isl_space *space; + isl_pw_multi_aff *pma; + + space = isl_space_map_from_set(isl_set_get_space(set)); + pma = isl_pw_multi_aff_identity(space); + pma = isl_pw_multi_aff_intersect_domain(pma, set); + *res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma); + + return *res ? 0 : -1; +} + +/* Return an identity function on "uset" in the form + * of an isl_union_pw_multi_aff. + */ +__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff( + __isl_take isl_union_set *uset) +{ + isl_union_pw_multi_aff *res; + + res = isl_union_pw_multi_aff_empty(isl_union_set_get_space(uset)); + if (isl_union_set_foreach_set(uset, &identity_upma, &res) < 0) + res = isl_union_pw_multi_aff_free(res); + + isl_union_set_free(uset); + return res; +} + /* If "map" is of the form [A -> B] -> C, then add A -> C to "res". */ static int domain_factor_domain_entry(void **entry, void *user) @@ -2174,6 +2303,80 @@ int isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1, return isl_union_map_is_strict_subset(uset1, uset2); } +/* Internal data structure for isl_union_map_is_disjoint. + * umap2 is the union map with which we are comparing. + * is_disjoint is initialized to 1 and is set to 0 as soon + * as the union maps turn out not to be disjoint. + */ +struct isl_union_map_is_disjoint_data { + isl_union_map *umap2; + int is_disjoint; +}; + +/* Check if "map" is disjoint from data->umap2 and abort + * the search if it is not. + */ +static int is_disjoint_entry(void **entry, void *user) +{ + struct isl_union_map_is_disjoint_data *data = user; + uint32_t hash; + struct isl_hash_table_entry *entry2; + isl_map *map = *entry; + + hash = isl_space_get_hash(map->dim); + entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table, + hash, &has_dim, map->dim, 0); + if (!entry2) + return 0; + + data->is_disjoint = isl_map_is_disjoint(map, entry2->data); + if (data->is_disjoint < 0 || !data->is_disjoint) + return -1; + + return 0; +} + +/* Are "umap1" and "umap2" disjoint? + */ +int isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1, + __isl_keep isl_union_map *umap2) +{ + struct isl_union_map_is_disjoint_data data = { NULL, 1 }; + + umap1 = isl_union_map_copy(umap1); + umap2 = isl_union_map_copy(umap2); + umap1 = isl_union_map_align_params(umap1, + isl_union_map_get_space(umap2)); + umap2 = isl_union_map_align_params(umap2, + isl_union_map_get_space(umap1)); + + if (!umap1 || !umap2) + goto error; + + data.umap2 = umap2; + if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table, + &is_disjoint_entry, &data) < 0 && + data.is_disjoint) + goto error; + + isl_union_map_free(umap1); + isl_union_map_free(umap2); + + return data.is_disjoint; +error: + isl_union_map_free(umap1); + isl_union_map_free(umap2); + return -1; +} + +/* Are "uset1" and "uset2" disjoint? + */ +int isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1, + __isl_keep isl_union_set *uset2) +{ + return isl_union_map_is_disjoint(uset1, uset2); +} + static int sample_entry(void **entry, void *user) { isl_basic_map **sample = (isl_basic_map **)user; @@ -3324,6 +3527,18 @@ __isl_give isl_union_map *isl_union_map_project_out( return data.res; } +/* Turn the "n" dimensions of type "type", starting at "first" + * into existentially quantified variables. + * Since the space of an isl_union_set only contains parameters, + * "type" is required to be equal to isl_dim_param. + */ +__isl_give isl_union_set *isl_union_set_project_out( + __isl_take isl_union_set *uset, + enum isl_dim_type type, unsigned first, unsigned n) +{ + return isl_union_map_project_out(uset, type, first, n); +} + /* Internal data structure for isl_union_map_involves_dims. * "first" and "n" are the arguments for the isl_map_involves_dims calls. */ @@ -3371,3 +3586,176 @@ int isl_union_map_involves_dims(__isl_keep isl_union_map *umap, return !excludes; } + +/* Internal data structure for isl_union_map_reset_range_space. + * "range" is the space from which to set the range space. + * "res" collects the results. + */ +struct isl_union_map_reset_range_space_data { + isl_space *range; + isl_union_map *res; +}; + +/* Replace the range space of "map" by the range space of data->range and + * add the result to data->res. + */ +static int reset_range_space(__isl_take isl_map *map, void *user) +{ + struct isl_union_map_reset_range_space_data *data = user; + isl_space *space; + + space = isl_map_get_space(map); + space = isl_space_domain(space); + space = isl_space_extend_domain_with_range(space, + isl_space_copy(data->range)); + map = isl_map_reset_space(map, space); + data->res = isl_union_map_add_map(data->res, map); + + return data->res ? 0 : -1; +} + +/* Replace the range space of all the maps in "umap" by + * the range space of "space". + * + * This assumes that all maps have the same output dimension. + * This function should therefore not be made publicly available. + * + * Since the spaces of the maps change, so do their hash value. + * We therefore need to create a new isl_union_map. + */ +__isl_give isl_union_map *isl_union_map_reset_range_space( + __isl_take isl_union_map *umap, __isl_take isl_space *space) +{ + struct isl_union_map_reset_range_space_data data = { space }; + + data.res = isl_union_map_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &reset_range_space, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_space_free(space); + isl_union_map_free(umap); + return data.res; +} + +/* Internal data structure for isl_union_map_order_at_multi_union_pw_aff. + * "mupa" is the function from which the isl_multi_pw_affs are extracted. + * "order" is applied to the extracted isl_multi_pw_affs that correspond + * to the domain and the range of each map. + * "res" collects the results. + */ +struct isl_union_order_at_data { + isl_multi_union_pw_aff *mupa; + __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2); + isl_union_map *res; +}; + +/* Intersect "map" with the result of applying data->order to + * the functions in data->mupa that apply to the domain and the range + * of "map" and add the result to data->res. + */ +static int order_at(__isl_take isl_map *map, void *user) +{ + struct isl_union_order_at_data *data = user; + isl_space *space; + isl_multi_pw_aff *mpa1, *mpa2; + isl_map *order; + + space = isl_space_domain(isl_map_get_space(map)); + mpa1 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space); + space = isl_space_range(isl_map_get_space(map)); + mpa2 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space); + order = data->order(mpa1, mpa2); + map = isl_map_intersect(map, order); + data->res = isl_union_map_add_map(data->res, map); + + return data->res ? 0 : -1; +} + +/* Intersect each map in "umap" with the result of calling "order" + * on the functions is "mupa" that apply to the domain and the range + * of the map. + */ +static __isl_give isl_union_map *isl_union_map_order_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, __isl_take isl_multi_union_pw_aff *mupa, + __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1, + __isl_take isl_multi_pw_aff *mpa2)) +{ + struct isl_union_order_at_data data; + + umap = isl_union_map_align_params(umap, + isl_multi_union_pw_aff_get_space(mupa)); + mupa = isl_multi_union_pw_aff_align_params(mupa, + isl_union_map_get_space(umap)); + data.mupa = mupa; + data.order = order; + data.res = isl_union_map_empty(isl_union_map_get_space(umap)); + if (isl_union_map_foreach_map(umap, &order_at, &data) < 0) + data.res = isl_union_map_free(data.res); + + isl_multi_union_pw_aff_free(mupa); + isl_union_map_free(umap); + return data.res; +} + +/* Return the subset of "umap" where the domain and the range + * have equal "mupa" values. + */ +__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_eq_map); +} + +/* Return the subset of "umap" where the domain has a lexicographically + * smaller "mupa" value than the range. + */ +__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_lex_lt_map); +} + +/* Return the subset of "umap" where the domain has a lexicographically + * greater "mupa" value than the range. + */ +__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff( + __isl_take isl_union_map *umap, + __isl_take isl_multi_union_pw_aff *mupa) +{ + return isl_union_map_order_at_multi_union_pw_aff(umap, mupa, + &isl_multi_pw_aff_lex_gt_map); +} + +/* Return the union of the elements in the list "list". + */ +__isl_give isl_union_set *isl_union_set_list_union( + __isl_take isl_union_set_list *list) +{ + int i, n; + isl_ctx *ctx; + isl_space *space; + isl_union_set *res; + + if (!list) + return NULL; + + ctx = isl_union_set_list_get_ctx(list); + space = isl_space_params_alloc(ctx, 0); + res = isl_union_set_empty(space); + + n = isl_union_set_list_n_union_set(list); + for (i = 0; i < n; ++i) { + isl_union_set *uset_i; + + uset_i = isl_union_set_list_get_union_set(list, i); + res = isl_union_set_union(res, uset_i); + } + + isl_union_set_list_free(list); + return res; +} diff --git a/polly/lib/External/isl/isl_union_map_private.h b/polly/lib/External/isl/isl_union_map_private.h index 7a502e7bdd5..5cd27838548 100644 --- a/polly/lib/External/isl/isl_union_map_private.h +++ b/polly/lib/External/isl/isl_union_map_private.h @@ -1,3 +1,4 @@ +#define isl_union_set_list isl_union_map_list #define isl_union_set isl_union_map #include <isl/union_map.h> #include <isl/union_set.h> @@ -8,3 +9,6 @@ struct isl_union_map { struct isl_hash_table table; }; + +__isl_give isl_union_map *isl_union_map_reset_range_space( + __isl_take isl_union_map *umap, __isl_take isl_space *space); diff --git a/polly/lib/External/isl/isl_union_templ.c b/polly/lib/External/isl/isl_union_templ.c index 4cd1d9dd183..729187138fd 100644 --- a/polly/lib/External/isl/isl_union_templ.c +++ b/polly/lib/External/isl/isl_union_templ.c @@ -1,11 +1,13 @@ /* * Copyright 2010 INRIA Saclay + * Copyright 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 */ #define xFN(TYPE,NAME) TYPE ## _ ## NAME @@ -116,13 +118,20 @@ __isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u) return u; } +/* Return the number of base expressions in "u". + */ +int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u) +{ + return u ? u->table.n : 0; +} + S(UNION,foreach_data) { int (*fn)(__isl_take PART *part, void *user); void *user; }; -static int call_on_copy(void **entry, void *user) +static int FN(UNION,call_on_copy)(void **entry, void *user) { PART *part = *entry; S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user; @@ -139,12 +148,12 @@ int FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u, return -1; return isl_hash_table_foreach(u->space->ctx, &u->table, - &call_on_copy, &data); + &FN(UNION,call_on_copy), &data); } /* Is the space of "entry" equal to "space"? */ -static int has_space(const void *entry, const void *val) +static int FN(UNION,has_space)(const void *entry, const void *val) { PART *part = (PART *)entry; isl_space *space = (isl_space *) val; @@ -154,12 +163,12 @@ static int has_space(const void *entry, const void *val) /* This function is not currently used by isl_aff.c. */ -static int has_domain_space(const void *entry, const void *val) +static int FN(UNION,has_domain_space)(const void *entry, const void *val) __attribute__ ((unused)); /* Is the domain space of "entry" equal to "space"? */ -static int has_domain_space(const void *entry, const void *val) +static int FN(UNION,has_domain_space)(const void *entry, const void *val) { PART *part = (PART *)entry; isl_space *space = (isl_space *) val; @@ -173,7 +182,7 @@ static int has_domain_space(const void *entry, const void *val) /* Is the domain space of "entry" equal to the domain of "space"? */ -static int has_same_domain_space(const void *entry, const void *val) +static int FN(UNION,has_same_domain_space)(const void *entry, const void *val) { PART *part = (PART *)entry; isl_space *space = (isl_space *) val; @@ -209,7 +218,7 @@ __isl_give PART *FN(FN(UNION,extract),PARTS)(__isl_keep UNION *u, hash = isl_space_get_hash(space); entry = isl_hash_table_find(u->space->ctx, &u->table, hash, - &has_space, space, 0); + &FN(UNION,has_space), space, 0); if (!entry) #ifdef HAS_TYPE return FN(PART,ZERO)(space, u->type); @@ -257,7 +266,8 @@ static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u, hash = isl_space_get_hash(part->dim); entry = isl_hash_table_find(u->space->ctx, &u->table, hash, - &has_same_domain_space, part->dim, 1); + &FN(UNION,has_same_domain_space), + part->dim, 1); if (!entry) goto error; @@ -304,7 +314,7 @@ __isl_give UNION *FN(FN(UNION,add),PARTS)(__isl_take UNION *u, return FN(UNION,add_part_generic)(u, part, 1); } -static int add_part(__isl_take PART *part, void *user) +static int FN(UNION,add_part)(__isl_take PART *part, void *user) { UNION **u = (UNION **)user; @@ -325,7 +335,7 @@ __isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u) #else dup = FN(UNION,ZERO)(isl_space_copy(u->space)); #endif - if (FN(FN(UNION,foreach),PARTS)(u, &add_part, &dup) < 0) + if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,add_part), &dup) < 0) goto error; return dup; error: @@ -344,7 +354,7 @@ __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u) return FN(UNION,dup)(u); } -static int free_u_entry(void **entry, void *user) +static int FN(UNION,free_u_entry)(void **entry, void *user) { PART *part = *entry; FN(PART,free)(part); @@ -359,7 +369,8 @@ __isl_null UNION *FN(UNION,free)(__isl_take UNION *u) if (--u->ref > 0) return NULL; - isl_hash_table_foreach(u->space->ctx, &u->table, &free_u_entry, NULL); + isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,free_u_entry), NULL); isl_hash_table_clear(&u->table); isl_space_free(u->space); free(u); @@ -371,8 +382,7 @@ S(UNION,align) { UNION *res; }; -#ifdef ALIGN_DOMAIN -static int align_entry(__isl_take PART *part, void *user) +static int FN(UNION,align_entry)(__isl_take PART *part, void *user) { isl_reordering *exp; S(UNION,align) *data = user; @@ -385,26 +395,41 @@ static int align_entry(__isl_take PART *part, void *user) return 0; } -#else -static int align_entry(__isl_take PART *part, void *user) + +/* Reorder the parameters of "u" according to the given reordering. + */ +static __isl_give UNION *FN(UNION,realign_domain)(__isl_take UNION *u, + __isl_take isl_reordering *r) { - isl_reordering *exp; - S(UNION,align) *data = user; + S(UNION,align) data = { NULL, NULL }; - exp = isl_reordering_extend_space(isl_reordering_copy(data->exp), - FN(PART,get_space)(part)); + if (!u || !r) + goto error; - data->res = FN(FN(UNION,add),PARTS)(data->res, - FN(PART,realign)(part, exp)); +#ifdef HAS_TYPE + data.res = FN(UNION,alloc)(isl_space_copy(r->dim), u->type, u->table.n); +#else + data.res = FN(UNION,alloc)(isl_space_copy(r->dim), u->table.n); +#endif + data.exp = r; + if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,align_entry), &data) < 0) + data.res = FN(UNION,free)(data.res); - return 0; + isl_reordering_free(data.exp); + FN(UNION,free)(u); + return data.res; +error: + FN(UNION,free)(u); + isl_reordering_free(r); + return NULL; } -#endif +/* Align the parameters of "u" to those of "model". + */ __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u, __isl_take isl_space *model) { - S(UNION,align) data = { NULL, NULL }; + isl_reordering *r; if (!u || !model) goto error; @@ -415,35 +440,20 @@ __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u, } model = isl_space_params(model); - data.exp = isl_parameter_alignment_reordering(u->space, model); - if (!data.exp) - goto error; - -#ifdef HAS_TYPE - data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim), - u->type, u->table.n); -#else - data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim), u->table.n); -#endif - if (FN(FN(UNION,foreach),PARTS)(u, &align_entry, &data) < 0) - goto error; - - isl_reordering_free(data.exp); - FN(UNION,free)(u); + r = isl_parameter_alignment_reordering(u->space, model); isl_space_free(model); - return data.res; + + return FN(UNION,realign_domain)(u, r); error: - isl_reordering_free(data.exp); - FN(UNION,free)(u); - FN(UNION,free)(data.res); isl_space_free(model); + FN(UNION,free)(u); return NULL; } /* Add "part" to *u, taking the union sum if "u" already has * a part defined on the same space as "part". */ -static int union_add_part(__isl_take PART *part, void *user) +static int FN(UNION,union_add_part)(__isl_take PART *part, void *user) { UNION **u = (UNION **)user; @@ -473,7 +483,7 @@ static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1, if (!u1 || !u2) goto error; - if (FN(FN(UNION,foreach),PARTS)(u2, &union_add_part, &u1) < 0) + if (FN(FN(UNION,foreach),PARTS)(u2, &FN(UNION,union_add_part), &u1) < 0) goto error; FN(UNION,free)(u2); @@ -516,7 +526,7 @@ S(UNION,match_bin_data) { * If so, call data->fn on the two elements and add the result to * data->res. */ -static int match_bin_entry(void **entry, void *user) +static int FN(UNION,match_bin_entry)(void **entry, void *user) { S(UNION,match_bin_data) *data = user; uint32_t hash; @@ -528,7 +538,8 @@ static int match_bin_entry(void **entry, void *user) space = FN(PART,get_space)(part); hash = isl_space_get_hash(space); entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table, - hash, &has_same_domain_space, space, 0); + hash, &FN(UNION,has_same_domain_space), + space, 0); isl_space_free(space); if (!entry2) return 0; @@ -553,14 +564,14 @@ static int match_bin_entry(void **entry, void *user) /* This function is currently only used from isl_polynomial.c * and not from isl_fold.c. */ -static __isl_give UNION *match_bin_op(__isl_take UNION *u1, +static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1, __isl_take UNION *u2, __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *)) __attribute__ ((unused)); /* For each pair of elements in "u1" and "u2" living in the same space, * call "fn" and collect the results. */ -static __isl_give UNION *match_bin_op(__isl_take UNION *u1, +static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1, __isl_take UNION *u2, __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *)) { @@ -580,7 +591,7 @@ static __isl_give UNION *match_bin_op(__isl_take UNION *u1, data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->table.n); #endif if (isl_hash_table_foreach(u1->space->ctx, &u1->table, - &match_bin_entry, &data) < 0) + &FN(UNION,match_bin_entry), &data) < 0) goto error; FN(UNION,free)(u1); @@ -604,7 +615,7 @@ __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2) #if DEFAULT_IS_ZERO return FN(UNION,union_add_)(u1, u2); #else - return match_bin_op(u1, u2, &FN(PART,add)); + return FN(UNION,match_bin_op)(u1, u2, &FN(PART,add)); #endif } @@ -613,7 +624,7 @@ __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2) */ __isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2) { - return match_bin_op(u1, u2, &FN(PART,sub)); + return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub)); } #endif @@ -623,7 +634,7 @@ S(UNION,any_set_data) { __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*); }; -static int any_set_entry(void **entry, void *user) +static int FN(UNION,any_set_entry)(void **entry, void *user) { S(UNION,any_set_data) *data = user; PW *pw = *entry; @@ -640,7 +651,7 @@ static int any_set_entry(void **entry, void *user) /* Update each element of "u" by calling "fn" on the element and "set". */ -static __isl_give UNION *any_set_op(__isl_take UNION *u, +static __isl_give UNION *FN(UNION,any_set_op)(__isl_take UNION *u, __isl_take isl_set *set, __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*)) { @@ -660,7 +671,7 @@ static __isl_give UNION *any_set_op(__isl_take UNION *u, data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n); #endif if (isl_hash_table_foreach(u->space->ctx, &u->table, - &any_set_entry, &data) < 0) + &FN(UNION,any_set_entry), &data) < 0) goto error; FN(UNION,free)(u); @@ -678,7 +689,7 @@ error: __isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u, __isl_take isl_set *set) { - return any_set_op(u, set, &FN(PW,intersect_params)); + return FN(UNION,any_set_op)(u, set, &FN(PW,intersect_params)); } /* Compute the gist of the domain of "u" with respect to @@ -687,7 +698,7 @@ __isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u, __isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u, __isl_take isl_set *set) { - return any_set_op(u, set, &FN(PW,gist_params)); + return FN(UNION,any_set_op)(u, set, &FN(PW,gist_params)); } S(UNION,match_domain_data) { @@ -696,7 +707,7 @@ S(UNION,match_domain_data) { __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*); }; -static int set_has_dim(const void *entry, const void *val) +static int FN(UNION,set_has_dim)(const void *entry, const void *val) { isl_set *set = (isl_set *)entry; isl_space *dim = (isl_space *)val; @@ -708,7 +719,7 @@ static int set_has_dim(const void *entry, const void *val) * of *entry, apply data->fn to *entry and this set (if any), and add * the result to data->res. */ -static int match_domain_entry(void **entry, void *user) +static int FN(UNION,match_domain_entry)(void **entry, void *user) { S(UNION,match_domain_data) *data = user; uint32_t hash; @@ -719,7 +730,7 @@ static int match_domain_entry(void **entry, void *user) space = FN(PW,get_domain_space)(pw); hash = isl_space_get_hash(space); entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table, - hash, &set_has_dim, space, 0); + hash, &FN(UNION,set_has_dim), space, 0); isl_space_free(space); if (!entry2) return 0; @@ -738,7 +749,7 @@ static int match_domain_entry(void **entry, void *user) * the set lives in the same space as the domain of PW * and collect the results. */ -static __isl_give UNION *match_domain_op(__isl_take UNION *u, +static __isl_give UNION *FN(UNION,match_domain_op)(__isl_take UNION *u, __isl_take isl_union_set *uset, __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*)) { @@ -758,7 +769,7 @@ static __isl_give UNION *match_domain_op(__isl_take UNION *u, data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n); #endif if (isl_hash_table_foreach(u->space->ctx, &u->table, - &match_domain_entry, &data) < 0) + &FN(UNION,match_domain_entry), &data) < 0) goto error; FN(UNION,free)(u); @@ -781,7 +792,64 @@ __isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u, if (isl_union_set_is_params(uset)) return FN(UNION,intersect_params)(u, isl_set_from_union_set(uset)); - return match_domain_op(u, uset, &FN(PW,intersect_domain)); + return FN(UNION,match_domain_op)(u, uset, &FN(PW,intersect_domain)); +} + +/* Internal data structure for isl_union_*_subtract_domain. + * uset is the set that needs to be removed from the domain. + * res collects the results. + */ +S(UNION,subtract_domain_data) { + isl_union_set *uset; + UNION *res; +}; + +/* Take the set (which may be empty) in data->uset that lives + * in the same space as the domain of "pw", subtract it from the domain + * of "pw" and add the result to data->res. + */ +static int FN(UNION,subtract_domain_entry)(__isl_take PW *pw, void *user) +{ + S(UNION,subtract_domain_data) *data = user; + isl_space *space; + isl_set *set; + + space = FN(PW,get_domain_space)(pw); + set = isl_union_set_extract_set(data->uset, space); + pw = FN(PW,subtract_domain)(pw, set); + data->res = FN(FN(UNION,add),PARTS)(data->res, pw); + + return 0; +} + +/* Subtract "uset' from the domain of "u". + */ +__isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u, + __isl_take isl_union_set *uset) +{ + S(UNION,subtract_domain_data) data; + + if (!u || !uset) + goto error; + + data.uset = uset; +#ifdef HAS_TYPE + data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type, + u->table.n); +#else + data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n); +#endif + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,subtract_domain_entry), &data) < 0) + data.res = FN(UNION,free)(data.res); + + FN(UNION,free)(u); + isl_union_set_free(uset); + return data.res; +error: + FN(UNION,free)(u); + isl_union_set_free(uset); + return NULL; } __isl_give UNION *FN(UNION,gist)(__isl_take UNION *u, @@ -789,7 +857,7 @@ __isl_give UNION *FN(UNION,gist)(__isl_take UNION *u, { if (isl_union_set_is_params(uset)) return FN(UNION,gist_params)(u, isl_set_from_union_set(uset)); - return match_domain_op(u, uset, &FN(PW,gist)); + return FN(UNION,match_domain_op)(u, uset, &FN(PW,gist)); } #ifndef NO_EVAL @@ -809,7 +877,8 @@ __isl_give isl_val *FN(UNION,eval)(__isl_take UNION *u, goto error; hash = isl_space_get_hash(space); entry = isl_hash_table_find(u->space->ctx, &u->table, - hash, &has_domain_space, space, 0); + hash, &FN(UNION,has_domain_space), + space, 0); isl_space_free(space); if (!entry) { v = isl_val_zero(isl_point_get_ctx(pnt)); @@ -826,7 +895,7 @@ error: } #endif -static int coalesce_entry(void **entry, void *user) +static int FN(UNION,coalesce_entry)(void **entry, void *user) { PW **pw = (PW **)entry; @@ -843,7 +912,7 @@ __isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u) return NULL; if (isl_hash_table_foreach(u->space->ctx, &u->table, - &coalesce_entry, NULL) < 0) + &FN(UNION,coalesce_entry), NULL) < 0) goto error; return u; @@ -852,7 +921,7 @@ error: return NULL; } -static int domain(__isl_take PART *part, void *user) +static int FN(UNION,domain_entry)(__isl_take PART *part, void *user) { isl_union_set **uset = (isl_union_set **)user; @@ -866,7 +935,7 @@ __isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u) isl_union_set *uset; uset = isl_union_set_empty(FN(UNION,get_space)(u)); - if (FN(FN(UNION,foreach),PARTS)(u, &domain, &uset) < 0) + if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,domain_entry), &uset) < 0) goto error; FN(UNION,free)(u); @@ -878,7 +947,7 @@ error: return NULL; } -static int mul_isl_int(void **entry, void *user) +static int FN(UNION,mul_isl_int_entry)(void **entry, void *user) { PW **pw = (PW **)entry; isl_int *v = user; @@ -916,7 +985,7 @@ __isl_give UNION *FN(UNION,mul_isl_int)(__isl_take UNION *u, isl_int v) u->type = isl_fold_type_negate(u->type); #endif if (isl_hash_table_foreach(u->space->ctx, &u->table, - &mul_isl_int, &v) < 0) + &FN(UNION,mul_isl_int_entry), v) < 0) goto error; return u; @@ -929,7 +998,7 @@ error: * * Return 0 on success and -1 on error. */ -static int scale_val(void **entry, void *user) +static int FN(UNION,scale_val_entry)(void **entry, void *user) { PW **pw = (PW **)entry; isl_val *v = user; @@ -978,7 +1047,8 @@ __isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u, if (isl_val_is_neg(v)) u->type = isl_fold_type_negate(u->type); #endif - if (isl_hash_table_foreach(u->space->ctx, &u->table, &scale_val, v) < 0) + if (isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,scale_val_entry), v) < 0) goto error; isl_val_free(v); @@ -1050,7 +1120,7 @@ S(UNION,plain_is_equal_data) int is_equal; }; -static int plain_is_equal_entry(void **entry, void *user) +static int FN(UNION,plain_is_equal_entry)(void **entry, void *user) { S(UNION,plain_is_equal_data) *data = user; uint32_t hash; @@ -1059,7 +1129,8 @@ static int plain_is_equal_entry(void **entry, void *user) hash = isl_space_get_hash(pw->dim); entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table, - hash, &has_same_domain_space, pw->dim, 0); + hash, &FN(UNION,has_same_domain_space), + pw->dim, 0); if (!entry2) { data->is_equal = 0; return -1; @@ -1092,7 +1163,7 @@ int FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2) data.u2 = u2; if (isl_hash_table_foreach(u1->space->ctx, &u1->table, - &plain_is_equal_entry, &data) < 0 && + &FN(UNION,plain_is_equal_entry), &data) < 0 && data.is_equal) goto error; @@ -1105,3 +1176,196 @@ error: FN(UNION,free)(u2); return -1; } + +#ifndef NO_NEG +/* Replace *entry by its opposite. + * + * Return 0 on success and -1 on error. + */ +static int FN(UNION,neg_entry)(void **entry, void *user) +{ + PW **pw = (PW **) entry; + + *pw = FN(PW,neg)(*pw); + + return *pw ? 0 : -1; +} + +/* Return the opposite of "u". + */ +__isl_give UNION *FN(UNION,neg)(__isl_take UNION *u) +{ + u = FN(UNION,cow)(u); + if (!u) + return NULL; + + if (isl_hash_table_foreach(u->space->ctx, &u->table, + &FN(UNION,neg_entry), NULL) < 0) + return FN(UNION,free)(u); + + return u; +} +#endif + +/* Internal data structure for isl_union_*_drop_dims. + * type, first and n are passed to isl_*_drop_dims. + * res collects the results. + */ +S(UNION,drop_dims_data) { + enum isl_dim_type type; + unsigned first; + unsigned n; + + UNION *res; +}; + +/* Drop the parameters specified by "data" from "part" and + * add the results to data->res. + */ +static int FN(UNION,drop_dims_entry)(__isl_take PART *part, void *user) +{ + S(UNION,drop_dims_data) *data = user; + + part = FN(PART,drop_dims)(part, data->type, data->first, data->n); + data->res = FN(FN(UNION,add),PARTS)(data->res, part); + if (!data->res) + return -1; + + return 0; +} + +/* Drop the specified parameters from "u". + * That is, type is required to be isl_dim_param. + */ +__isl_give UNION *FN(UNION,drop_dims)( __isl_take UNION *u, + enum isl_dim_type type, unsigned first, unsigned n) +{ + isl_space *space; + S(UNION,drop_dims_data) data = { type, first, n }; + + if (!u) + return NULL; + + if (type != isl_dim_param) + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "can only project out parameters", + return FN(UNION,free)(u)); + + space = FN(UNION,get_space)(u); + space = isl_space_drop_dims(space, type, first, n); +#ifdef HAS_TYPE + data.res = FN(UNION,alloc)(space, u->type, u->table.n); +#else + data.res = FN(UNION,alloc)(space, u->table.n); +#endif + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,drop_dims_entry), &data) < 0) + data.res = FN(UNION,free)(data.res); + + FN(UNION,free)(u); + + return data.res; +} + +/* Internal data structure for isl_union_*_set_dim_name. + * pos is the position of the parameter that needs to be renamed. + * s is the new name. + * res collects the results. + */ +S(UNION,set_dim_name_data) { + unsigned pos; + const char *s; + + UNION *res; +}; + +/* Change the name of the parameter at position data->pos of "part" to data->s + * and add the result to data->res. + */ +static int FN(UNION,set_dim_name_entry)(__isl_take PART *part, void *user) +{ + S(UNION,set_dim_name_data) *data = user; + + part = FN(PART,set_dim_name)(part, isl_dim_param, data->pos, data->s); + data->res = FN(FN(UNION,add),PARTS)(data->res, part); + if (!data->res) + return -1; + + return 0; +} + +/* Change the name of the parameter at position "pos" to "s". + * That is, type is required to be isl_dim_param. + */ +__isl_give UNION *FN(UNION,set_dim_name)(__isl_take UNION *u, + enum isl_dim_type type, unsigned pos, const char *s) +{ + S(UNION,set_dim_name_data) data = { pos, s }; + isl_space *space; + + if (!u) + return NULL; + + if (type != isl_dim_param) + isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, + "can only set parameter names", + return FN(UNION,free)(u)); + + space = FN(UNION,get_space)(u); + space = isl_space_set_dim_name(space, type, pos, s); +#ifdef HAS_TYPE + data.res = FN(UNION,alloc)(space, u->type, u->table.n); +#else + data.res = FN(UNION,alloc)(space, u->table.n); +#endif + + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,set_dim_name_entry), &data) < 0) + data.res = FN(UNION,free)(data.res); + + FN(UNION,free)(u); + + return data.res; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the space of "part" and add the result to *res. + */ +static int FN(UNION,reset_user_entry)(__isl_take PART *part, void *user) +{ + UNION **res = user; + + part = FN(PART,reset_user)(part); + *res = FN(FN(UNION,add),PARTS)(*res, part); + if (!*res) + return -1; + + return 0; +} + +/* Reset the user pointer on all identifiers of parameters and tuples + * of the spaces of "u". + */ +__isl_give UNION *FN(UNION,reset_user)(__isl_take UNION *u) +{ + isl_space *space; + UNION *res; + + if (!u) + return NULL; + + space = FN(UNION,get_space)(u); + space = isl_space_reset_user(space); +#ifdef HAS_TYPE + res = FN(UNION,alloc)(space, u->type, u->table.n); +#else + res = FN(UNION,alloc)(space, u->table.n); +#endif + if (FN(FN(UNION,foreach),PARTS)(u, + &FN(UNION,reset_user_entry), &res) < 0) + res = FN(UNION,free)(res); + + FN(UNION,free)(u); + + return res; +} diff --git a/polly/lib/External/isl/isl_val.c b/polly/lib/External/isl/isl_val.c index 4938c4c3823..2343153068b 100644 --- a/polly/lib/External/isl/isl_val.c +++ b/polly/lib/External/isl/isl_val.c @@ -936,6 +936,18 @@ error: return NULL; } +/* Given two integer values "v1" and "v2", return the residue of "v1" + * modulo "v2". + * + * This is a private copy of isl_val_mod for use in the generic + * isl_multi_*_mod_multi_val instantiated for isl_val. + */ +__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1, + __isl_take isl_val *v2) +{ + return isl_val_mod(v1, v2); +} + /* Given two integer values, return their greatest common divisor. */ __isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, __isl_take isl_val *v2) @@ -1566,8 +1578,6 @@ int isl_val_check_match_domain_space(__isl_keep isl_val *v, #define BASE val #define NO_DOMAIN -#define NO_INTERSECT_DOMAIN -#define NO_GIST #define NO_IDENTITY #define NO_FROM_BASE #define NO_MOVE_DIMS diff --git a/polly/lib/External/isl/isl_val_private.h b/polly/lib/External/isl/isl_val_private.h index 722fcf07639..ec1076dd06f 100644 --- a/polly/lib/External/isl/isl_val_private.h +++ b/polly/lib/External/isl/isl_val_private.h @@ -55,6 +55,8 @@ __isl_give isl_val *isl_val_scale_val(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_give isl_val *isl_val_scale_down_val(__isl_take isl_val *v1, __isl_take isl_val *v2); +__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1, + __isl_take isl_val *v2); int isl_val_plain_is_equal(__isl_keep isl_val *val1, __isl_keep isl_val *val2); diff --git a/polly/lib/External/isl/isl_yaml.h b/polly/lib/External/isl/isl_yaml.h new file mode 100644 index 00000000000..4d2c442ac50 --- /dev/null +++ b/polly/lib/External/isl/isl_yaml.h @@ -0,0 +1,18 @@ +#ifndef ISL_YAML_H +#define ISL_YAML_H + +#define ISL_YAML_INDENT_FLOW -1 + +enum isl_yaml_state { + isl_yaml_none, + isl_yaml_mapping_first_key_start, + isl_yaml_mapping_key_start, + isl_yaml_mapping_key, + isl_yaml_mapping_val_start, + isl_yaml_mapping_val, + isl_yaml_sequence_first_start, + isl_yaml_sequence_start, + isl_yaml_sequence +}; + +#endif diff --git a/polly/lib/External/isl/polyhedron_detect_equalities.c b/polly/lib/External/isl/polyhedron_detect_equalities.c index 567acec71df..c3dcec5712d 100644 --- a/polly/lib/External/isl/polyhedron_detect_equalities.c +++ b/polly/lib/External/isl/polyhedron_detect_equalities.c @@ -13,10 +13,16 @@ int main(int argc, char **argv) { struct isl_ctx *ctx = isl_ctx_alloc(); struct isl_basic_set *bset; + isl_printer *p; bset = isl_basic_set_read_from_file(ctx, stdin); bset = isl_basic_set_detect_equalities(bset); - isl_basic_set_print(bset, stdout, 0, "", "", ISL_FORMAT_POLYLIB); + + p = isl_printer_to_file(ctx, stdout); + p = isl_printer_set_output_format(p, ISL_FORMAT_POLYLIB); + p = isl_printer_print_basic_set(p, bset); + isl_printer_free(p); + isl_basic_set_free(bset); isl_ctx_free(ctx); diff --git a/polly/lib/External/isl/print.c b/polly/lib/External/isl/print.c index 5e3a5319636..4d724e72445 100644 --- a/polly/lib/External/isl/print.c +++ b/polly/lib/External/isl/print.c @@ -90,6 +90,12 @@ #define BASE multi_pw_aff #include <print_templ.c> #undef BASE +#define BASE union_pw_aff +#include <print_templ.c> +#undef BASE +#define BASE multi_union_pw_aff +#include <print_templ.c> +#undef BASE #define BASE point #include <print_templ.c> #undef BASE diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c b/polly/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c index c746460b4fa..7834ff4924a 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c @@ -6,14 +6,11 @@ } for (int c0 = 1; c0 < 3 * M - 1; c0 += 3) { S3((c0 + 2) / 3); - if (3 * M >= c0 + 8) { - for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) { - S6((c0 + 2) / 3, c1); - for (int c4 = (c0 + 5) / 3; c4 < c1; c4 += 1) - S5(c4, c1, (c0 + 2) / 3); - } - } else if (c0 + 5 == 3 * M) - S6(M - 1, M); + for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) { + S6((c0 + 2) / 3, c1); + for (int c4 = (c0 + 5) / 3; c4 < c1; c4 += 1) + S5(c4, c1, (c0 + 2) / 3); + } for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) S2(c1, (c0 + 2) / 3); } diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/classen.c b/polly/lib/External/isl/test_inputs/codegen/cloog/classen.c index ad7be335451..7ed3c45c9e8 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/classen.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/classen.c @@ -1,30 +1,20 @@ -{ - if (m == 1) { - S1(0, 1, 1, 1); - S8(0, 1); - } else if (m >= 2) { - S1(0, 1, 1, 1); - S3(0, 1, 1, 2, 1, 1, 1, 2); - S4(0, 1, 2, 2, 1, 1, 2, 2); - S2(0, 1, 1, 1, 1, 1, 2, 1); - S8(0, 1); - } - for (int c0 = 1; c0 < 2 * m - 3; c0 += 1) { +for (int c0 = 0; c0 < 2 * m - 1; c0 += 1) { + if (2 * m >= c0 + 3 && c0 >= 1) { if (c0 + 1 == m) { S5(m - 2, 1, m - 1, 1, m - 1, 1, m, 1); S1(m - 1, 1, m, 1); S3(m - 1, 1, m, 2, m, 1, m, 2); - } else if (m >= c0 + 2) { + } else if (c0 >= m) { + S5(c0 - 1, -m + c0 + 2, c0, -m + c0 + 2, m - 1, -m + c0 + 2, m, -m + c0 + 2); + S6(c0 - 1, -m + c0 + 1, c0, -m + c0 + 2, m, -m + c0 + 1, m, -m + c0 + 2); + S1(c0, -m + c0 + 2, m, -m + c0 + 2); + S3(c0, -m + c0 + 2, c0 + 1, -m + c0 + 3, m, -m + c0 + 2, m, -m + c0 + 3); + } else { S5(c0 - 1, 1, c0, 1, c0, 1, c0 + 1, 1); S1(c0, 1, c0 + 1, 1); S3(c0, 1, c0 + 1, 2, c0 + 1, 1, c0 + 1, 2); S4(c0, 1, c0 + 2, 2, c0 + 1, 1, c0 + 2, 2); S2(c0, 1, c0 + 1, 1, c0 + 1, 1, c0 + 2, 1); - } else { - S5(c0 - 1, -m + c0 + 2, c0, -m + c0 + 2, m - 1, -m + c0 + 2, m, -m + c0 + 2); - S6(c0 - 1, -m + c0 + 1, c0, -m + c0 + 2, m, -m + c0 + 1, m, -m + c0 + 2); - S1(c0, -m + c0 + 2, m, -m + c0 + 2); - S3(c0, -m + c0 + 2, c0 + 1, -m + c0 + 3, m, -m + c0 + 2, m, -m + c0 + 3); } for (int c2 = max(2, -m + c0 + 3); c2 <= min(m - 1, c0); c2 += 1) { S5(c0 - 1, c2, c0, c2, c0 - c2 + 1, c2, c0 - c2 + 2, c2); @@ -54,33 +44,17 @@ S4(c0, c0 + 1, c0 + 2, c0 + 2, 1, c0 + 1, 2, c0 + 2); S2(c0, c0 + 1, c0 + 1, c0 + 1, 1, c0 + 1, 2, c0 + 1); } - for (int c8 = max(1, -m + c0 + 2); c8 <= min(m, c0 + 1); c8 += 1) - S8(c0, c8); - } - if (m >= 2) { - if (m >= 3) { - S5(2 * m - 4, m - 1, 2 * m - 3, m - 1, m - 1, m - 1, m, m - 1); - S6(2 * m - 4, m - 2, 2 * m - 3, m - 1, m, m - 2, m, m - 1); - S1(2 * m - 3, m - 1, m, m - 1); - S3(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m); - S5(2 * m - 4, m, 2 * m - 3, m, m - 2, m, m - 1, m); - S7(2 * m - 4, m - 1, 2 * m - 2, m, m - 1, m - 1, m, m); - S6(2 * m - 4, m - 1, 2 * m - 3, m, m - 1, m - 1, m - 1, m); - S1(2 * m - 3, m, m - 1, m); - } else { - S5(0, 1, 1, 1, 1, 1, 2, 1); - S1(1, 1, 2, 1); - S3(1, 1, 2, 2, 2, 1, 2, 2); - S7(0, 1, 2, 2, 1, 1, 2, 2); - S6(0, 1, 1, 2, 1, 1, 1, 2); - S1(1, 2, 1, 2); - } - S2(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m); - for (int c8 = m - 1; c8 <= m; c8 += 1) - S8(2 * m - 3, c8); + } else if (m >= 2 && c0 == 0) { + S1(0, 1, 1, 1); + S3(0, 1, 1, 2, 1, 1, 1, 2); + S4(0, 1, 2, 2, 1, 1, 2, 2); + S2(0, 1, 1, 1, 1, 1, 2, 1); + } else if (m >= 2) { S5(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m); S6(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m); S1(2 * m - 2, m, m, m); - S8(2 * m - 2, m); - } + } else + S1(0, 1, 1, 1); + for (int c8 = max(1, -m + c0 + 2); c8 <= min(m, c0 + 1); c8 += 1) + S8(c0, c8); } diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/faber.c b/polly/lib/External/isl/test_inputs/codegen/cloog/faber.c index b398206b260..4e553d84078 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/faber.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/faber.c @@ -67,32 +67,25 @@ } } for (int c0 = 37; c0 <= 218; c0 += 1) { - for (int c1 = (c0 + 5) / 14 - 8; c1 < min(0, c0 / 14 - 5); c1 += 1) { - if (c0 <= 46 && c1 == -3) - S7(c0, -3, 6); - if (-77 * ((-3 * c1 + 1) / 5) + 447 >= 6 * c0) - S6(c0, c1, -((-2 * c1 + 3) / 5) + 9); - for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1) - S2(c0, c1, c2); - for (int c2 = -2 * c1 + 30; c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) - S1(c0, c1, c2); - } - if (c0 <= 148) - for (int c1 = max(0, (c0 + 5) / 14 - 8); c1 < c0 / 14 - 5; c1 += 1) { - if (c1 == 0) - S2(c0, 0, 24); + if (c0 <= 148) { + for (int c1 = (c0 + 5) / 14 - 8; c1 < c0 / 14 - 5; c1 += 1) { + if (c0 <= 46 && c1 == -3) + S7(c0, -3, 6); + if (77 * ((3 * c1 + 18) / 5) + 216 >= 6 * c0) + S6(c0, c1, -((-2 * c1 + 3) / 5) + 9); + for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1) + S2(c0, c1, c2); for (int c2 = max(c1 + 24, -2 * c1 + 30); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1) S1(c0, c1, c2); } - if (c0 >= 79 && c0 % 14 >= 9) { - for (int c2 = max((c0 - 70) / 14 + 24, (c0 - 70) / 14 - (3 * c0 + 14) / 14 + 49); c2 <= (c0 - 70) / 14 - (3 * c0 + 17) / 14 + 56; c2 += 1) - S1(c0, c0 / 14 - 5, c2); - } else if (c0 <= 69 && c0 % 14 >= 9) { - if (c0 <= 41) - S7(c0, -3, 6); - S6(c0, c0 / 14 - 5, 8); - for (int c2 = -((-c0 + 83) / 14) - (3 * c0 + 14) / 14 + 49; c2 <= -((-c0 + 83) / 14) - (3 * c0 + 17) / 14 + 56; c2 += 1) - S1(c0, c0 / 14 - 5, c2); + if (c0 % 14 >= 9) { + if (c0 <= 41) + S7(c0, -3, 6); + if (c0 <= 69) + S6(c0, c0 / 14 - 5, 8); + for (int c2 = max((c0 - 28) / 14 + 21, (c0 - 28) / 14 - (3 * c0 + 14) / 14 + 46); c2 <= (c0 - 28) / 14 - (3 * c0 + 17) / 14 + 53; c2 += 1) + S1(c0, c0 / 14 - 5, c2); + } } for (int c1 = (c0 + 5) / 14 - 5; c1 < 0; c1 += 1) { if (7 * c1 + 114 >= 2 * c0) @@ -125,7 +118,7 @@ S1(c0, c1, c2); } for (int c1 = c0 / 14 - 2; c1 <= 18; c1 += 1) { - for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, floord(2 * c0 - 7 * c1, 21) + 4); c2 += 1) + for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, (2 * c0 - 7 * c1 + 63) / 21 + 1); c2 += 1) S7(c0, c1, c2); for (int c2 = max(6, (c0 + 5) / 14 + 1); c2 <= min(min(c1, c0 / 14 + 3), -c1 + c1 / 2 + 18); c2 += 1) S5(c0, c1, c2); diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c b/polly/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c index c2423f01f5c..4308a9c9043 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c @@ -1,6 +1,3 @@ -if (g4 == 0 && N >= g0 + t1 + 1 && t1 <= 7) { - for (int c0 = t0; c0 <= min(127, N - g1 - 1); c0 += 16) - S1(g0 + t1, g1 + c0); -} else if (g4 >= 4 && N >= g0 + t1 + 1 && t1 <= 7 && g4 % 4 == 0) +if (N >= g0 + t1 + 1 && t1 <= 7 && g4 % 4 == 0) for (int c0 = t0; c0 <= min(127, N - g1 - 1); c0 += 16) S1(g0 + t1, g1 + c0); diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c b/polly/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c index 7053351603e..067e7515aa7 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c @@ -1,3 +1,3 @@ for (int c0 = 0; c0 <= 5 * n; c0 += 1) - for (int c1 = max(-((5 * n - c0 + 1) % 2) - n + c0 + 1, 2 * floord(c0 - 1, 3) + 2); c1 <= min(c0, n + c0 - (n + c0 + 2) / 3); c1 += 2) + for (int c1 = max(-((5 * n - c0 + 1) % 2) - n + c0 + 1, 2 * ((c0 + 2) / 3)); c1 <= min(c0, n + c0 - (n + c0 + 2) / 3); c1 += 2) S1((3 * c1 / 2) - c0, c0 - c1); diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/vivien.c b/polly/lib/External/isl/test_inputs/codegen/cloog/vivien.c index ce38c10e833..c4bd08b673a 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/vivien.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/vivien.c @@ -2,50 +2,50 @@ for (int c0 = -27 * n + 2; c0 <= 1; c0 += 1) S1(c0 - 1); for (int c0 = 2; c0 <= min(2 * n, n + 29); c0 += 1) { - if (c0 >= 3) { - if (2 * n >= c0 + 1) { - S4(c0 - c0 / 2 - 1, c0 / 2 + 1); - if (c0 + 2 >= 2 * n) { - for (int c2 = 1; c2 < -n + c0; c2 += 1) - S5(-n + c0, n, c2); - } else if (c0 >= 5) { - S4(c0 - c0 / 2 - 2, c0 / 2 + 2); - for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) - S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); - } - } - for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { - S4(-c1, c0 + c1); - S6(-c1 + 2, c0 + c1 - 2); - for (int c2 = 1; c2 <= -c1; c2 += 1) - S5(-c1 + 1, c0 + c1 - 1, c2); - } - if (2 * n >= c0 + 3 && c0 >= n + 2) { - S6(-n + c0 + 1, n - 1); - for (int c2 = 1; c2 < -n + c0; c2 += 1) - S5(-n + c0, n, c2); - } - if (c0 >= n + 3 && 2 * n >= c0 + 1) { - S6(-n + c0, n); - } else { - if (c0 >= 5 && n + 1 >= c0) { - S6(2, c0 - 2); - S1(c0 - 1); - } else if (n + 1 >= c0 && c0 <= 4) - S1(c0 - 1); - if (n + 1 >= c0) { - S6(1, c0 - 1); - } else if (n >= 3 && c0 == n + 2) { - S6(2, n); - S1(n + 1); - } + if (c0 >= 3 && 2 * n >= c0 + 1) { + S4(c0 - c0 / 2 - 1, c0 / 2 + 1); + if (c0 >= 5 && 2 * n >= c0 + 3) { + S4(c0 - c0 / 2 - 2, c0 / 2 + 2); + for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) + S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); } - if (c0 >= n + 3) - S1(c0 - 1); - if (n == 2 && c0 == 4) - S1(3); - } else + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { + S4(-c1, c0 + c1); + S6(-c1 + 2, c0 + c1 - 2); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (c0 >= 3 && n + 1 >= c0 && c0 <= 4) { + S1(c0 - 1); + } else if (c0 >= 5 && n + 1 >= c0) { + S6(2, c0 - 2); + S1(c0 - 1); + } + if (n >= 2 && c0 == n + 1) { + S6(1, n); + } else if (2 * n >= c0 + 3 && c0 >= n + 2) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } + if (2 * n >= c0 + 1 && c0 + 2 >= 2 * n) + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + if (c0 >= n + 3 && 2 * n >= c0 + 1) { + S6(-n + c0, n); + } else if (c0 >= 3 && n >= c0) { + S6(1, c0 - 1); + } else if (c0 == 2) { S1(1); + } else if (n >= 3 && c0 == n + 2) { + S6(2, n); + S1(n + 1); + } + if (c0 >= n + 3) + S1(c0 - 1); + if (n == 2 && c0 == 4) + S1(3); if (c0 % 2 == 0) S3(c0 / 2); for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1) diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/vivien2.c b/polly/lib/External/isl/test_inputs/codegen/cloog/vivien2.c index 7fe52ff319b..57fc55e6a6d 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/vivien2.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/vivien2.c @@ -9,37 +9,40 @@ for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1) S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2); } - for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { - S4(-c1, c0 + c1); - S6(-c1 + 2, c0 + c1 - 2); - for (int c2 = 1; c2 <= -c1; c2 += 1) - S5(-c1 + 1, c0 + c1 - 1, c2); - } - if (2 * n >= c0 + 3 && c0 >= n + 2) { - S6(-n + c0 + 1, n - 1); - for (int c2 = 1; c2 < -n + c0; c2 += 1) - S5(-n + c0, n, c2); - } else if (c0 + 2 >= 2 * n) + } + for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) { + S4(-c1, c0 + c1); + S6(-c1 + 2, c0 + c1 - 2); + for (int c2 = 1; c2 <= -c1; c2 += 1) + S5(-c1 + 1, c0 + c1 - 1, c2); + } + if (c0 >= 5 && n + 1 >= c0) { + S6(2, c0 - 2); + S1(c0 - 1); + if (c0 == n + 1) + S6(1, n); + } else if (c0 == 2) { + S1(1); + } else if (2 * n >= c0 + 3 && c0 >= n + 2) { + S6(-n + c0 + 1, n - 1); + for (int c2 = 1; c2 < -n + c0; c2 += 1) + S5(-n + c0, n, c2); + } else if (c0 <= 4) + S1(c0 - 1); + if (c0 >= 3 && n >= c0) { + S6(1, c0 - 1); + } else { + if (c0 + 2 >= 2 * n) for (int c2 = 1; c2 < -n + c0; c2 += 1) S5(-n + c0, n, c2); if (c0 >= n + 3) { S6(-n + c0, n); S1(c0 - 1); - } else { - if (c0 >= 5 && n + 1 >= c0) { - S6(2, c0 - 2); - S1(c0 - 1); - } else if (c0 <= 4) - S1(c0 - 1); - if (n + 1 >= c0) { - S6(1, c0 - 1); - } else { - S6(2, n); - S1(n + 1); - } + } else if (c0 == n + 2) { + S6(2, n); + S1(n + 1); } - } else - S1(1); + } if (c0 % 2 == 0) S3(c0 / 2); for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1) diff --git a/polly/lib/External/isl/test_inputs/codegen/cloog/yosr.c b/polly/lib/External/isl/test_inputs/codegen/cloog/yosr.c index 1c20057bd1b..93792b2fa34 100644 --- a/polly/lib/External/isl/test_inputs/codegen/cloog/yosr.c +++ b/polly/lib/External/isl/test_inputs/codegen/cloog/yosr.c @@ -1,12 +1,7 @@ -{ - for (int c0 = 1; c0 < n; c0 += 1) { - for (int c2 = c0 + 1; c2 <= n; c2 += 1) - S1(c0, c2); - for (int c1 = 1; c1 < c0; c1 += 1) - for (int c2 = c1 + 1; c2 <= n; c2 += 1) - S2(c1, c2, c0); - } - for (int c1 = 1; c1 < n; c1 += 1) +for (int c0 = 1; c0 <= n; c0 += 1) { + for (int c2 = c0 + 1; c2 <= n; c2 += 1) + S1(c0, c2); + for (int c1 = 1; c1 < c0; c1 += 1) for (int c2 = c1 + 1; c2 <= n; c2 += 1) - S2(c1, c2, n); + S2(c1, c2, c0); } diff --git a/polly/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c b/polly/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c index aab26208811..55942443710 100644 --- a/polly/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c +++ b/polly/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c @@ -1,5 +1,5 @@ for (int c0 = 0; c0 <= 15; c0 += 1) for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) - for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + floord(c0 + c1 - 1, 3) + 133); c2 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) s0(c0, c1, c2, c3); diff --git a/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c b/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c index aab26208811..55942443710 100644 --- a/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c +++ b/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c @@ -1,5 +1,5 @@ for (int c0 = 0; c0 <= 15; c0 += 1) for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) - for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + floord(c0 + c1 - 1, 3) + 133); c2 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) s0(c0, c1, c2, c3); diff --git a/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c b/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c index aab26208811..55942443710 100644 --- a/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c +++ b/polly/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c @@ -1,5 +1,5 @@ for (int c0 = 0; c0 <= 15; c0 += 1) for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1) - for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + floord(c0 + c1 - 1, 3) + 133); c2 += 1) + for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1) for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1) s0(c0, c1, c2, c3); diff --git a/polly/lib/External/isl/test_inputs/codegen/omega/substitution-1.c b/polly/lib/External/isl/test_inputs/codegen/omega/substitution-1.c index 486514c0433..51ab952e273 100644 --- a/polly/lib/External/isl/test_inputs/codegen/omega/substitution-1.c +++ b/polly/lib/External/isl/test_inputs/codegen/omega/substitution-1.c @@ -1,3 +1,3 @@ for (int c0 = 0; c0 <= 14; c0 += 1) - for (int c1 = max(2 * c0 - 12, -c0 + 3 * floord(c0 - 1, 2) + 3); c1 <= min(2 * c0, c0 / 2 + 9); c1 += 3) + for (int c1 = max(2 * c0 - 12, -c0 + 3 * ((c0 + 1) / 2)); c1 <= min(2 * c0, c0 / 2 + 9); c1 += 3) s0((2 * c0 - c1) / 3, (-c0 + 2 * c1) / 3); diff --git a/polly/lib/External/isl/test_inputs/codegen/unroll11.c b/polly/lib/External/isl/test_inputs/codegen/unroll11.c new file mode 100644 index 00000000000..c1fc5298a48 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/codegen/unroll11.c @@ -0,0 +1,8 @@ +{ + if (t1 >= 126) + S(0, t1 - 384); + S(0, t1 - 256); + if (t1 >= 126) + S(1, t1 - 384); + S(1, t1 - 256); +} diff --git a/polly/lib/External/isl/test_inputs/codegen/unroll11.in b/polly/lib/External/isl/test_inputs/codegen/unroll11.in new file mode 100644 index 00000000000..79445e20dce --- /dev/null +++ b/polly/lib/External/isl/test_inputs/codegen/unroll11.in @@ -0,0 +1,10 @@ +# Check that the most appropriate lower bound is selected +[t1,t2]->{ S[i,j] -> [i,j] : exists (alpha, beta : + 0 <= i <= 1 && + t1 = j+128alpha && + 0 <= j+2beta < 128 && + 510 <= t2+2beta <= 514 && + 0 <= 2beta - t2 <= 5 +)} +[t1,t2] -> {: 125 <= t1 <= 127 and 254 <= t2 < 257} +{[i,j] -> unroll[x]} |