From a749e09e184b2b0b6dde71af01c82dd427b3e3e2 Mon Sep 17 00:00:00 2001 From: Michael Kruse Date: Wed, 25 Jan 2023 09:56:22 -0600 Subject: [PATCH] [Polly] Update ISL to isl-0.25-193-g8621c60c. The bugfix https://reviews.llvm.org/D142308 might already have been fixed upstream. --- polly/lib/External/CMakeLists.txt | 2 + polly/lib/External/isl/AUTHORS | 11 +- polly/lib/External/isl/ChangeLog | 7 + polly/lib/External/isl/GIT_HEAD_ID | 2 +- polly/lib/External/isl/all.h | 1 + polly/lib/External/isl/basis_reduction_templ.c | 3 +- polly/lib/External/isl/cpp/cpp-checked.h.top | 32 +- polly/lib/External/isl/cpp/cpp.h.top | 11 + polly/lib/External/isl/doc/isl.bib | 4 +- polly/lib/External/isl/doc/user.pod | 208 +- polly/lib/External/isl/extract_key.c | 16 +- polly/lib/External/isl/flow_cmp.c | 18 +- polly/lib/External/isl/include/isl/aff.h | 14 + polly/lib/External/isl/include/isl/ast.h | 10 + polly/lib/External/isl/include/isl/hash.h | 2 + polly/lib/External/isl/include/isl/hmap.h | 20 +- polly/lib/External/isl/include/isl/hmap_templ.c | 160 +- polly/lib/External/isl/include/isl/id.h | 1 + .../lib/External/isl/include/isl/id_to_ast_expr.h | 4 + polly/lib/External/isl/include/isl/id_to_id.h | 4 + polly/lib/External/isl/include/isl/id_to_pw_aff.h | 4 + polly/lib/External/isl/include/isl/ilp.h | 4 + polly/lib/External/isl/include/isl/list.h | 9 +- polly/lib/External/isl/include/isl/map.h | 14 + .../External/isl/include/isl/map_to_basic_set.h | 4 + .../lib/External/isl/include/isl/polynomial_type.h | 3 + polly/lib/External/isl/include/isl/schedule_node.h | 7 + polly/lib/External/isl/include/isl/set.h | 3 + polly/lib/External/isl/include/isl/space.h | 11 + polly/lib/External/isl/include/isl/stream.h | 13 +- polly/lib/External/isl/include/isl/stride_info.h | 2 +- polly/lib/External/isl/include/isl/union_map.h | 14 + polly/lib/External/isl/interface/configure.ac | 2 +- polly/lib/External/isl/interface/cpp.cc | 170 +- polly/lib/External/isl/interface/cpp.h | 37 +- .../External/isl/interface/extract_interface.cc | 4 +- polly/lib/External/isl/interface/generator.cc | 18 + polly/lib/External/isl/interface/generator.h | 2 + polly/lib/External/isl/interface/plain_cpp.cc | 265 ++- polly/lib/External/isl/interface/plain_cpp.h | 50 +- polly/lib/External/isl/interface/python.cc | 214 ++- polly/lib/External/isl/interface/python.h | 4 +- polly/lib/External/isl/interface/template_cpp.cc | 245 ++- polly/lib/External/isl/interface/template_cpp.h | 2 +- polly/lib/External/isl/isl_aff.c | 802 ++++---- polly/lib/External/isl/isl_aff_map.c | 5 + polly/lib/External/isl/isl_aff_private.h | 5 + polly/lib/External/isl/isl_ast.c | 1648 ++++++++++++---- polly/lib/External/isl/isl_ast_build.c | 6 +- polly/lib/External/isl/isl_ast_build_expr.c | 663 ++++--- polly/lib/External/isl/isl_ast_build_private.h | 2 +- polly/lib/External/isl/isl_ast_codegen.c | 41 +- polly/lib/External/isl/isl_ast_graft.c | 150 +- polly/lib/External/isl/isl_ast_graft_private.h | 3 + .../External/isl/isl_ast_node_set_field_templ.c | 41 + polly/lib/External/isl/isl_ast_private.h | 26 +- polly/lib/External/isl/isl_box.c | 42 +- polly/lib/External/isl/isl_coalesce.c | 4 +- polly/lib/External/isl/isl_ctx.c | 2 +- polly/lib/External/isl/isl_dim_map.c | 2 +- polly/lib/External/isl/isl_flow.c | 20 +- polly/lib/External/isl/isl_fold.c | 5 +- polly/lib/External/isl/isl_from_range_templ.c | 29 + polly/lib/External/isl/isl_hash.c | 47 +- polly/lib/External/isl/isl_hash_private.h | 8 + polly/lib/External/isl/isl_id.c | 25 +- polly/lib/External/isl/isl_id_private.h | 1 - polly/lib/External/isl/isl_id_to_ast_expr.c | 7 +- polly/lib/External/isl/isl_id_to_id.c | 4 + polly/lib/External/isl/isl_id_to_pw_aff.c | 7 +- polly/lib/External/isl/isl_ilp.c | 28 +- polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c | 32 + polly/lib/External/isl/isl_input.c | 1182 +++++------- polly/lib/External/isl/isl_int_sioimath.h | 1 + polly/lib/External/isl/isl_list_read_templ.c | 24 +- polly/lib/External/isl/isl_list_read_yaml_templ.c | 40 + polly/lib/External/isl/isl_list_templ.c | 10 +- polly/lib/External/isl/isl_local.c | 70 +- polly/lib/External/isl/isl_local.h | 7 + polly/lib/External/isl/isl_local_space.c | 139 +- polly/lib/External/isl/isl_local_space_private.h | 2 + polly/lib/External/isl/isl_lp.c | 2 +- polly/lib/External/isl/isl_map.c | 111 +- polly/lib/External/isl/isl_map_simplify.c | 2 +- polly/lib/External/isl/isl_map_subtract.c | 4 +- polly/lib/External/isl/isl_map_to_basic_set.c | 4 + .../External/isl/isl_multi_add_constant_templ.c | 52 +- polly/lib/External/isl/isl_multi_apply_templ.c | 21 +- polly/lib/External/isl/isl_multi_arith_templ.c | 161 +- polly/lib/External/isl/isl_multi_bin_val_templ.c | 73 + polly/lib/External/isl/isl_multi_dim_id_templ.c | 30 +- polly/lib/External/isl/isl_multi_dims.c | 29 +- polly/lib/External/isl/isl_multi_floor.c | 14 +- .../lib/External/isl/isl_multi_from_tuple_templ.c | 46 + polly/lib/External/isl/isl_multi_move_dims_templ.c | 31 +- .../External/isl/isl_multi_pw_aff_pullback_templ.c | 73 + .../isl/isl_multi_read_no_explicit_domain_templ.c | 16 +- polly/lib/External/isl/isl_multi_templ.c | 278 ++- polly/lib/External/isl/isl_multi_un_op_templ.c | 33 + polly/lib/External/isl/isl_output.c | 345 +--- polly/lib/External/isl/isl_point.c | 62 +- polly/lib/External/isl/isl_point_private.h | 4 + polly/lib/External/isl/isl_polynomial.c | 17 +- polly/lib/External/isl/isl_polynomial_private.h | 19 +- polly/lib/External/isl/isl_power_templ.c | 31 +- .../lib/External/isl/isl_project_out_param_templ.c | 59 + polly/lib/External/isl/isl_pw_add_disjoint_templ.c | 93 + polly/lib/External/isl/isl_pw_eval.c | 15 + polly/lib/External/isl/isl_pw_fix_templ.c | 71 + polly/lib/External/isl/isl_pw_from_range_templ.c | 14 + polly/lib/External/isl/isl_pw_insert_dims_templ.c | 41 +- polly/lib/External/isl/isl_pw_morph_templ.c | 34 +- polly/lib/External/isl/isl_pw_move_dims_templ.c | 39 +- polly/lib/External/isl/isl_pw_neg_templ.c | 20 +- polly/lib/External/isl/isl_pw_print_templ.c | 55 + polly/lib/External/isl/isl_pw_pullback_templ.c | 23 +- polly/lib/External/isl/isl_pw_scale_templ.c | 42 + polly/lib/External/isl/isl_pw_split_dims_templ.c | 37 + polly/lib/External/isl/isl_pw_templ.c | 1379 ++++++-------- polly/lib/External/isl/isl_pw_un_op_templ.c | 36 + polly/lib/External/isl/isl_pw_union_opt.c | 2 +- polly/lib/External/isl/isl_read_from_str_templ.c | 27 + polly/lib/External/isl/isl_reordering.c | 104 +- polly/lib/External/isl/isl_reordering.h | 11 +- polly/lib/External/isl/isl_sample.c | 5 +- polly/lib/External/isl/isl_sample.h | 2 - polly/lib/External/isl/isl_schedule_constraints.c | 40 +- polly/lib/External/isl/isl_schedule_node.c | 116 +- polly/lib/External/isl/isl_schedule_read.c | 103 +- polly/lib/External/isl/isl_schedule_tree.c | 2 +- polly/lib/External/isl/isl_scheduler.c | 1997 ++------------------ polly/lib/External/isl/isl_scheduler.h | 289 +++ polly/lib/External/isl/isl_scheduler_clustering.c | 1565 +++++++++++++++ polly/lib/External/isl/isl_scheduler_clustering.h | 39 + polly/lib/External/isl/isl_scheduler_scc.c | 1209 ++++++++++++ polly/lib/External/isl/isl_scheduler_scc.h | 19 + polly/lib/External/isl/isl_set_to_ast_graft_list.c | 4 + polly/lib/External/isl/isl_set_to_ast_graft_list.h | 4 + polly/lib/External/isl/isl_space.c | 39 +- polly/lib/External/isl/isl_space_private.h | 3 + polly/lib/External/isl/isl_stream.c | 137 +- .../isl/isl_stream_read_pw_with_params_templ.c | 30 + .../isl/isl_stream_read_with_params_templ.c | 52 + polly/lib/External/isl/isl_stride.c | 4 - polly/lib/External/isl/isl_tab.c | 6 +- polly/lib/External/isl/isl_tab.h | 1 + polly/lib/External/isl/isl_test.c | 224 ++- polly/lib/External/isl/isl_test2.cc | 252 +++ polly/lib/External/isl/isl_test_cpp.cc | 36 + polly/lib/External/isl/isl_test_cpp17-checked.cc | 41 + polly/lib/External/isl/isl_test_cpp17-generic.cc | 68 + polly/lib/External/isl/isl_test_cpp17.cc | 78 + polly/lib/External/isl/isl_test_python.py | 55 + .../isl/isl_type_check_match_range_multi_val.c | 32 + polly/lib/External/isl/isl_union_map.c | 58 +- polly/lib/External/isl/isl_union_print_templ.c | 69 + polly/lib/External/isl/isl_union_single.c | 2 +- polly/lib/External/isl/isl_union_sub_templ.c | 27 + polly/lib/External/isl/isl_union_templ.c | 36 +- polly/lib/External/isl/isl_val.c | 30 +- polly/lib/External/isl/isl_vec.c | 30 + polly/lib/External/isl/isl_vec_private.h | 4 + polly/lib/External/isl/pip.c | 3 +- polly/lib/External/isl/python/isl.py.top | 12 + .../lib/External/isl/test_inputs/schedule/fork1.sc | 5 + .../lib/External/isl/test_inputs/schedule/fork1.st | 9 + .../lib/External/isl/test_inputs/schedule/fork2.sc | 5 + .../lib/External/isl/test_inputs/schedule/fork2.st | 6 + .../lib/External/isl/test_inputs/schedule/fork3.sc | 7 + .../lib/External/isl/test_inputs/schedule/fork3.st | 22 + .../lib/External/isl/test_inputs/schedule/nana.sc | 9 + .../lib/External/isl/test_inputs/schedule/nana.st | 13 + 172 files changed, 11148 insertions(+), 5972 deletions(-) create mode 100644 polly/lib/External/isl/isl_ast_node_set_field_templ.c create mode 100644 polly/lib/External/isl/isl_from_range_templ.c create mode 100644 polly/lib/External/isl/isl_hash_private.h create mode 100644 polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c create mode 100644 polly/lib/External/isl/isl_list_read_yaml_templ.c create mode 100644 polly/lib/External/isl/isl_multi_bin_val_templ.c create mode 100644 polly/lib/External/isl/isl_multi_from_tuple_templ.c create mode 100644 polly/lib/External/isl/isl_multi_pw_aff_pullback_templ.c create mode 100644 polly/lib/External/isl/isl_multi_un_op_templ.c create mode 100644 polly/lib/External/isl/isl_project_out_param_templ.c create mode 100644 polly/lib/External/isl/isl_pw_add_disjoint_templ.c create mode 100644 polly/lib/External/isl/isl_pw_fix_templ.c create mode 100644 polly/lib/External/isl/isl_pw_from_range_templ.c create mode 100644 polly/lib/External/isl/isl_pw_print_templ.c create mode 100644 polly/lib/External/isl/isl_pw_scale_templ.c create mode 100644 polly/lib/External/isl/isl_pw_split_dims_templ.c create mode 100644 polly/lib/External/isl/isl_pw_un_op_templ.c create mode 100644 polly/lib/External/isl/isl_read_from_str_templ.c create mode 100644 polly/lib/External/isl/isl_scheduler.h create mode 100644 polly/lib/External/isl/isl_scheduler_clustering.c create mode 100644 polly/lib/External/isl/isl_scheduler_clustering.h create mode 100644 polly/lib/External/isl/isl_scheduler_scc.c create mode 100644 polly/lib/External/isl/isl_scheduler_scc.h create mode 100644 polly/lib/External/isl/isl_stream_read_pw_with_params_templ.c create mode 100644 polly/lib/External/isl/isl_stream_read_with_params_templ.c create mode 100644 polly/lib/External/isl/isl_test_cpp17-checked.cc create mode 100644 polly/lib/External/isl/isl_test_cpp17-generic.cc create mode 100644 polly/lib/External/isl/isl_test_cpp17.cc create mode 100644 polly/lib/External/isl/isl_type_check_match_range_multi_val.c create mode 100644 polly/lib/External/isl/isl_union_print_templ.c create mode 100644 polly/lib/External/isl/isl_union_sub_templ.c create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork1.sc create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork1.st create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork2.sc create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork2.st create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork3.sc create mode 100644 polly/lib/External/isl/test_inputs/schedule/fork3.st create mode 100644 polly/lib/External/isl/test_inputs/schedule/nana.sc create mode 100644 polly/lib/External/isl/test_inputs/schedule/nana.st diff --git a/polly/lib/External/CMakeLists.txt b/polly/lib/External/CMakeLists.txt index c0a5b32..8a360e4 100644 --- a/polly/lib/External/CMakeLists.txt +++ b/polly/lib/External/CMakeLists.txt @@ -254,6 +254,8 @@ if (POLLY_BUNDLED_ISL) isl/isl_schedule_read.c isl/isl_schedule_tree.c isl/isl_scheduler.c + isl/isl_scheduler_clustering.c + isl/isl_scheduler_scc.c isl/isl_seq.c isl/isl_set_list.c isl/isl_set_to_ast_graft_list.c diff --git a/polly/lib/External/isl/AUTHORS b/polly/lib/External/isl/AUTHORS index c6aa5cd..4f7c2d6 100644 --- a/polly/lib/External/isl/AUTHORS +++ b/polly/lib/External/isl/AUTHORS @@ -23,17 +23,22 @@ isl was written by Domaine de Voluceau - Rocquencourt, B.P. 105 78153 Le Chesnay France -2015-2020 Polly Labs -2018-2020 Cerebras Systems +2015-2022 Polly Labs +2018-2021 Cerebras Systems 175 S San Antonio Rd Los Altos, CA USA +2021-2022 Cerebras Systems + 1237 E Arques Ave + Sunnyvale, CA + USA Contributions by Mythri Alle Riyadh Baghdadi Serge Belyshev +Basile Clement Albert Cohen Ray Donnelly Johannes Doerfert @@ -49,6 +54,7 @@ Michael Kruse Manjunath Kudlur Alexander Matz Chielo Newctle +Riccardo Mori Sebastian Pop Louis-Noel Pouchet Benoit Pradelle @@ -59,6 +65,7 @@ Malhar Thakkar Sergei Trofimovich Miheer Vaidya Sven van Haastregt +Matt Whitlock Oleksandr Zinenko The merge sort implementation was written by Jeffrey Stedfast. diff --git a/polly/lib/External/isl/ChangeLog b/polly/lib/External/isl/ChangeLog index 44acc42..49100a8 100644 --- a/polly/lib/External/isl/ChangeLog +++ b/polly/lib/External/isl/ChangeLog @@ -1,3 +1,10 @@ +version: 0.25 +date: Sat 02 Jul 2022 11:14:57 AM CEST +changes: + - support (type safe) user object on id in bindings + - more exports to (templated C++) bindings + - add some convenience functions +--- version: 0.24 date: Sun 25 Apr 2021 03:56:37 PM CEST changes: diff --git a/polly/lib/External/isl/GIT_HEAD_ID b/polly/lib/External/isl/GIT_HEAD_ID index 60beb8f..0aad105 100644 --- a/polly/lib/External/isl/GIT_HEAD_ID +++ b/polly/lib/External/isl/GIT_HEAD_ID @@ -1 +1 @@ -isl-0.24-69-g54aac5ac +isl-0.25-193-g8621c60c diff --git a/polly/lib/External/isl/all.h b/polly/lib/External/isl/all.h index dea77dd..73b8095 100644 --- a/polly/lib/External/isl/all.h +++ b/polly/lib/External/isl/all.h @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/polly/lib/External/isl/basis_reduction_templ.c b/polly/lib/External/isl/basis_reduction_templ.c index 5c03eab..290da7d 100644 --- a/polly/lib/External/isl/basis_reduction_templ.c +++ b/polly/lib/External/isl/basis_reduction_templ.c @@ -155,8 +155,7 @@ struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab) GBR_lp_get_obj_val(lp, &F_new); fixed = GBR_lp_is_fixed(lp); GBR_set_ui(alpha, 0); - } else - if (use_saved) { + } else if (use_saved) { row = GBR_lp_next_row(lp); GBR_set(F_new, F_saved); fixed = fixed_saved; diff --git a/polly/lib/External/isl/cpp/cpp-checked.h.top b/polly/lib/External/isl/cpp/cpp-checked.h.top index be29b97..6d62fb1 100644 --- a/polly/lib/External/isl/cpp/cpp-checked.h.top +++ b/polly/lib/External/isl/cpp/cpp-checked.h.top @@ -17,6 +17,11 @@ #include #include +#if __cplusplus >= 201703L +#include +#include +#endif + namespace isl { namespace checked { @@ -95,18 +100,23 @@ inline boolean manage(isl_bool val) { } class ctx { - isl_ctx *ptr; + isl_ctx *ptr; public: - /* implicit */ ctx(isl_ctx *ctx) - : ptr(ctx) {} - isl_ctx *release() { - auto tmp = ptr; - ptr = nullptr; - return tmp; - } - isl_ctx *get() { - return ptr; - } + /* implicit */ ctx(isl_ctx *ctx) : ptr(ctx) {} + isl_ctx *release() { + auto tmp = ptr; + ptr = nullptr; + return tmp; + } + isl_ctx *get() { + return ptr; + } +#if __cplusplus >= 201703L + static void free_user(void *user) { + std::any *p = static_cast(user); + delete p; + } +#endif }; /* Class encapsulating an isl_stat value. diff --git a/polly/lib/External/isl/cpp/cpp.h.top b/polly/lib/External/isl/cpp/cpp.h.top index 15282b1..9af6f48 100644 --- a/polly/lib/External/isl/cpp/cpp.h.top +++ b/polly/lib/External/isl/cpp/cpp.h.top @@ -18,6 +18,11 @@ #include #include +#if __cplusplus >= 201703L +#include +#include +#endif + /* ISL_USE_EXCEPTIONS should be defined to 1 if exceptions are available. * gcc and clang define __cpp_exceptions; MSVC and xlC define _CPPUNWIND. * Older versions of gcc (e.g., 4.9) only define __EXCEPTIONS. @@ -46,6 +51,12 @@ public: isl_ctx *get() { return ptr; } +#if __cplusplus >= 201703L + static void free_user(void *user) { + std::any *p = static_cast(user); + delete p; + } +#endif }; /* Macros hiding try/catch. diff --git a/polly/lib/External/isl/doc/isl.bib b/polly/lib/External/isl/doc/isl.bib index 42074b2..51fdcab 100644 --- a/polly/lib/External/isl/doc/isl.bib +++ b/polly/lib/External/isl/doc/isl.bib @@ -198,7 +198,7 @@ @misc{barvinok-0.22, author = {Sven Verdoolaege}, title = {{\texttt{barvinok}}, version 0.22}, - howpublished = {Available from \url{http://barvinok.gforge.inria.fr/}}, + howpublished = {Available from \url{https://barvinok.sourceforge.io/}}, year = 2006 } @@ -437,7 +437,7 @@ their correctness. year = 2014, month = Jan, address = {Vienna, Austria}, - url = {http://impact.gforge.inria.fr/impact2014/papers/impact2014-verdoolaege.pdf}, + url = {https://acohen.gitlabpages.inria.fr/impact/impact2014/papers/impact2014-verdoolaege.pdf}, abstract = { Schedules in the polyhedral model, both those that represent the original execution order and those produced by scheduling algorithms, naturally have the diff --git a/polly/lib/External/isl/doc/user.pod b/polly/lib/External/isl/doc/user.pod index 1e8d6a9..e0433a0 100644 --- a/polly/lib/External/isl/doc/user.pod +++ b/polly/lib/External/isl/doc/user.pod @@ -343,7 +343,7 @@ under the MIT license. The source of C can be obtained either as a tarball or from the git repository. Both are available from -L. +L. The installation process depends on how you obtained the source. @@ -422,11 +422,11 @@ for values out of the 32 bit range. In most applications, C will run fastest with the C option, followed by C and C, the slowest. -=item C<--with-gmp-prefix> +=item C<--with-gmp-prefix=>I Installation prefix for C (architecture-independent files). -=item C<--with-gmp-exec-prefix> +=item C<--with-gmp-exec-prefix=>I Installation prefix for C (architecture-dependent files). @@ -436,12 +436,47 @@ Installation prefix for C (architecture-dependent files). make -=item 4 Install (optional) +=item 4 Test (optional) + + make check + +=item 5 Install (optional) make install =back +=head2 Building the foreign language bindings + +The tarball already contains the generated foreign language bindings, +but they are not included in the git repository. +Building the C++ and Python bindings relies on the LLVM/clang libraries, +see C. +The C script will not assume that these are available +on the system. +To enable building the foreign language bindings, +one of the following options needs to be specified. + +=over + +=item C<--with-clang=system> + +Use the system clang libraries (installed in a default location). + +=item C<--with-clang-prefix=>I + +Use the system clang libraries installed in I. + +=back + +It is best to use the latest release of the clang libraries (14.0), +although any release since 2.9 should work as well. +Note that if you build the clang libraries from source, +then you need to make sure they are also installed (using C). +If the compiler that was used to compile the clang libraries +is different from the default C++ compiler, then use C +to specify this non-default C++ compiler when running C's C<./configure>. + =head1 Integer Set Library =head2 Memory Management @@ -971,6 +1006,8 @@ using the following functions. __isl_give isl_id *isl_id_set_free_user( __isl_take isl_id *id, void (*free_user)(void *user)); + void (*isl_id_get_free_user(__isl_keep isl_id *id)) + (void *user); __isl_give isl_id *isl_id_copy(isl_id *id); __isl_null isl_id *isl_id_free(__isl_take isl_id *id); @@ -982,6 +1019,7 @@ using the following functions. The callback set by C is called on the user pointer when the last reference to the C is freed. +This callback can be retrieved using C. Note that C returns a pointer to some internal data structure, so the result can only be used while the corresponding C is alive. @@ -3739,6 +3777,9 @@ then create a piecewise expression over a given domain. __isl_give isl_pw_aff *isl_pw_aff_val_on_domain( __isl_take isl_set *domain, __isl_take isl_val *v); + __isl_give isl_pw_aff *isl_set_pw_aff_on_domain_val( + __isl_take isl_set *domain, + __isl_take isl_val *v); __isl_give isl_pw_multi_aff * isl_pw_multi_aff_multi_val_on_domain( __isl_take isl_set *domain, @@ -3750,9 +3791,17 @@ then create a piecewise expression over a given domain. __isl_give isl_pw_aff *isl_pw_aff_param_on_domain_id( __isl_take isl_set *domain, __isl_take isl_id *id); + __isl_give isl_pw_aff *isl_set_param_pw_aff_on_domain_id( + __isl_take isl_set *domain, + __isl_take isl_id *id); -C is an alternative name -for C. +C is an alternative name +for C. +Similarly for the pair +C and +C and +for the pair C and +C. As a convenience, a piecewise multiple expression can also be created from a piecewise expression. @@ -4300,6 +4349,10 @@ Objects can be read from input using the following functions. __isl_give isl_multi_val *isl_multi_val_read_from_str( isl_ctx *ctx, const char *str); + #include + __isl_give isl_space *isl_space_read_from_str( + isl_ctx *ctx, const char *str); + #include __isl_give isl_basic_set *isl_basic_set_read_from_file( isl_ctx *ctx, FILE *input); @@ -4435,6 +4488,9 @@ To actually print something, use #include __isl_give isl_printer *isl_printer_print_val( __isl_take isl_printer *p, __isl_keep isl_val *v); + __isl_give isl_printer *isl_printer_print_multi_val( + __isl_take isl_printer *p, + __isl_keep isl_multi_val *mv); #include __isl_give isl_printer *isl_printer_print_basic_set( @@ -4462,11 +4518,6 @@ To actually print something, use __isl_take isl_printer *p, __isl_keep isl_union_map *umap); - #include - __isl_give isl_printer *isl_printer_print_multi_val( - __isl_take isl_printer *p, - __isl_keep isl_multi_val *mv); - #include __isl_give isl_printer *isl_printer_print_multi_id( __isl_take isl_printer *p, @@ -4801,6 +4852,8 @@ can be found then assign C<1> to C<*modulo> and C<1> to C<*residue>. __isl_keep isl_set *set, int pos); __isl_give isl_val *isl_set_get_stride( __isl_keep isl_set *set, int pos); + __isl_give isl_fixed_box *isl_set_get_lattice_tile( + __isl_keep isl_set *set); #include __isl_give isl_stride_info * @@ -4831,6 +4884,8 @@ can be extracted from the returned C using the functions described under "Box hull" in L. Note that the C object returned by C is always valid. +The function C collects the same stride +information over all set dimensions. For the other functions, the stride and offset can be extracted from the returned object using the following functions. @@ -5484,6 +5539,18 @@ in the domain of the input function. __isl_take isl_space *space); __isl_give isl_space *isl_space_params( __isl_take isl_space *space); + __isl_give isl_space * + isl_space_domain_wrapped_domain( + __isl_take isl_space *space); + __isl_give isl_space * + isl_space_domain_wrapped_range( + __isl_take isl_space *space); + __isl_give isl_space * + isl_space_range_wrapped_domain( + __isl_take isl_space *space); + __isl_give isl_space * + isl_space_range_wrapped_range( + __isl_take isl_space *space); #include __isl_give isl_local_space *isl_local_space_domain( @@ -5514,6 +5581,8 @@ in the domain of the input function. __isl_take isl_basic_set *bset); __isl_give isl_set *isl_set_params(__isl_take isl_set *set); +The function C returns the domain +of the binary relation wrapped inside the domain of the input. The function C returns a relation that projects the input set onto the given set dimensions. @@ -5521,6 +5590,12 @@ that projects the input set onto the given set dimensions. __isl_give isl_basic_map *isl_basic_map_project_out( __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, unsigned n); + __isl_give isl_map *isl_map_project_out_param_id( + __isl_take isl_map *map, + __isl_take isl_id *id); + __isl_give isl_map *isl_map_project_out_param_id_list( + __isl_take isl_map *map, + __isl_take isl_id_list *list); __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, enum isl_dim_type type, unsigned first, unsigned n); __isl_give isl_map *isl_map_project_out_all_params( @@ -5550,6 +5625,14 @@ The function C can only project out parameters. #include + __isl_give isl_union_map * + isl_union_map_project_out_param_id( + __isl_take isl_union_map *umap, + __isl_take isl_id *id); + __isl_give isl_union_map * + isl_union_map_project_out_param_id_list( + __isl_take isl_union_map *umap, + __isl_take isl_id_list *list); __isl_give isl_union_map *isl_union_map_project_out( __isl_take isl_union_map *umap, enum isl_dim_type type, unsigned first, unsigned n); @@ -6527,6 +6610,10 @@ there is one, negative infinity or infinity if the problem is unbounded and NaN if the problem is empty. #include + __isl_give isl_val *isl_pw_aff_min_val( + __isl_take isl_pw_aff *pa); + __isl_give isl_val *isl_pw_aff_max_val( + __isl_take isl_pw_aff *pa); __isl_give isl_multi_val * isl_pw_multi_aff_min_multi_val( __isl_take isl_pw_multi_aff *pma); @@ -7361,6 +7448,14 @@ the same (number of) parameters. isl_map_intersect_range_factor_range( __isl_take isl_map *map, __isl_take isl_map *factor); + __isl_give isl_map * + isl_map_intersect_domain_wrapped_domain( + __isl_take isl_map *map, + __isl_take isl_set *domain); + __isl_give isl_map * + isl_map_intersect_range_wrapped_domain( + __isl_take isl_map *map, + __isl_take isl_set *domain); #include __isl_give isl_union_set *isl_union_set_intersect_params( @@ -7415,6 +7510,14 @@ the same (number of) parameters. isl_union_map_intersect_range_factor_range( __isl_take isl_union_map *umap, __isl_take isl_union_map *factor); + __isl_give isl_union_map * + isl_union_map_intersect_domain_wrapped_domain_union_set( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *domain); + __isl_give isl_union_map * + isl_union_map_intersect_range_wrapped_domain_union_set( + __isl_take isl_union_map *umap, + __isl_take isl_union_set *domain); #include __isl_give isl_pw_aff *isl_pw_aff_intersect_domain( @@ -9053,6 +9156,10 @@ only defined on the shared definition domain of the arguments. isl_multi_aff_scale_down_multi_val( __isl_take isl_multi_aff *ma, __isl_take isl_multi_val *mv); + __isl_give isl_pw_multi_aff * + isl_pw_multi_aff_scale_down_multi_val( + __isl_take isl_pw_multi_aff *pma, + __isl_take isl_multi_val *mv); __isl_give isl_multi_pw_aff * isl_multi_pw_aff_scale_down_multi_val( __isl_take isl_multi_pw_aff *mpa, @@ -9331,6 +9438,9 @@ Lists can be created, copied, modified and freed using the following functions. unsigned pos1, unsigned pos2); __isl_give isl_set_list *isl_set_list_reverse( __isl_take isl_set_list *list); + __isl_give isl_set_list *isl_set_list_set_at( + __isl_take isl_set_list *list, int index, + __isl_take isl_set *set); __isl_give isl_set_list *isl_set_list_set_set( __isl_take isl_set_list *list, int index, __isl_take isl_set *set); @@ -9358,6 +9468,7 @@ C performs the same operation. C removes all elements from a list. C swaps the elements at the specified locations. C reverses the elements in the list. +C is an alternative name for C. Lists can be inspected using the following functions. @@ -9493,6 +9604,11 @@ Associative arrays can be inspected using the following functions. isl_stat (*fn)(__isl_take isl_id *key, __isl_take isl_ast_expr *val, void *user), void *user); + isl_bool isl_id_to_ast_expr_every( + __isl_keep isl_id_to_ast_expr *id2expr, + isl_bool (*test)(__isl_keep isl_id *key, + __isl_keep isl_ast_expr *val, void *user), + void *user); The function C returns a structure containing two elements, C and C. @@ -9516,12 +9632,33 @@ Associative arrays can be modified using the following functions. __isl_take isl_id_to_ast_expr *id2expr, __isl_take isl_id *key); -Associative arrays can be printed using the following function. +Associative arrays can be checked for (obvious) equality +using the following function. + + #include + isl_bool isl_id_to_ast_expr_is_equal( + __isl_take isl_id_to_ast_expr *id2expr1, + __isl_take isl_id_to_ast_expr *id2expr2); + +Note that depending on how the keys and values are being compared, +for other types of keys and/or values, this function may be called +C rather than C. + +Associative arrays can be printed using the following functions. #include __isl_give isl_printer *isl_printer_print_id_to_ast_expr( __isl_take isl_printer *p, __isl_keep isl_id_to_ast_expr *id2expr); + __isl_give char *isl_id_to_ast_expr_to_str( + __isl_keep isl_id_to_ast_expr *id2expr); + +They can be read from input using the following function. + + #include + __isl_give isl_id_to_ast_expr * + isl_id_to_ast_expr_read_from_str(isl_ctx *ctx, + const char *str); =head2 Vectors @@ -10089,6 +10226,9 @@ exists. __isl_keep isl_schedule_node *node); __isl_give isl_schedule_node *isl_schedule_node_parent( __isl_take isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_grandparent( + __isl_take isl_schedule_node *node); __isl_give isl_schedule_node *isl_schedule_node_root( __isl_take isl_schedule_node *node); __isl_give isl_schedule_node *isl_schedule_node_ancestor( @@ -10100,6 +10240,10 @@ exists. __isl_take isl_schedule_node *node, int pos); isl_bool isl_schedule_node_has_children( __isl_keep isl_schedule_node *node); + __isl_give isl_schedule_node * + isl_schedule_node_grandchild( + __isl_take isl_schedule_node *node, + int pos1, int pos2); __isl_give isl_schedule_node *isl_schedule_node_first_child( __isl_take isl_schedule_node *node); isl_bool isl_schedule_node_has_previous_sibling( @@ -10541,19 +10685,26 @@ introduced expansion node. Grouping instances of different statements ensures that they will be treated as a single statement by the AST generator up to the point of the expansion node. -The following function can be used to flatten a nested +The following functions can be used to flatten a nested sequence. #include __isl_give isl_schedule_node * isl_schedule_node_sequence_splice_child( __isl_take isl_schedule_node *node, int pos); + __isl_give isl_schedule_node * + isl_schedule_node_sequence_splice_children( + __isl_take isl_schedule_node *node); That is, given a sequence node C that has another sequence node in its child at position C (in particular, the child of that filter -node is a sequence node), attach the children of that other sequence +node is a sequence node), the function +C +attaches the children of that other sequence node as children of C, replacing the original child at position C. +C does this for all +such children. The partial schedule of a band node can be scaled (down) or reduced using the following functions. @@ -11747,6 +11898,10 @@ A member access. This operation has two arguments, a structure and the name of the member of the structure being accessed. +=item C + +The address of its single argument, which is always an array access. + =back #include @@ -11922,6 +12077,18 @@ subexpressions of C of type C by the corresponding expression in C, if there is any. +The following function can be used to modify the descendants +of a specific node in an AST using a depth-first post-order +traversal of those descendants (including the node itself). + + #include + __isl_give isl_ast_node * + isl_ast_node_map_descendant_bottom_up( + __isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_node *node, + void *user), void *user); + User specified data can be attached to an C and obtained from the same C using the following functions. @@ -12693,9 +12860,22 @@ AST generation or a user defined node created using the following function. #include + __isl_give isl_ast_node *isl_ast_node_user_from_expr( + __isl_take isl_ast_expr *expr); __isl_give isl_ast_node *isl_ast_node_alloc_user( __isl_take isl_ast_expr *expr); +C is an alternative name for +C. + +In some cases, a single user defined node is not enough, +in which case the following function can be used +to create a block node from multiple AST nodes. + + #include + __isl_give isl_ast_node *isl_ast_node_block_from_children( + __isl_take isl_ast_node_list *list); + #include __isl_give isl_ast_build * isl_ast_build_set_at_each_domain( diff --git a/polly/lib/External/isl/extract_key.c b/polly/lib/External/isl/extract_key.c index 070c1f6..28fbdfd 100644 --- a/polly/lib/External/isl/extract_key.c +++ b/polly/lib/External/isl/extract_key.c @@ -13,17 +13,17 @@ * Return KEY_ERROR on error, i.e., if "tok" does not * correspond to any known key. */ -static KEY extract_key(__isl_keep isl_stream *s, struct isl_token *tok) +static KEY KEY_EXTRACT(__isl_keep isl_stream *s, struct isl_token *tok) { - int type; + isl_bool has_string; char *name; KEY key; isl_ctx *ctx; - if (!tok) + has_string = isl_token_has_str(tok); + if (has_string < 0) return KEY_ERROR; - type = isl_token_get_type(tok); - if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) { + if (!has_string) { isl_stream_error(s, tok, "expecting key"); return KEY_ERROR; } @@ -34,7 +34,7 @@ static KEY extract_key(__isl_keep isl_stream *s, struct isl_token *tok) return KEY_ERROR; for (key = 0; key < KEY_END; ++key) { - if (!strcmp(name, key_str[key])) + if (KEY_STR[key] && !strcmp(name, KEY_STR[key])) break; } free(name); @@ -49,13 +49,13 @@ static KEY extract_key(__isl_keep isl_stream *s, struct isl_token *tok) * Return KEY_ERROR on error, i.e., if the first token * on the stream does not correspond to any known key. */ -static KEY get_key(__isl_keep isl_stream *s) +static KEY KEY_GET(__isl_keep isl_stream *s) { struct isl_token *tok; KEY key; tok = isl_stream_next_token(s); - key = extract_key(s, tok); + key = KEY_EXTRACT(s, tok); isl_token_free(tok); return key; diff --git a/polly/lib/External/isl/flow_cmp.c b/polly/lib/External/isl/flow_cmp.c index ca7e377..e01c0fa 100644 --- a/polly/lib/External/isl/flow_cmp.c +++ b/polly/lib/External/isl/flow_cmp.c @@ -59,7 +59,7 @@ static FILE *open_or_die(const char *filename) */ int main(int argc, char **argv) { - int more; + isl_bool more; isl_ctx *ctx; struct options *options; FILE *input1, *input2; @@ -77,15 +77,15 @@ int main(int argc, char **argv) s1 = isl_stream_new_file(ctx, input1); s2 = isl_stream_new_file(ctx, input2); - if (isl_stream_yaml_read_start_mapping(s1)) + if (isl_stream_yaml_read_start_mapping(s1) < 0) isl_die(ctx, isl_error_unknown, "arg1 not a YAML mapping", return EXIT_FAILURE); - if (isl_stream_yaml_read_start_mapping(s2)) + if (isl_stream_yaml_read_start_mapping(s2) < 0) isl_die(ctx, isl_error_unknown, "arg2 not a YAML mapping", return EXIT_FAILURE); - while ((more = isl_stream_yaml_next(s1)) > 0) { - int more2; + while ((more = isl_stream_yaml_next(s1)) == isl_bool_true) { + isl_bool more2; isl_bool equal; isl_union_map *umap1, *umap2; @@ -121,14 +121,10 @@ int main(int argc, char **argv) return EXIT_FAILURE; - if (isl_stream_yaml_read_end_mapping(s1) < 0) { - isl_stream_error(s1, NULL, "unexpected extra elements"); + if (isl_stream_yaml_read_end_mapping(s1) < 0) return EXIT_FAILURE; - } - if (isl_stream_yaml_read_end_mapping(s2) < 0) { - isl_stream_error(s2, NULL, "unexpected extra elements"); + if (isl_stream_yaml_read_end_mapping(s2) < 0) return EXIT_FAILURE; - } isl_stream_free(s1); isl_stream_free(s2); diff --git a/polly/lib/External/isl/include/isl/aff.h b/polly/lib/External/isl/include/isl/aff.h index c417be1..cf0b5f6 100644 --- a/polly/lib/External/isl/include/isl/aff.h +++ b/polly/lib/External/isl/include/isl/aff.h @@ -153,6 +153,7 @@ __isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, __isl_export __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, __isl_take isl_set *context); +__isl_export __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, __isl_take isl_set *context); @@ -230,8 +231,14 @@ __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls); __isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain, __isl_take isl_val *v); __isl_overload +__isl_give isl_pw_aff *isl_set_pw_aff_on_domain_val(__isl_take isl_set *domain, + __isl_take isl_val *v); +__isl_overload __isl_give isl_pw_aff *isl_pw_aff_param_on_domain_id( __isl_take isl_set *domain, __isl_take isl_id *id); +__isl_overload +__isl_give isl_pw_aff *isl_set_param_pw_aff_on_domain_id( + __isl_take isl_set *domain, __isl_take isl_id *id); __isl_export __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set); @@ -379,6 +386,7 @@ __isl_give isl_pw_aff *isl_pw_aff_coalesce(__isl_take isl_pw_aff *pa); __isl_export __isl_give isl_pw_aff *isl_pw_aff_gist(__isl_take isl_pw_aff *pwaff, __isl_take isl_set *context); +__isl_export __isl_give isl_pw_aff *isl_pw_aff_gist_params(__isl_take isl_pw_aff *pwaff, __isl_take isl_set *context); @@ -529,6 +537,7 @@ __isl_give isl_multi_val *isl_multi_aff_get_constant_multi_val( __isl_export __isl_give isl_multi_aff *isl_multi_aff_floor(__isl_take isl_multi_aff *ma); +__isl_export __isl_give isl_multi_aff *isl_multi_aff_gist_params( __isl_take isl_multi_aff *maff, __isl_take isl_set *context); __isl_export @@ -738,8 +747,12 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_val( __isl_overload __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_overload __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv); +__isl_overload +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv); __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( __isl_take isl_pw_multi_aff *pma1, @@ -795,6 +808,7 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_unused_params( __isl_export __isl_give isl_pw_multi_aff *isl_pw_multi_aff_coalesce( __isl_take isl_pw_multi_aff *pma); +__isl_export __isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist_params( __isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set); __isl_export diff --git a/polly/lib/External/isl/include/isl/ast.h b/polly/lib/External/isl/include/isl/ast.h index 570c48a..786f5b4 100644 --- a/polly/lib/External/isl/include/isl/ast.h +++ b/polly/lib/External/isl/include/isl/ast.h @@ -103,6 +103,9 @@ __isl_give char *isl_ast_expr_to_str(__isl_keep isl_ast_expr *expr); __isl_export __isl_give char *isl_ast_expr_to_C_str(__isl_keep isl_ast_expr *expr); +__isl_constructor +__isl_give isl_ast_node *isl_ast_node_user_from_expr( + __isl_take isl_ast_expr *expr); __isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr); __isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node); __isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node); @@ -150,6 +153,9 @@ __isl_give isl_ast_node *isl_ast_node_if_get_else_node( __isl_give isl_ast_node *isl_ast_node_if_get_else( __isl_keep isl_ast_node *node); +__isl_constructor +__isl_give isl_ast_node *isl_ast_node_block_from_children( + __isl_take isl_ast_node_list *list); __isl_export __isl_give isl_ast_node_list *isl_ast_node_block_get_children( __isl_keep isl_ast_node *node); @@ -167,6 +173,10 @@ __isl_give isl_ast_expr *isl_ast_node_user_get_expr( isl_stat isl_ast_node_foreach_descendant_top_down( __isl_keep isl_ast_node *node, isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user); +__isl_export +__isl_give isl_ast_node *isl_ast_node_map_descendant_bottom_up( + __isl_take isl_ast_node *node, __isl_give isl_ast_node *(*fn)( + __isl_take isl_ast_node *node, void *user), void *user); __isl_give isl_printer *isl_printer_print_ast_node(__isl_take isl_printer *p, __isl_keep isl_ast_node *node); diff --git a/polly/lib/External/isl/include/isl/hash.h b/polly/lib/External/isl/include/isl/hash.h index 7ef3d2e..31cf25c 100644 --- a/polly/lib/External/isl/include/isl/hash.h +++ b/polly/lib/External/isl/include/isl/hash.h @@ -67,6 +67,8 @@ struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx, const void *val, int reserve); isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table, isl_stat (*fn)(void **entry, void *user), void *user); +isl_bool isl_hash_table_every(isl_ctx *ctx, struct isl_hash_table *table, + isl_bool (*test)(void **entry, void *user), void *user); void isl_hash_table_remove(struct isl_ctx *ctx, struct isl_hash_table *table, struct isl_hash_table_entry *entry); diff --git a/polly/lib/External/isl/include/isl/hmap.h b/polly/lib/External/isl/include/isl/hmap.h index 2161221..8d4178f 100644 --- a/polly/lib/External/isl/include/isl/hmap.h +++ b/polly/lib/External/isl/include/isl/hmap.h @@ -11,9 +11,10 @@ extern "C" { #define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME #define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME) -struct ISL_HMAP; +struct __isl_export ISL_HMAP; typedef struct ISL_HMAP ISL_HMAP; +__isl_constructor __isl_give ISL_HMAP *ISL_FN(ISL_HMAP,alloc)(isl_ctx *ctx, int min_size); __isl_give ISL_HMAP *ISL_FN(ISL_HMAP,copy)(__isl_keep ISL_HMAP *hmap); __isl_null ISL_HMAP *ISL_FN(ISL_HMAP,free)(__isl_take ISL_HMAP *hmap); @@ -26,6 +27,7 @@ isl_bool ISL_FN(ISL_HMAP,has)(__isl_keep ISL_HMAP *hmap, __isl_keep ISL_KEY *key); __isl_give ISL_VAL *ISL_FN(ISL_HMAP,get)(__isl_keep ISL_HMAP *hmap, __isl_take ISL_KEY *key); +__isl_export __isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap, __isl_take ISL_KEY *key, __isl_take ISL_VAL *val); __isl_give ISL_HMAP *ISL_FN(ISL_HMAP,drop)(__isl_take ISL_HMAP *hmap, @@ -35,7 +37,23 @@ isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap, isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val, void *user), void *user); +isl_bool ISL_FN(ISL_HMAP,every)(__isl_keep ISL_HMAP *hmap, + isl_bool (*test)(__isl_keep ISL_KEY *key, __isl_keep ISL_VAL *val, + void *user), + void *user); +#ifdef ISL_HMAP_IS_EQUAL +__isl_export +isl_bool ISL_HMAP_IS_EQUAL(__isl_keep ISL_HMAP *hmap1, + __isl_keep ISL_HMAP *hmap2); +#endif + +#ifdef ISL_HMAP_HAVE_READ_FROM_STR +__isl_constructor +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,read_from_str)(isl_ctx *ctx, + const char *str); +#endif +__isl_give char *ISL_FN(ISL_HMAP,to_str)(__isl_keep ISL_HMAP *hmap); __isl_give isl_printer *ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)( __isl_take isl_printer *p, __isl_keep ISL_HMAP *hmap); void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap); diff --git a/polly/lib/External/isl/include/isl/hmap_templ.c b/polly/lib/External/isl/include/isl/hmap_templ.c index ceb52bd..ba0d7cc 100644 --- a/polly/lib/External/isl/include/isl/hmap_templ.c +++ b/polly/lib/External/isl/include/isl/hmap_templ.c @@ -12,6 +12,7 @@ #include #include +#include #define ISL_xCAT(A,B) A ## B #define ISL_CAT(A,B) ISL_xCAT(A,B) @@ -322,7 +323,7 @@ error: return ISL_FN(ISL_HMAP,free)(hmap); } -/* Internal data structure for isl_map_to_basic_set_foreach. +/* Internal data structure for isl_*_to_*_foreach. * * fn is the function that should be called on each entry. * user is the user-specified final argument to fn. @@ -360,6 +361,83 @@ isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap, &call_on_copy, &data); } +/* Internal data structure for isl_*_to_*_every. + * + * "test" is the function that should be called on each entry, + * until any invocation returns isl_bool_false. + * "test_user" is the user-specified final argument to "test". + */ +ISL_S(every_data) { + isl_bool (*test)(__isl_keep ISL_KEY *key, __isl_keep ISL_VAL *val, + void *user); + void *test_user; +}; + +/* Call data->test on the key and value in *entry. + */ +static isl_bool call_on_pair(void **entry, void *user) +{ + ISL_S(pair) *pair = *entry; + ISL_S(every_data) *data = (ISL_S(every_data) *) user; + + return data->test(pair->key, pair->val, data->test_user); +} + +/* Does "test" succeed on every entry of "hmap"? + */ +isl_bool ISL_FN(ISL_HMAP,every)(__isl_keep ISL_HMAP *hmap, + isl_bool (*test)(__isl_keep ISL_KEY *key, __isl_keep ISL_VAL *val, + void *user), + void *user) +{ + ISL_S(every_data) data = { test, user }; + + if (!hmap) + return isl_bool_error; + + return isl_hash_table_every(hmap->ctx, &hmap->table, + &call_on_pair, &data); +} + +#ifdef ISL_HMAP_IS_EQUAL + +/* Does "hmap" have an entry with key "key" and value "val"? + */ +static isl_bool has_entry(__isl_keep ISL_KEY *key, __isl_keep ISL_VAL *val, + void *user) +{ + ISL_HMAP *hmap = user; + ISL_MAYBE(ISL_VAL) maybe_val; + isl_bool equal; + + maybe_val = ISL_FN(ISL_HMAP,try_get)(hmap, key); + if (maybe_val.valid < 0 || !maybe_val.valid) + return maybe_val.valid; + equal = ISL_VAL_IS_EQUAL(maybe_val.value, val); + ISL_FN(ISL_VAL,free)(maybe_val.value); + return equal; +} + +/* Is "hmap1" (obviously) equal to "hmap2"? + * + * In particular, do the two associative arrays have + * the same number of entries and does every entry of the first + * also appear in the second? + */ +isl_bool ISL_HMAP_IS_EQUAL(__isl_keep ISL_HMAP *hmap1, + __isl_keep ISL_HMAP *hmap2) +{ + if (!hmap1 || !hmap2) + return isl_bool_error; + if (hmap1 == hmap2) + return isl_bool_true; + if (hmap1->table.n != hmap2->table.n) + return isl_bool_false; + return ISL_FN(ISL_HMAP,every)(hmap1, &has_entry, hmap2); +} + +#endif + /* Internal data structure for print_pair. * * p is the printer on which the associative array is being printed. @@ -423,3 +501,83 @@ void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap) isl_printer_free(printer); } + +/* Return a string representation of "hmap". + */ +__isl_give char *ISL_FN(ISL_HMAP,to_str)(__isl_keep ISL_HMAP *hmap) +{ + isl_printer *p; + char *s; + + if (!hmap) + return NULL; + p = isl_printer_to_str(ISL_FN(ISL_HMAP,get_ctx)(hmap)); + p = ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)(p, hmap); + s = isl_printer_get_str(p); + isl_printer_free(p); + + return s; +} + +#ifdef ISL_HMAP_HAVE_READ_FROM_STR + +/* Read an associative array from "s". + * The input format corresponds to the way associative arrays are printed + * by isl_printer_print_*_to_*. + * In particular, each key-value pair is separated by a colon, + * the key-value pairs are separated by a comma and + * the entire associative array is surrounded by braces. + */ +__isl_give ISL_HMAP *ISL_FN(isl_stream_read,ISL_HMAP_SUFFIX)(isl_stream *s) +{ + isl_ctx *ctx; + ISL_HMAP *hmap; + + if (!s) + return NULL; + ctx = isl_stream_get_ctx(s); + hmap = ISL_FN(ISL_HMAP,alloc)(ctx, 0); + if (!hmap) + return NULL; + if (isl_stream_eat(s, '{') < 0) + return ISL_FN(ISL_HMAP,free)(hmap); + if (isl_stream_eat_if_available(s, '}')) + return hmap; + do { + ISL_KEY *key; + ISL_VAL *val = NULL; + + key = ISL_KEY_READ(s); + if (isl_stream_eat(s, ':') >= 0) + val = ISL_VAL_READ(s); + hmap = ISL_FN(ISL_HMAP,set)(hmap, key, val); + if (!hmap) + return NULL; + } while (isl_stream_eat_if_available(s, ',')); + if (isl_stream_eat(s, '}') < 0) + return ISL_FN(ISL_HMAP,free)(hmap); + return hmap; +} + +/* Read an associative array from the string "str". + * The input format corresponds to the way associative arrays are printed + * by isl_printer_print_*_to_*. + * In particular, each key-value pair is separated by a colon, + * the key-value pairs are separated by a comma and + * the entire associative array is surrounded by braces. + */ +__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,read_from_str)(isl_ctx *ctx, + const char *str) +{ + ISL_HMAP *hmap; + isl_stream *s; + + s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + hmap = ISL_FN(isl_stream_read,ISL_HMAP_SUFFIX)(s); + isl_stream_free(s); + return hmap; +} + +#endif diff --git a/polly/lib/External/isl/include/isl/id.h b/polly/lib/External/isl/include/isl/id.h index 3e71cb0..f434d53 100644 --- a/polly/lib/External/isl/include/isl/id.h +++ b/polly/lib/External/isl/include/isl/id.h @@ -31,6 +31,7 @@ __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, void (*free_user)(void *user)); +void (*isl_id_get_free_user(__isl_keep isl_id *id))(void *user); __isl_constructor __isl_give isl_id *isl_id_read_from_str(isl_ctx *ctx, const char *str); diff --git a/polly/lib/External/isl/include/isl/id_to_ast_expr.h b/polly/lib/External/isl/include/isl/id_to_ast_expr.h index 5822241..ccdb1e0 100644 --- a/polly/lib/External/isl/include/isl/id_to_ast_expr.h +++ b/polly/lib/External/isl/include/isl/id_to_ast_expr.h @@ -9,10 +9,14 @@ #define ISL_VAL isl_ast_expr #define ISL_HMAP_SUFFIX id_to_ast_expr #define ISL_HMAP isl_id_to_ast_expr +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_HMAP_IS_EQUAL isl_id_to_ast_expr_is_equal #include #undef ISL_KEY #undef ISL_VAL #undef ISL_HMAP_SUFFIX #undef ISL_HMAP +#undef ISL_HMAP_HAVE_READ_FROM_STR +#undef ISL_HMAP_IS_EQUAL #endif diff --git a/polly/lib/External/isl/include/isl/id_to_id.h b/polly/lib/External/isl/include/isl/id_to_id.h index 3090115..94b40ef 100644 --- a/polly/lib/External/isl/include/isl/id_to_id.h +++ b/polly/lib/External/isl/include/isl/id_to_id.h @@ -8,10 +8,14 @@ #define ISL_VAL isl_id #define ISL_HMAP_SUFFIX id_to_id #define ISL_HMAP isl_id_to_id +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_HMAP_IS_EQUAL isl_id_to_id_is_equal #include #undef ISL_KEY #undef ISL_VAL #undef ISL_HMAP_SUFFIX #undef ISL_HMAP +#undef ISL_HMAP_HAVE_READ_FROM_STR +#undef ISL_HMAP_IS_EQUAL #endif diff --git a/polly/lib/External/isl/include/isl/id_to_pw_aff.h b/polly/lib/External/isl/include/isl/id_to_pw_aff.h index bcbea66..0b7a0e5 100644 --- a/polly/lib/External/isl/include/isl/id_to_pw_aff.h +++ b/polly/lib/External/isl/include/isl/id_to_pw_aff.h @@ -9,10 +9,14 @@ #define ISL_VAL isl_pw_aff #define ISL_HMAP_SUFFIX id_to_pw_aff #define ISL_HMAP isl_id_to_pw_aff +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_HMAP_IS_EQUAL isl_id_to_pw_aff_plain_is_equal #include #undef ISL_KEY #undef ISL_VAL #undef ISL_HMAP_SUFFIX #undef ISL_HMAP +#undef ISL_HMAP_HAVE_READ_FROM_STR +#undef ISL_HMAP_IS_EQUAL #endif diff --git a/polly/lib/External/isl/include/isl/ilp.h b/polly/lib/External/isl/include/isl/ilp.h index a2be08e..5f9b816 100644 --- a/polly/lib/External/isl/include/isl/ilp.h +++ b/polly/lib/External/isl/include/isl/ilp.h @@ -32,6 +32,10 @@ __isl_give isl_multi_val *isl_union_set_min_multi_union_pw_aff( __isl_keep isl_union_set *uset, __isl_keep isl_multi_union_pw_aff *obj); __isl_export +__isl_give isl_val *isl_pw_aff_min_val(__isl_take isl_pw_aff *pa); +__isl_export +__isl_give isl_val *isl_pw_aff_max_val(__isl_take isl_pw_aff *pa); +__isl_export __isl_give isl_multi_val *isl_pw_multi_aff_min_multi_val( __isl_take isl_pw_multi_aff *pma); __isl_export diff --git a/polly/lib/External/isl/include/isl/list.h b/polly/lib/External/isl/include/isl/list.h index 3d8dabe..af5d6ba 100644 --- a/polly/lib/External/isl/include/isl/list.h +++ b/polly/lib/External/isl/include/isl/list.h @@ -69,6 +69,10 @@ __isl_give isl_##EL *isl_##EL##_list_get_at( \ __isl_keep isl_##EL##_list *list, int index); \ __isl_give struct isl_##EL *isl_##EL##_list_get_##EL( \ __isl_keep isl_##EL##_list *list, int index); \ +EXPORT \ +__isl_give isl_##EL##_list *isl_##EL##_list_set_at( \ + __isl_take isl_##EL##_list *list, int index, \ + __isl_take isl_##EL *el); \ __isl_give struct isl_##EL##_list *isl_##EL##_list_set_##EL( \ __isl_take struct isl_##EL##_list *list, int index, \ __isl_take struct isl_##EL *el); \ @@ -89,9 +93,10 @@ __isl_give isl_##EL##_list *isl_##EL##_list_sort( \ int (*cmp)(__isl_keep struct isl_##EL *a, \ __isl_keep struct isl_##EL *b, \ void *user), void *user); \ +EXPORT \ isl_stat isl_##EL##_list_foreach_scc(__isl_keep isl_##EL##_list *list, \ - isl_bool (*follows)(__isl_keep struct isl_##EL *a, \ - __isl_keep struct isl_##EL *b, void *user), \ + isl_bool (*follows)(__isl_keep isl_##EL *a, \ + __isl_keep isl_##EL *b, void *user), \ void *follows_user, \ isl_stat (*fn)(__isl_take isl_##EL##_list *scc, void *user), \ void *fn_user); \ diff --git a/polly/lib/External/isl/include/isl/map.h b/polly/lib/External/isl/include/isl/map.h index 55feb9b..38359c6 100644 --- a/polly/lib/External/isl/include/isl/map.h +++ b/polly/lib/External/isl/include/isl/map.h @@ -354,6 +354,12 @@ __isl_export __isl_give isl_map *isl_map_intersect_range_factor_range( __isl_take isl_map *map, __isl_take isl_map *factor); __isl_export +__isl_give isl_map *isl_map_intersect_domain_wrapped_domain( + __isl_take isl_map *map, __isl_take isl_set *domain); +__isl_export +__isl_give isl_map *isl_map_intersect_range_wrapped_domain( + __isl_take isl_map *map, __isl_take isl_set *domain); +__isl_export __isl_give isl_map *isl_map_apply_domain( __isl_take isl_map *map1, __isl_take isl_map *map2); @@ -479,6 +485,12 @@ __isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map, __isl_give isl_basic_map *isl_basic_map_project_out( __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, unsigned n); +__isl_overload +__isl_give isl_map *isl_map_project_out_param_id(__isl_take isl_map *map, + __isl_take isl_id *id); +__isl_overload +__isl_give isl_map *isl_map_project_out_param_id_list(__isl_take isl_map *map, + __isl_take isl_id_list *list); __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, enum isl_dim_type type, unsigned first, unsigned n); __isl_export @@ -676,6 +688,7 @@ __isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map, __isl_take isl_set *context); __isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map, __isl_take isl_set *context); +__isl_export __isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map, __isl_take isl_set *context); __isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map, @@ -706,6 +719,7 @@ isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map, __isl_give isl_basic_map_list *isl_map_get_basic_map_list( __isl_keep isl_map *map); +__isl_overload __isl_give isl_map *isl_map_fixed_power_val(__isl_take isl_map *map, __isl_take isl_val *exp); __isl_give isl_map *isl_map_power(__isl_take isl_map *map, isl_bool *exact); diff --git a/polly/lib/External/isl/include/isl/map_to_basic_set.h b/polly/lib/External/isl/include/isl/map_to_basic_set.h index 80e9ab5..da86aac 100644 --- a/polly/lib/External/isl/include/isl/map_to_basic_set.h +++ b/polly/lib/External/isl/include/isl/map_to_basic_set.h @@ -9,10 +9,14 @@ #define ISL_VAL isl_basic_set #define ISL_HMAP_SUFFIX map_to_basic_set #define ISL_HMAP isl_map_to_basic_set +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_HMAP_IS_EQUAL isl_map_to_basic_set_plain_is_equal #include #undef ISL_KEY #undef ISL_VAL #undef ISL_HMAP_SUFFIX #undef ISL_HMAP +#undef ISL_HMAP_HAVE_READ_FROM_STR +#undef ISL_HMAP_IS_EQUAL #endif diff --git a/polly/lib/External/isl/include/isl/polynomial_type.h b/polly/lib/External/isl/include/isl/polynomial_type.h index f4a3f20..02bbc03 100644 --- a/polly/lib/External/isl/include/isl/polynomial_type.h +++ b/polly/lib/External/isl/include/isl/polynomial_type.h @@ -1,6 +1,9 @@ #ifndef ISL_POLYNOMIAL_TYPE_H #define ISL_POLYNOMIAL_TYPE_H +#include +#include + struct isl_qpolynomial; typedef struct isl_qpolynomial isl_qpolynomial; diff --git a/polly/lib/External/isl/include/isl/schedule_node.h b/polly/lib/External/isl/include/isl/schedule_node.h index b336003..648bc0d 100644 --- a/polly/lib/External/isl/include/isl/schedule_node.h +++ b/polly/lib/External/isl/include/isl/schedule_node.h @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(__cplusplus) extern "C" { @@ -91,12 +92,16 @@ __isl_give isl_schedule_node *isl_schedule_node_root( __isl_export __isl_give isl_schedule_node *isl_schedule_node_parent( __isl_take isl_schedule_node *node); +__isl_give isl_schedule_node *isl_schedule_node_grandparent( + __isl_take isl_schedule_node *node); __isl_export __isl_give isl_schedule_node *isl_schedule_node_ancestor( __isl_take isl_schedule_node *node, int generation); __isl_export __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_grandchild( + __isl_take isl_schedule_node *node, int pos1, int pos2); __isl_export __isl_give isl_schedule_node *isl_schedule_node_first_child( __isl_take isl_schedule_node *node); @@ -116,6 +121,8 @@ __isl_give isl_schedule_node *isl_schedule_node_group( __isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child( __isl_take isl_schedule_node *node, int pos); +__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_children( + __isl_take isl_schedule_node *node); __isl_give isl_space *isl_schedule_node_band_get_space( __isl_keep isl_schedule_node *node); diff --git a/polly/lib/External/isl/include/isl/set.h b/polly/lib/External/isl/include/isl/set.h index 3e9b224f..e2c79f8 100644 --- a/polly/lib/External/isl/include/isl/set.h +++ b/polly/lib/External/isl/include/isl/set.h @@ -488,6 +488,7 @@ __isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set, __isl_export __isl_give isl_set *isl_set_gist(__isl_take isl_set *set, __isl_take isl_set *context); +__isl_export __isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set, __isl_take isl_set *context); isl_stat isl_set_dim_residue_class_val(__isl_keep isl_set *set, @@ -498,6 +499,8 @@ __isl_give isl_stride_info *isl_set_get_stride_info(__isl_keep isl_set *set, __isl_export __isl_give isl_val *isl_set_get_stride(__isl_keep isl_set *set, int pos); __isl_export +__isl_give isl_fixed_box *isl_set_get_lattice_tile(__isl_keep isl_set *set); +__isl_export __isl_give isl_fixed_box *isl_set_get_simple_fixed_box_hull( __isl_keep isl_set *set); diff --git a/polly/lib/External/isl/include/isl/space.h b/polly/lib/External/isl/include/isl/space.h index f3e1d8a..f89ff0e 100644 --- a/polly/lib/External/isl/include/isl/space.h +++ b/polly/lib/External/isl/include/isl/space.h @@ -119,6 +119,14 @@ __isl_give isl_space *isl_space_range_factor_domain( __isl_take isl_space *space); __isl_give isl_space *isl_space_range_factor_range( __isl_take isl_space *space); +__isl_give isl_space *isl_space_domain_wrapped_domain( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_domain_wrapped_range( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_range_wrapped_domain( + __isl_take isl_space *space); +__isl_give isl_space *isl_space_range_wrapped_range( + __isl_take isl_space *space); __isl_export __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space); __isl_give isl_space *isl_space_map_from_domain_and_range( @@ -205,6 +213,9 @@ __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space); __isl_export __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space); +__isl_constructor +__isl_give isl_space *isl_space_read_from_str(isl_ctx *ctx, + const char *str); __isl_give char *isl_space_to_str(__isl_keep isl_space *space); __isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p, __isl_keep isl_space *space); diff --git a/polly/lib/External/isl/include/isl/stream.h b/polly/lib/External/isl/include/isl/stream.h index b77797f..09d15f6 100644 --- a/polly/lib/External/isl/include/isl/stream.h +++ b/polly/lib/External/isl/include/isl/stream.h @@ -44,6 +44,7 @@ enum isl_token_type { ISL_TOKEN_ERROR = -1, struct isl_token; __isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok); +isl_bool isl_token_has_str(struct isl_token *tok); __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); @@ -75,21 +76,23 @@ enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s, const char *name); struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s); +__isl_give isl_id *isl_stream_read_id(__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_basic_set *isl_stream_read_basic_set(__isl_keep isl_stream *s); __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial( __isl_keep isl_stream *s); __isl_give isl_union_set *isl_stream_read_union_set(__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); +isl_stat isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s); +isl_stat isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s); +isl_stat isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s); +isl_stat isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s); +isl_bool isl_stream_yaml_next(__isl_keep isl_stream *s); #if defined(__cplusplus) } diff --git a/polly/lib/External/isl/include/isl/stride_info.h b/polly/lib/External/isl/include/isl/stride_info.h index 7a4e0dc..533eb68 100644 --- a/polly/lib/External/isl/include/isl/stride_info.h +++ b/polly/lib/External/isl/include/isl/stride_info.h @@ -5,7 +5,7 @@ #ifndef ISL_STRIDE_INFO_H #define ISL_STRIDE_INFO_H -#include +#include #include #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 c630dc0..029e9f9 100644 --- a/polly/lib/External/isl/include/isl/union_map.h +++ b/polly/lib/External/isl/include/isl/union_map.h @@ -178,6 +178,14 @@ __isl_give isl_union_map *isl_union_map_intersect_range_factor_domain( __isl_export __isl_give isl_union_map *isl_union_map_intersect_range_factor_range( __isl_take isl_union_map *umap, __isl_take isl_union_map *factor); +__isl_overload +__isl_give isl_union_map * +isl_union_map_intersect_domain_wrapped_domain_union_set( + __isl_take isl_union_map *umap, __isl_take isl_union_set *domain); +__isl_overload +__isl_give isl_union_map * +isl_union_map_intersect_range_wrapped_domain_union_set( + __isl_take isl_union_map *umap, __isl_take isl_union_set *domain); __isl_export __isl_give isl_union_map *isl_union_map_subtract_domain( @@ -234,6 +242,12 @@ __isl_give isl_union_map *isl_union_map_deltas_map( __isl_export __isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset); +__isl_overload +__isl_give isl_union_map *isl_union_map_project_out_param_id( + __isl_take isl_union_map *umap, __isl_take isl_id *id); +__isl_overload +__isl_give isl_union_map *isl_union_map_project_out_param_id_list( + __isl_take isl_union_map *umap, __isl_take isl_id_list *list); __isl_give isl_union_map *isl_union_map_project_out( __isl_take isl_union_map *umap, enum isl_dim_type type, unsigned first, unsigned n); diff --git a/polly/lib/External/isl/interface/configure.ac b/polly/lib/External/isl/interface/configure.ac index 357eb60..b61822b 100644 --- a/polly/lib/External/isl/interface/configure.ac +++ b/polly/lib/External/isl/interface/configure.ac @@ -20,7 +20,7 @@ OBJEXT="$BUILD_OBJEXT" AX_CXX_COMPILE_STDCXX_11_NO_OVERRIDE AC_DISABLE_SHARED -AC_PROG_LIBTOOL +LT_INIT AX_DETECT_CLANG diff --git a/polly/lib/External/isl/interface/cpp.cc b/polly/lib/External/isl/interface/cpp.cc index 23e2281..d5c08eb 100644 --- a/polly/lib/External/isl/interface/cpp.cc +++ b/polly/lib/External/isl/interface/cpp.cc @@ -649,11 +649,11 @@ void cpp_generator::class_printer::print_method_header( else os << cppstring; - method.print_cpp_arg_list(os, [&] (int i) { + method.print_cpp_arg_list(os, [&] (int i, int arg) { std::string name = method.fd->getParamDecl(i)->getName().str(); ParmVarDecl *param = method.get_param(i); QualType type = param->getOriginalType(); - string cpptype = type_printer.param(i, type); + string cpptype = type_printer.param(arg, type); if (!method.param_needs_copy(i)) os << "const " << cpptype << " &" << name; @@ -928,6 +928,24 @@ bool cpp_generator::is_implicit_conversion(const Method &cons) return false; } +/* Construct a list combiner for printing a list. + */ +Method::list_combiner Method::print_combiner(std::ostream &os) +{ + return { + [&] () { os << "("; }, + [&] () { os << ", "; }, + [&] () { os << ")"; } + }; +} + +/* Construct a list combiner for simply iterating over a list. + */ +Method::list_combiner Method::empty_combiner() +{ + return { [&] () { }, [&] () { }, [&] () { } }; +} + /* Get kind of "method" in "clazz". * * Given the declaration of a static or member method, returns its kind. @@ -942,20 +960,20 @@ static Method::Kind get_kind(const isl_class &clazz, FunctionDecl *method) return Method::Kind::member_method; } -/* Return the callback argument of "fd", if there is any. - * Return NULL otherwise. +/* Return the callback arguments of "fd". */ -static ParmVarDecl *find_callback_arg(FunctionDecl *fd) +static std::vector find_callback_args(FunctionDecl *fd) { + std::vector callbacks; int num_params = fd->getNumParams(); for (int i = 0; i < num_params; ++i) { ParmVarDecl *param = fd->getParamDecl(i); if (generator::is_callback(param->getType())) - return param; + callbacks.emplace_back(param); } - return NULL; + return callbacks; } /* Construct a C++ method object from the class to which is belongs, @@ -968,7 +986,7 @@ Method::Method(const isl_class &clazz, FunctionDecl *fd, const std::string &name) : clazz(clazz), fd(fd), name(rename_method(name)), kind(get_kind(clazz, fd)), - callback(find_callback_arg(fd)) + callbacks(find_callback_args(fd)) { } @@ -985,19 +1003,13 @@ Method::Method(const isl_class &clazz, FunctionDecl *fd) : /* Return the number of parameters of the corresponding C function. * - * If the method has a callback argument, we reduce the number of parameters - * that are exposed by one to hide the user pointer from the interface. On - * the C++ side no user pointer is needed, as arguments can be forwarded - * as part of the std::function argument which specifies the callback function. - * - * The user pointer is also removed from the number of parameters - * of the C function because the pair of callback and user pointer - * is considered as a single argument that is printed as a whole - * by Method::print_param_use. + * This number includes any possible user pointers that follow callback + * arguments. These are skipped by Method::print_fd_arg_list + * during the actual argument printing. */ int Method::c_num_params() const { - return fd->getNumParams() - (callback != NULL); + return fd->getNumParams(); } /* Return the number of parameters of the method @@ -1011,30 +1023,128 @@ int Method::num_params() const return c_num_params(); } -/* Print the arguments from "start" (inclusive) to "end" (exclusive) - * as arguments to a method of C function call, using "print_arg" - * to print each individual argument. +/* Call "on_arg_skip_next" on the arguments from "start" (inclusive) + * to "end" (exclusive), calling the methods of "combiner" + * before, between and after the arguments. + * If "on_arg_skip_next" returns true then the next argument is skipped. */ -void Method::print_arg_list(std::ostream &os, int start, int end, - const std::function &print_arg) +void Method::on_arg_list(int start, int end, + const Method::list_combiner &combiner, + const std::function &on_arg_skip_next) { - os << "("; + combiner.before(); for (int i = start; i < end; ++i) { if (i != start) - os << ", "; - print_arg(i); + combiner.between(); + if (on_arg_skip_next(i)) + ++i; } - os << ")"; + combiner.after(); +} + +/* Print the arguments from "start" (inclusive) to "end" (exclusive) + * as arguments to a method of C function call, using "print_arg_skip_next" + * to print each individual argument. If this callback return true + * then the next argument is skipped. + */ +void Method::print_arg_list(std::ostream &os, int start, int end, + const std::function &print_arg_skip_next) +{ + on_arg_list(start, end, print_combiner(os), [&] (int i) { + return print_arg_skip_next(i); + }); +} + +/* Call "on_arg" on the arguments from "start" (inclusive) to "end" (exclusive), + * calling the methods of "combiner" before, between and after the arguments. + * The first argument to "on_arg" is the position of the argument + * in this->fd. + * The second argument is the (first) position in the list of arguments + * with all callback arguments spliced in. + * + * Call on_arg_list to do the actual iteration over the arguments, skipping + * the user argument that comes after every callback argument. + * On the C++ side no user pointer is needed, as arguments can be forwarded + * as part of the std::function argument which specifies the callback function. + * The user pointer is also removed from the number of parameters + * of the C function because the pair of callback and user pointer + * is considered as a single argument that is printed as a whole + * by Method::print_param_use. + * + * In case of a callback argument, the second argument to "print_arg" + * is also adjusted to account for the spliced-in arguments of the callback. + * The return value takes the place of the callback itself, + * while the arguments (excluding the final user pointer) + * take the following positions. + */ +void Method::on_fd_arg_list(int start, int end, + const Method::list_combiner &combiner, + const std::function &on_arg) const +{ + int arg = start; + + on_arg_list(start, end, combiner, [this, &on_arg, &arg] (int i) { + auto type = fd->getParamDecl(i)->getType(); + + on_arg(i, arg++); + if (!generator::is_callback(type)) + return false; + arg += generator::prototype_n_args(type) - 1; + return true; + }); +} + +/* Print the arguments from "start" (inclusive) to "end" (exclusive) + * as arguments to a method of C function call, using "print_arg" + * to print each individual argument. + * The first argument to this callback is the position of the argument + * in this->fd. + * The second argument is the (first) position in the list of arguments + * with all callback arguments spliced in. + */ +void Method::print_fd_arg_list(std::ostream &os, int start, int end, + const std::function &print_arg) const +{ + on_fd_arg_list(start, end, print_combiner(os), print_arg); +} + +/* Call "on_arg" on the arguments to the method call, + * calling the methods of "combiner" before, between and after the arguments. + * The first argument to "on_arg" is the position of the argument + * in this->fd. + * The second argument is the (first) position in the list of arguments + * with all callback arguments spliced in. + */ +void Method::on_cpp_arg_list(const Method::list_combiner &combiner, + const std::function &on_arg) const +{ + int first_param = kind == member_method ? 1 : 0; + on_fd_arg_list(first_param, num_params(), combiner, on_arg); +} + +/* Call "on_arg" on the arguments to the method call. + * The first argument to "on_arg" is the position of the argument + * in this->fd. + * The second argument is the (first) position in the list of arguments + * with all callback arguments spliced in. + */ +void Method::on_cpp_arg_list( + const std::function &on_arg) const +{ + on_cpp_arg_list(empty_combiner(), on_arg); } /* Print the arguments to the method call, using "print_arg" * to print each individual argument. + * The first argument to this callback is the position of the argument + * in this->fd. + * The second argument is the (first) position in the list of arguments + * with all callback arguments spliced in. */ void Method::print_cpp_arg_list(std::ostream &os, - const std::function &print_arg) const + const std::function &print_arg) const { - int first_param = kind == member_method ? 1 : 0; - print_arg_list(os, first_param, num_params(), print_arg); + on_cpp_arg_list(print_combiner(os), print_arg); } /* Should the parameter at position "pos" be a copy (rather than diff --git a/polly/lib/External/isl/interface/cpp.h b/polly/lib/External/isl/interface/cpp.h index 837cdee..55a8fb4 100644 --- a/polly/lib/External/isl/interface/cpp.h +++ b/polly/lib/External/isl/interface/cpp.h @@ -14,7 +14,7 @@ * "name" is the name of the method, which may be different * from the default name derived from "fd". * "kind" is the type of the method. - * "callback" stores the callback argument, if any, or NULL. + * "callbacks" stores the callback arguments. */ struct Method { enum Kind { @@ -23,6 +23,10 @@ struct Method { constructor, }; + struct list_combiner; + static list_combiner print_combiner(std::ostream &os); + static list_combiner empty_combiner(); + Method(const isl_class &clazz, FunctionDecl *fd, const std::string &name); Method(const isl_class &clazz, FunctionDecl *fd); @@ -33,16 +37,41 @@ struct Method { virtual clang::ParmVarDecl *get_param(int pos) const; virtual void print_param_use(ostream &os, int pos) const; bool is_subclass_mutator() const; + static void on_arg_list(int start, int end, + const list_combiner &combiner, + const std::function &on_arg_skip_next); static void print_arg_list(std::ostream &os, int start, int end, - const std::function &print_arg); + const std::function &print_arg_skip_next); + void on_fd_arg_list(int start, int end, + const list_combiner &combiner, + const std::function &on_arg) const; + void print_fd_arg_list(std::ostream &os, int start, int end, + const std::function &print_arg) const; + void on_cpp_arg_list(const list_combiner &combiner, + const std::function &on_arg) const; + void on_cpp_arg_list( + const std::function &on_arg) const; void print_cpp_arg_list(std::ostream &os, - const std::function &print_arg) const; + const std::function &print_arg) const; const isl_class &clazz; FunctionDecl *const fd; const std::string name; const enum Kind kind; - ParmVarDecl *const callback; + const std::vector callbacks; +}; + +/* A data structure expressing how Method::on_arg_list should combine + * the arguments. + * + * In particular, "before" is called before any argument is handled; + * "between" is called between two arguments and + * "after" is called after all arguments have been handled. + */ +struct Method::list_combiner { + const std::function before; + const std::function between; + const std::function after; }; /* A method that does not require its isl type parameters to be a copy. diff --git a/polly/lib/External/isl/interface/extract_interface.cc b/polly/lib/External/isl/interface/extract_interface.cc index e1fcb24..b94847c 100644 --- a/polly/lib/External/isl/interface/extract_interface.cc +++ b/polly/lib/External/isl/interface/extract_interface.cc @@ -109,7 +109,7 @@ static llvm::cl::opt OutputLanguage(llvm::cl::Required, llvm::cl::value_desc("name")); static const char *ResourceDir = - CLANG_PREFIX "/lib/clang/" CLANG_VERSION_MAJOR_STRING; + CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING; /* Does decl have an attribute of the following form? * @@ -428,7 +428,7 @@ static void set_lang_defaults(CompilerInstance *Clang) PreprocessorOptions &PO = Clang->getPreprocessorOpts(); TargetOptions &TO = Clang->getTargetOpts(); llvm::Triple T(TO.Triple); - CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, T, + SETLANGDEFAULTS::setLangDefaults(Clang->getLangOpts(), IK_C, T, setLangDefaultsArg4(PO), LangStandard::lang_unspecified); } diff --git a/polly/lib/External/isl/interface/generator.cc b/polly/lib/External/isl/interface/generator.cc index eacbc36..4b98903 100644 --- a/polly/lib/External/isl/interface/generator.cc +++ b/polly/lib/External/isl/interface/generator.cc @@ -735,6 +735,16 @@ bool generator::is_callback(QualType type) return type->isFunctionType(); } +/* Is the parameter at position "i" of "fd" a pointer to a function? + */ +bool generator::is_callback_arg(FunctionDecl *fd, int i) +{ + ParmVarDecl *param = fd->getParamDecl(i); + QualType type = param->getOriginalType(); + + return is_callback(type); +} + /* Is "type" that of "char *" of "const char *"? */ bool generator::is_string(QualType type) @@ -781,6 +791,14 @@ const FunctionProtoType *generator::extract_prototype(QualType type) return type->getPointeeType()->getAs(); } +/* Given the type of a function pointer, return the number of arguments + * of the corresponding function prototype. + */ +int generator::prototype_n_args(QualType type) +{ + return extract_prototype(type)->getNumArgs(); +} + /* Return the function name suffix for the type of "param". * * If the type of "param" is an isl object type, diff --git a/polly/lib/External/isl/interface/generator.h b/polly/lib/External/isl/interface/generator.h index 29faaaa..90eae82 100644 --- a/polly/lib/External/isl/interface/generator.h +++ b/polly/lib/External/isl/interface/generator.h @@ -190,11 +190,13 @@ public: static bool is_isl_size(QualType type); static bool is_long(QualType type); static bool is_callback(QualType type); + static bool is_callback_arg(FunctionDecl *fd, int i); static bool is_string(QualType type); static bool is_static(const isl_class &clazz, FunctionDecl *method); static bool is_mutator(const isl_class &clazz, FunctionDecl *fd); static string extract_type(QualType type); static const FunctionProtoType *extract_prototype(QualType type); + static int prototype_n_args(QualType type); static ParmVarDecl *persistent_callback_arg(FunctionDecl *fd); }; diff --git a/polly/lib/External/isl/interface/plain_cpp.cc b/polly/lib/External/isl/interface/plain_cpp.cc index ae15c34..326cf12 100644 --- a/polly/lib/External/isl/interface/plain_cpp.cc +++ b/polly/lib/External/isl/interface/plain_cpp.cc @@ -261,17 +261,7 @@ void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz) printer.print_protected_constructors(); osprintf(os, "\n"); osprintf(os, "public:\n"); - printer.print_public_constructors(); - printer.print_constructors(); - printer.print_copy_assignment(); - printer.print_destructor(); - printer.print_ptr(); - printer.print_downcast(); - printer.print_ctx(); - osprintf(os, "\n"); - printer.print_persistent_callbacks(); - printer.print_methods(); - printer.print_set_enums(); + printer.print_public_methods(); osprintf(os, "};\n"); } @@ -380,6 +370,23 @@ void plain_cpp_generator::decl_printer::print_method(const Method &method) print_full_method_header(method); } +/* Print a declaration for a constructor for the "id" class + * that takes a user object. + */ +void plain_cpp_generator::decl_printer::print_id_constructor_user() +{ + print_id_constructor_user_header(); +} + +/* Print a declaration for an "id" method + * for retrieving the user object associated to the identifier. + * If "optional" is set, the method returns a std::optional user object. + */ +void plain_cpp_generator::decl_printer::print_id_user(bool optional) +{ + print_id_user_header(optional); +} + /* Print declarations of copy assignment operator. * * Each class has one assignment operator. @@ -515,6 +522,13 @@ void plain_cpp_generator::decl_printer::print_ctx() osprintf(os, " inline %sctx ctx() const;\n", ns.c_str()); } +/* Print a separator between groups of method declarations. + */ +void plain_cpp_generator::decl_printer::print_method_separator() +{ + os << "\n"; +} + /* Add a space to the return type "type" if needed, * i.e., if it is not the type of a pointer. */ @@ -648,17 +662,8 @@ void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) osprintf(os, "// implementations for isl::%s", cppname); printer.print_class_factory(); - printer.print_public_constructors(); printer.print_protected_constructors(); - printer.print_constructors(); - printer.print_copy_assignment(); - printer.print_destructor(); - printer.print_ptr(); - printer.print_downcast(); - printer.print_ctx(); - printer.print_persistent_callbacks(); - printer.print_methods(); - printer.print_set_enums(); + printer.print_public_methods(); printer.print_stream_insertion(); } @@ -768,8 +773,7 @@ void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr) return; print_check_ptr(ptr); - osprintf(os, " auto saved_ctx = %s_get_ctx(%s);\n", - clazz.name.c_str(), ptr); + print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")"); print_on_error_continue(); } @@ -929,12 +933,12 @@ void plain_cpp_generator::impl_printer::print_method(const Method &method) print_save_ctx(method); print_on_error_continue(); - if (method.callback) - print_callback_local(method.callback); + for (const auto &callback : method.callbacks) + print_callback_local(callback); osprintf(os, " auto res = %s", methodname.c_str()); - Method::print_arg_list(os, 0, num_params, [&] (int i) { + method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) { method.print_param_use(os, i); }); osprintf(os, ";\n"); @@ -1002,7 +1006,7 @@ void plain_cpp_generator::impl_printer::print_method( print_check_ptr("ptr"); osprintf(os, " return "); method.print_call(os, generator.isl_namespace()); - method.print_cpp_arg_list(os, [&] (int i) { + method.print_cpp_arg_list(os, [&] (int i, int arg) { ParmVarDecl *param = method.fd->getParamDecl(i); print_arg_conversion(param, method.get_param(i)); @@ -1011,6 +1015,82 @@ void plain_cpp_generator::impl_printer::print_method( osprintf(os, "}\n"); } +/* Print a definition for a constructor for the "id" class + * that takes a user object. + * + * The user object is taken as a std::any and copied into + * a new std::any object on the heap. + * A pointer to this heap object is stored in the isl_id and + * is scheduled to be freed when the reference count of the isl_id + * drops to zero. + * If the allocation of the isl_id fails, then the heap object + * will not be freed automatically, so it needs to be freed manually. + * + * Unless checked C++ bindings are being generated, + * the ctx argument is copied into the save_ctx variable + * for use by print_throw_last_error, which throws an exception + * if the construction fails. + * During the function call, isl is made not to print any error message + * because the error message is included in the exception. + */ +void plain_cpp_generator::impl_printer::print_id_constructor_user() +{ + print_id_constructor_user_header(); + os << "{\n"; + if (!generator.checked) { + print_save_ctx("ctx"); + print_on_error_continue(); + } + os << " std::any *p = new std::any(any);\n"; + os << " auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n"; + os << " res = isl_id_set_free_user(res, &ctx::free_user);\n"; + os << " if (!res) {\n"; + os << " delete p;\n"; + if (!generator.checked) + print_throw_last_error(os); + os << " }\n"; + os << " ptr = res;\n"; + os << "}\n"; +} + +/* Print a definition for an "id" method + * for retrieving the user object associated to the identifier. + * If "optional" is set, the method returns a std::optional user object. + * The returned object is of a type specified by template parameter T. + * + * The isl_id needs to have been created by the constructor generated + * by print_id_constructor_user. That is, it needs to have a user pointer and + * it needs to have its free_user callback set to &ctx::free_user. + * The object stored in the std::any also needs to be of the required type. + * + * If "optional" is set, return a std::nullopt if any of the checks fail. + * Otherwise, throw an exception_invalid (or call isl_die and + * return a default T in the checked C++ bindings). + */ +void plain_cpp_generator::impl_printer::print_id_user(bool optional) +{ + auto fail = [&] (const char *msg) { + if (optional) + os << " return std::nullopt;\n"; + else + generator.print_invalid(os, 4, msg, "return T()"); + }; + os << "\n"; + print_id_user_header(optional); + os << "{\n"; + print_check_ptr("ptr"); + os << " std::any *p = (std::any *) isl_id_get_user(ptr);\n"; + os << " if (!p)\n"; + fail("no user pointer"); + os << " if (isl_id_get_free_user(ptr) != &ctx::free_user)\n"; + fail("user pointer not attached by C++ interface"); + os << " T *res = std::any_cast(p);\n"; + os << " if (!res)\n"; + fail("user pointer not of given type"); + os << " return *res;\n"; + os << "}\n"; +} + /* Print implementation of copy assignment operator. * * If the class has any persistent callbacks, then copy them @@ -1171,6 +1251,14 @@ void plain_cpp_generator::impl_printer::print_ctx() osprintf(os, "}\n"); } +/* Print a separator between groups of method definitions. + * + * No additional separator is required between method definitions. + */ +void plain_cpp_generator::impl_printer::print_method_separator() +{ +} + /* Print the implementations of the methods needed for the persistent callbacks * of the class. */ @@ -1272,6 +1360,13 @@ void plain_cpp_generator::impl_printer::print_argument_validity_check( print_throw_NULL_input(os); } +/* Print code for saving a copy of "ctx" in a "saved_ctx" variable. + */ +void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx) +{ + os << " auto saved_ctx = " << ctx << ";\n"; +} + /* Print code for saving a copy of the isl::ctx available at the start * of the method "method" in a "saved_ctx" variable, * for use in exception handling. @@ -1292,17 +1387,10 @@ void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method) if (generator.checked) return; - if (method.kind == Method::Kind::member_method) { - osprintf(os, " auto saved_ctx = ctx();\n"); - return; - } - if (is_isl_ctx(type)) { - std::string name; - - name = param->getName().str(); - osprintf(os, " auto saved_ctx = %s;\n", name.c_str()); - return; - } + if (method.kind == Method::Kind::member_method) + return print_save_ctx("ctx()"); + if (is_isl_ctx(type)) + return print_save_ctx(param->getName().str()); n = method.num_params(); for (int i = 0; i < n; ++i) { ParmVarDecl *param = method.fd->getParamDecl(i); @@ -1310,8 +1398,7 @@ void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method) if (!is_isl_type(type)) continue; - osprintf(os, " auto saved_ctx = %s.ctx();\n", - param->getName().str().c_str()); + print_save_ctx(param->getName().str() + ".ctx()"); return; } } @@ -1393,10 +1480,10 @@ void plain_cpp_generator::impl_printer::print_exceptional_execution_check( print_persistent_callback_exceptional_execution_check(os, method); - if (method.callback) { + for (const auto &callback : method.callbacks) { std::string name; - name = method.callback->getName().str(); + name = callback->getName().str(); osprintf(os, " if (%s_data.eptr)\n", name.c_str()); osprintf(os, " std::rethrow_exception(%s_data.eptr);\n", name.c_str()); @@ -1715,6 +1802,100 @@ bool plain_cpp_generator::plain_printer::want_descendent_overloads( return methods.size() > 1; } +/* Print the header of the constructor for the "id" class + * that takes a user object. + * + * The user object is taken as a std::any. + */ +void plain_cpp_generator::plain_printer::print_id_constructor_user_header() +{ + if (declarations) + os << " inline explicit "; + else + os << "id::"; + os << "id(" << generator.isl_namespace() << "ctx ctx, " + << "const std::string &str, const std::any &any)"; + if (declarations) + os << ";"; + os << "\n"; +} + +/* Print the header of the "id" method + * for retrieving the user object associated to the identifier. + * If "optional" is set, the method returns a std::optional user object. + * The returned object is of a type specified by template parameter T. + */ +void plain_cpp_generator::plain_printer::print_id_user_header(bool optional) +{ + auto indent = declarations ? " " : ""; + os << indent << "template \n"; + os << indent << (optional ? "std::optional " : "T "); + if (!declarations) + os << "id::"; + os << (optional ? "try_" : ""); + os << "user() const"; + if (declarations) + os << ";"; + os << "\n"; +} + +/* Perform printing by "fn" in a context that only gets compiled + * by C++17 compilers. + */ +static void on_cplusplus17(ostream &os, const std::function &fn) +{ + os << "#if __cplusplus >= 201703L\n"; + fn(); + os << "#endif\n"; +} + +/* Print declarations or definitions of the special methods of the "id" class + * that are not automatically derived from the C interface. + * + * In particular, print a constructor that takes a user pointer + * as well as methods for retrieving this user pointer. + * + * These methods require C++17 features. + */ +void plain_cpp_generator::plain_printer::print_special_id() +{ + os << "\n"; + on_cplusplus17(os, [this] () { + print_id_constructor_user(); + print_id_user(true); + print_id_user(false); + }); +} + +/* Print declarations or definitions of any special methods of this class + * not automatically derived from the C interface. + * + * In particular, print special methods for the "id" class. + */ +void plain_cpp_generator::plain_printer::print_special() +{ + if (clazz.name == "isl_id") + print_special_id(); +} + +/* Print declarations or definitions of the public methods. + */ +void plain_cpp_generator::plain_printer::print_public_methods() +{ + print_public_constructors(); + print_constructors(); + print_copy_assignment(); + print_destructor(); + print_ptr(); + print_downcast(); + print_ctx(); + print_method_separator(); + print_persistent_callbacks(); + print_methods(); + print_set_enums(); + print_special(); +} + /* Print the body of C function callback with the given indentation * that can be use as an argument to "param" for marshalling * the corresponding C++ callback. diff --git a/polly/lib/External/isl/interface/plain_cpp.h b/polly/lib/External/isl/interface/plain_cpp.h index 2644802..17f4af0 100644 --- a/polly/lib/External/isl/interface/plain_cpp.h +++ b/polly/lib/External/isl/interface/plain_cpp.h @@ -81,6 +81,21 @@ struct plain_cpp_generator::plain_printer : public cpp_generator::class_printer void print_callback_data_decl(ParmVarDecl *param, const string &name); virtual bool want_descendent_overloads(const function_set &methods) override; + virtual void print_public_constructors() = 0; + virtual void print_copy_assignment() = 0; + virtual void print_destructor() = 0; + virtual void print_ptr() = 0; + virtual void print_downcast() = 0; + virtual void print_ctx() = 0; + virtual void print_method_separator() = 0; + virtual void print_persistent_callbacks() = 0; + void print_public_methods(); + void print_id_constructor_user_header(); + void print_id_user_header(bool optional); + virtual void print_id_constructor_user() = 0; + virtual void print_id_user(bool optional) = 0; + void print_special_id(); + void print_special(); }; /* A helper class for printing method declarations of a class. @@ -95,18 +110,21 @@ struct plain_cpp_generator::decl_printer : void print_subclass_type(); void print_class_factory(const std::string &prefix = std::string()); void print_protected_constructors(); - void print_copy_assignment(); - void print_public_constructors(); - void print_destructor(); - void print_ptr(); + virtual void print_copy_assignment() override; + virtual void print_public_constructors() override; + virtual void print_destructor() override; + virtual void print_ptr() override; void print_isa_type_template(int indent, const isl_class &super); - void print_downcast(); - void print_ctx(); + virtual void print_downcast() override; + virtual void print_ctx() override; + virtual void print_method_separator() override; void print_persistent_callback_data(FunctionDecl *method); - void print_persistent_callbacks(); + virtual void print_persistent_callbacks() override; virtual void print_method(const Method &method) override; virtual void print_method(const ConversionMethod &method) override; virtual void print_get_method(FunctionDecl *fd) override; + virtual void print_id_constructor_user() override; + virtual void print_id_user(bool optional) override; }; /* A helper class for printing method definitions of a class. @@ -127,15 +145,17 @@ struct plain_cpp_generator::impl_printer : void print_check_ptr_end(const char *ptr); void print_class_factory(); void print_protected_constructors(); - void print_public_constructors(); - void print_copy_assignment(); - void print_destructor(); - void print_ptr(); - void print_downcast(); - void print_ctx(); + virtual void print_public_constructors() override; + virtual void print_copy_assignment() override; + virtual void print_destructor() override; + virtual void print_ptr() override; + virtual void print_downcast() override; + virtual void print_ctx() override; + virtual void print_method_separator() override; void print_set_persistent_callback(const Method &method); - void print_persistent_callbacks(); + virtual void print_persistent_callbacks() override; void print_argument_validity_check(const Method &method); + void print_save_ctx(const std::string &ctx); void print_save_ctx(const Method &method); void print_on_error_continue(); void print_exceptional_execution_check(const Method &method); @@ -147,6 +167,8 @@ struct plain_cpp_generator::impl_printer : void print_callback_body(int indent, ParmVarDecl *param, const string &name); void print_callback_local(ParmVarDecl *param); + virtual void print_id_constructor_user() override; + virtual void print_id_user(bool optional) override; }; #endif diff --git a/polly/lib/External/isl/interface/python.cc b/polly/lib/External/isl/interface/python.cc index 686bcc7..e4a8288 100644 --- a/polly/lib/External/isl/interface/python.cc +++ b/polly/lib/External/isl/interface/python.cc @@ -195,8 +195,7 @@ void python_generator::print_copy(QualType type) } /* Construct a wrapper for callback argument "param" (at position "arg"). - * Assign the wrapper to "cb". We assume here that a function call - * has at most one callback argument. + * Assign the wrapper to "cb{arg}". * * The wrapper converts the arguments of the callback to python types, * taking a copy if the C callback does not take its arguments. @@ -272,7 +271,7 @@ void python_generator::print_callback(ParmVarDecl *param, int arg) print_copy(return_type); printf("(res.ptr)\n"); } - printf(" cb = fn(cb_func)\n"); + printf(" cb%d = fn(cb_func)\n", arg); } /* Print the argument at position "arg" in call to "fd". @@ -284,7 +283,7 @@ void python_generator::print_callback(ParmVarDecl *param, int arg) * assuming that the caller has made the context available * in a "ctx" variable. * Otherwise, if the argument is a callback, then print a reference to - * the callback wrapper "cb". + * the corresponding callback wrapper. * Otherwise, if the argument is marked as consuming a reference, * then pass a copy of the pointer stored in the corresponding * argument passed to the Python method. @@ -302,7 +301,7 @@ void python_generator::print_arg_in_call(FunctionDecl *fd, const char *fmt, if (is_isl_ctx(type)) { printf("ctx"); } else if (is_callback(type)) { - printf("cb"); + printf("cb%d", arg - skip); } else if (takes(param)) { print_copy(type); printf("("); @@ -372,6 +371,8 @@ static void print_persistent_callback_failure_check(int indent, * then keep track of the constructed C callback (such that it doesn't * get destroyed) and the data structure that holds the captured exception * (such that it can be raised again). + * The callback appears in position 1 and the C callback is therefore + * called "cb1". * * If the return type is a (const) char *, then convert the result * to a Python string, raising an error on NULL and freeing @@ -406,14 +407,14 @@ void python_generator::print_method_return(int indent, const isl_class &clazz, string callback_name; callback_name = clazz.persistent_callback_name(method); - print_indent(indent, "obj.%s = { 'func': cb, " + print_indent(indent, "obj.%s = { 'func': cb1, " "'exc_info': exc_info }\n", callback_name.c_str()); } print_indent(indent, "return obj\n"); } else if (is_string(return_type)) { print_indent(indent, "if res == 0:\n"); - print_indent(indent, " raise\n"); + print_indent(indent, " raise Error\n"); print_indent(indent, "string = " "cast(res, c_char_p).value.decode('ascii')\n"); @@ -423,7 +424,7 @@ void python_generator::print_method_return(int indent, const isl_class &clazz, print_indent(indent, "return string\n"); } else if (is_isl_neg_error(return_type)) { print_indent(indent, "if res < 0:\n"); - print_indent(indent, " raise\n"); + print_indent(indent, " raise Error\n"); if (is_isl_bool(return_type)) print_indent(indent, "return bool(res)\n"); else if (is_isl_size(return_type)) @@ -456,20 +457,19 @@ void python_generator::print_get_method(const isl_class &clazz, /* Print a call to "method", along with the corresponding * return statement, with the given indentation. * "drop_ctx" is set if the first argument is an isl_ctx. - * "drop_user" is set if the last argument is a "user" argument - * corresponding to a callback argument. * * A "ctx" variable is first initialized as it may be needed * in the first call to print_arg_in_call and in print_method_return. * - * If the method has a callback function, then any exception - * thrown in the callback also need to be rethrown. + * If the method has any callback function, then any exception + * thrown in any callback also need to be rethrown. */ void python_generator::print_method_call(int indent, const isl_class &clazz, - FunctionDecl *method, const char *fmt, int drop_ctx, int drop_user) + FunctionDecl *method, const char *fmt, int drop_ctx) { string fullname = method->getName().str(); int num_params = method->getNumParams(); + int drop_user = 0; if (drop_ctx) { print_indent(indent, "ctx = Context.getDefaultInstance()\n"); @@ -479,16 +479,19 @@ void python_generator::print_method_call(int indent, const isl_class &clazz, printf(".ctx\n"); } print_indent(indent, "res = isl.%s(", fullname.c_str()); - for (int i = 0; i < num_params - drop_user; ++i) { + for (int i = 0; i < num_params; ++i) { if (i > 0) printf(", "); - print_arg_in_call(method, fmt, i, drop_ctx); - } - if (drop_user) + print_arg_in_call(method, fmt, i, drop_ctx + drop_user); + if (!is_callback_arg(method, i)) + continue; + ++drop_user; + ++i; printf(", None"); + } printf(")\n"); - if (drop_user) + if (drop_user > 0) print_rethrow(indent, "exc_info[0]"); print_method_return(indent, clazz, method, fmt); @@ -506,10 +509,10 @@ void python_generator::print_method_call(int indent, const isl_class &clazz, * If, moreover, this first argument is an isl_ctx, then remove * it from the arguments of the Python method. * - * If the function has a callback argument, then it also has a "user" - * argument. Since Python has closures, there is no need for such - * a user argument in the Python interface, so we simply drop it. - * We also create a wrapper ("cb") for the callback. + * If the function has any callback arguments, then it also has corresponding + * "user" arguments. Since Python has closures, there is no need for such + * user arguments in the Python interface, so we simply drop them. + * We also create a wrapper ("cb{arg}") for each callback. * * If the function consumes a reference, then we pass it a copy of * the actual argument. @@ -527,25 +530,25 @@ void python_generator::print_method(const isl_class &clazz, int drop_ctx = first_arg_is_isl_ctx(method); for (int i = 1; i < num_params; ++i) { - ParmVarDecl *param = method->getParamDecl(i); - QualType type = param->getOriginalType(); - if (is_callback(type)) - drop_user = 1; + if (is_callback_arg(method, i)) + drop_user += 1; } print_method_header(is_static(clazz, method), cname, num_params - drop_ctx - drop_user); print_type_checks(cname, method, drop_ctx, - num_params - drop_user, super); + num_params, super); + drop_user = 0; for (int i = 1; i < num_params; ++i) { ParmVarDecl *param = method->getParamDecl(i); QualType type = param->getOriginalType(); if (!is_callback(type)) continue; - print_callback(param, i - drop_ctx); + print_callback(param, i - drop_ctx - drop_user); + drop_user += 1; } - print_method_call(8, clazz, method, fixed_arg_fmt, drop_ctx, drop_user); + print_method_call(8, clazz, method, fixed_arg_fmt, drop_ctx); if (clazz.is_get_method(method)) print_get_method(clazz, method); @@ -568,9 +571,18 @@ static void print_argument_check(QualType type, int i) } } +/* Is any element of "vector" set? + */ +static bool any(const std::vector &vector) +{ + return std::find(vector.begin(), vector.end(), true) != vector.end(); +} + /* Print a test that checks whether the arguments passed * to the Python method correspond to the arguments - * expected by "fd". + * expected by "fd" and + * check if the object on which the method is called, if any, + * is of the right type. * "drop_ctx" is set if the first argument of "fd" is an isl_ctx, * which does not appear as an argument to the Python method. * @@ -579,14 +591,17 @@ static void print_argument_check(QualType type, int i) * to be of the type as prescribed by the second input argument * of the conversion function. * The corresponding arguments are then converted to the expected types - * if needed. The argument tuple first needs to be converted to a list + * if needed. + * The object on which the method is called is also converted if needed. + * The argument tuple first needs to be converted to a list * in order to be able to modify the entries. */ void python_generator::print_argument_checks(const isl_class &clazz, FunctionDecl *fd, int drop_ctx) { int num_params = fd->getNumParams(); - int first = generator::is_static(clazz, fd) ? drop_ctx : 1; + bool is_static = generator::is_static(clazz, fd); + int first = is_static ? drop_ctx : 1; std::vector convert(num_params); printf(" if len(args) == %d", num_params - drop_ctx); @@ -610,14 +625,16 @@ void python_generator::print_argument_checks(const isl_class &clazz, } printf(":\n"); - if (std::find(convert.begin(), convert.end(), true) == convert.end()) + if (is_static && !any(convert)) return; print_indent(12, "args = list(args)\n"); + first = is_static ? drop_ctx : 0; for (int i = first; i < num_params; ++i) { + bool is_self = !is_static && i == 0; ParmVarDecl *param = fd->getParamDecl(i); string type; - if (!convert[i]) + if (!is_self && !convert[i]) continue; type = type2python(extract_type(param->getOriginalType())); print_type_check(12, type, var_arg_fmt, @@ -639,7 +656,7 @@ void python_generator::print_method_overload(const isl_class &clazz, int drop_ctx = first_arg_is_isl_ctx(method); print_argument_checks(clazz, method, drop_ctx); - print_method_call(12, clazz, method, var_arg_fmt, drop_ctx, 0); + print_method_call(12, clazz, method, var_arg_fmt, drop_ctx); } /* Print a python method with a name derived from "fullname" @@ -755,6 +772,83 @@ void python_generator::print_constructor(const isl_class &clazz, printf(" return\n"); } +/* The definition of the part of constructor for the "id" class + * that construct an object from a name and a user object, + * without the initial newline. + * + * Just like the parts generated by python_generator::print_constructor, + * the result of the isl_id_alloc call is stored in self.ptr and + * a reference to the default context is stored in self.ctx. + * Also, just like any other constructor or method with a string argument, + * the python string is first encoded as a byte sequence, + * using 'ascii' as encoding. + * + * Since the isl_id keeps a reference to the Python user object, + * the reference count of the Python object needs to be incremented, + * but only if the construction of the isl_id is successful. + * The reference count of the Python object is decremented again + * by Context.free_user when the reference count of the isl_id + * drops to zero. + */ +static const char *const id_constructor_user = &R"( + if len(args) == 2 and type(args[0]) == str: + self.ctx = Context.getDefaultInstance() + name = args[0].encode('ascii') + self.ptr = isl.isl_id_alloc(self.ctx, name, args[1]) + self.ptr = isl.isl_id_set_free_user(self.ptr, Context.free_user) + if self.ptr is not None: + pythonapi.Py_IncRef(py_object(args[1])) + return +)"[1]; + +/* Print any special constructor parts of this class that are not + * automatically derived from the C interface. + * + * In particular, print a special constructor part for the "id" class. + */ +void python_generator::print_special_constructors(const isl_class &clazz) +{ + if (clazz.name != "isl_id") + return; + + printf("%s", id_constructor_user); +} + +/* The definition of an "id" method + * for retrieving the user object associated to the identifier, + * without the initial newline. + * + * The isl_id needs to have been created by the constructor + * in id_constructor_user. That is, it needs to have a user pointer and + * it needs to have its free_user callback set to Context.free_user. + * The functions need to be cast to c_void_p to be able to compare + * the addresses. + * + * Return None if any of the checks fail. + * Note that isl_id_get_user returning NULL automatically results in None. + */ +static const char *const id_user = &R"( + def user(self): + free_user = cast(Context.free_user, c_void_p) + id_free_user = cast(isl.isl_id_get_free_user(self.ptr), c_void_p) + if id_free_user.value != free_user.value: + return None + return isl.isl_id_get_user(self.ptr) +)"[1]; + +/* Print any special methods of this class that are not + * automatically derived from the C interface. + * + * In particular, print a special method for the "id" class. + */ +void python_generator::print_special_methods(const isl_class &clazz) +{ + if (clazz.name != "isl_id") + return; + + printf("%s", id_user); +} + /* If "clazz" has a type function describing subclasses, * then add constructors that allow each of these subclasses * to be treated as an object to the superclass. @@ -824,34 +918,37 @@ void python_generator::print_restype(FunctionDecl *fd) } /* Tell ctypes about the types of the arguments of the function "fd". + * + * Any callback argument is followed by a user pointer argument. + * Each such pair or arguments is handled together. */ void python_generator::print_argtypes(FunctionDecl *fd) { string fullname = fd->getName().str(); int n = fd->getNumParams(); - int drop_user = 0; printf("isl.%s.argtypes = [", fullname.c_str()); - for (int i = 0; i < n - drop_user; ++i) { + for (int i = 0; i < n; ++i) { ParmVarDecl *param = fd->getParamDecl(i); QualType type = param->getOriginalType(); - if (is_callback(type)) - drop_user = 1; if (i) printf(", "); if (is_isl_ctx(type)) printf("Context"); - else if (is_isl_type(type) || is_callback(type)) + else if (is_isl_type(type)) printf("c_void_p"); + else if (is_callback(type)) + printf("c_void_p, c_void_p"); else if (is_string(type)) printf("c_char_p"); else if (is_long(type)) printf("c_long"); else printf("c_int"); + + if (is_callback(type)) + ++i; } - if (drop_user) - printf(", c_void_p"); printf("]\n"); } @@ -867,7 +964,8 @@ void python_generator::print_method_type(FunctionDecl *fd) * if it is one of those type subclasses, then print a __new__ method. * * In the superclass, the __new__ method constructs an object - * of the subclass type specified by the type function. + * of the subclass type specified by the type function, + * raising an error on an error type. * In the subclass, the __new__ method reverts to the original behavior. */ void python_generator::print_new(const isl_class &clazz, @@ -891,7 +989,7 @@ void python_generator::print_new(const isl_class &clazz, printf(" return %s(**keywords)\n", type2python(i->second).c_str()); } - printf(" raise\n"); + printf(" raise Error\n"); } printf(" return super(%s, cls).__new__(cls)\n", @@ -1003,9 +1101,11 @@ void python_generator::print_method_types(const isl_class &clazz) * * Then we print a constructor with several cases, one for constructing * a Python object from a return value, one for each function that - * was marked as a constructor and for each type based subclass. + * was marked as a constructor, a class specific constructor, if any, and + * one for each type based subclass. * - * Next, we print out some common methods and the methods corresponding + * Next, we print out some common methods, class specific methods and + * the methods corresponding * to functions that are not marked as constructors, including those * that set a persistent callback and those that set an enum value. * @@ -1016,9 +1116,6 @@ void python_generator::print_method_types(const isl_class &clazz) void python_generator::print(const isl_class &clazz) { string p_name = type2python(clazz.subclass_name); - function_set::const_iterator in; - map::const_iterator it; - map >::const_iterator ie; vector super = find_superclasses(clazz.type); const set &callbacks = clazz.persistent_callbacks; @@ -1038,9 +1135,9 @@ void python_generator::print(const isl_class &clazz) printf(" self.ptr = keywords[\"ptr\"]\n"); printf(" return\n"); - for (in = clazz.constructors.begin(); in != clazz.constructors.end(); - ++in) - print_constructor(clazz, *in); + for (const auto &cons : clazz.constructors) + print_constructor(clazz, cons); + print_special_constructors(clazz); print_upcast_constructors(clazz); printf(" raise Error\n"); printf(" def __del__(self):\n"); @@ -1051,12 +1148,13 @@ void python_generator::print(const isl_class &clazz) print_representation(clazz, p_name); print_copy_callbacks(clazz); - for (in = callbacks.begin(); in != callbacks.end(); ++in) - print_method(clazz, *in, super); - for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) - print_method(clazz, it->first, it->second, super); - for (ie = clazz.set_enums.begin(); ie != clazz.set_enums.end(); ++ie) - print_set_enum(clazz, ie->first, super); + print_special_methods(clazz); + for (const auto &callback : callbacks) + print_method(clazz, callback, super); + for (const auto &kvp : clazz.methods) + print_method(clazz, kvp.first, kvp.second, super); + for (const auto &kvp : clazz.set_enums) + print_set_enum(clazz, kvp.first, super); printf("\n"); diff --git a/polly/lib/External/isl/interface/python.h b/polly/lib/External/isl/interface/python.h index e56c23d..87d5cae 100644 --- a/polly/lib/External/isl/interface/python.h +++ b/polly/lib/External/isl/interface/python.h @@ -38,6 +38,8 @@ private: void print_restype(FunctionDecl *fd); void print(map &classes, set &done); void print_constructor(const isl_class &clazz, FunctionDecl *method); + void print_special_constructors(const isl_class &clazz); + void print_special_methods(const isl_class &clazz); void print_upcast_constructors(const isl_class &clazz); void print_new(const isl_class &clazz, const string &python_name); @@ -51,7 +53,7 @@ private: vector super); void print_method_call(int indent, const isl_class &clazz, FunctionDecl *method, const char *fmt, - int drop_ctx, int drop_user); + int drop_ctx); void print_argument_checks(const isl_class &clazz, FunctionDecl *fd, int drop_ctx); void print_method_overload(const isl_class &clazz, diff --git a/polly/lib/External/isl/interface/template_cpp.cc b/polly/lib/External/isl/interface/template_cpp.cc index debbfcd..2beca82 100644 --- a/polly/lib/External/isl/interface/template_cpp.cc +++ b/polly/lib/External/isl/interface/template_cpp.cc @@ -429,6 +429,12 @@ static Signature bin_map_domain = { { Domain, Range }, { { Domain, Range }, { Domain } } }; static Signature bin_map_range = { { Domain, Range }, { { Domain, Range }, { Range } } }; +static Signature bin_map_domain_wrapped_domain = + { { { Domain, Domain2 }, Range }, + { { { Domain, Domain2 }, Range }, { Domain } } }; +static Signature bin_map_range_wrapped_domain = + { { Domain, { Range, Range2 } }, + { { Domain, { Range, Range2 } }, { Range } } }; /* Signatures for binary operations, where the second argument * is an identifier (with an anonymous tuple). @@ -529,6 +535,24 @@ static Signature each_map = { { Res }, { { Domain, Range }, { Res }, { Domain, Range } } }; static std::vector each = { each_params, each_set, each_map }; +/* Signatures for isl_*_list_foreach_scc. + * + * The first callback takes two elements with the same tuple kinds. + * The second callback takes a list with the same tuple kinds. + */ +static Signature each_scc_params = + { { Res }, { { }, { Res }, { }, { }, { Res }, { } } }; +static Signature each_scc_set = + { { Res }, { { Domain }, + { Res }, { Domain }, { Domain }, + { Res }, { Domain } } }; +static Signature each_scc_map = + { { Res }, { { Domain, Range }, + { Res }, { Domain, Range }, { Domain, Range }, + { Res }, { Domain, Range } } }; +static std::vector each_scc = + { each_scc_params, each_scc_set, each_scc_map }; + /* Signature for creating a map from a range, * where the domain is given by an extra argument. */ @@ -779,7 +803,7 @@ member_methods { { "ceil", fn_un_op }, { "coalesce", un_op }, { "cond", fn_ter_op }, - { "constant_multi_val", range_op }, + { "constant", range_op }, { "curry", { curry } }, { "deltas", { transformation_domain } }, { "detect_equalities", un_op }, @@ -798,10 +822,12 @@ member_methods { { "flatten_range", flatten_range }, { "floor", fn_un_op }, { "foreach", each }, + { "foreach_scc", each_scc }, { "ge_set", { set_join } }, { "gt_set", { set_join } }, { "gist", bin_op }, { "gist_domain", { bin_map_domain } }, + { "gist_params", { bin_set_params, bin_map_params } }, { "identity", { un_map, set_to_map } }, { "identity_on_domain", { set_to_map } }, { "indicator_function", anonymous_from_domain }, @@ -809,7 +835,12 @@ member_methods { { "intersect", bin_op }, { "intersect_params", { bin_set_params, bin_map_params } }, { "intersect_domain", { bin_map_domain } }, + { "intersect_domain_wrapped_domain", + { bin_map_domain_wrapped_domain } }, { "intersect_range", { bin_map_range } }, + { "intersect_range_wrapped_domain", + { bin_map_range_wrapped_domain } }, + { "lattice_tile", { un_set } }, { "le_set", { set_join } }, { "lt_set", { set_join } }, { "lex_le_at", { map_cmp } }, @@ -822,8 +853,10 @@ member_methods { { "lower_bound", fn_bin_op }, { "map_from_set", { set_to_map } }, { "max", min_max }, + { "max_val", range_op }, { "max_multi_val", range_op }, { "min", min_max }, + { "min_val", range_op }, { "min_multi_val", range_op }, { "mod", bin_val }, { "on_domain", { map_from_domain_and_range } }, @@ -1020,22 +1053,34 @@ static std::vector add_name(const std::vector &tuples) return named; } -/* Add a template class called "name", of which the methods are described - * by "clazz" and where the corresponding base type has kinds "base_kinds". +/* Look up the (initial) specializations of the class called "name". + * If no specializations have been defined, then return an empty vector. * + * Start from the initial specializations of the corresponding base type. * If this template class is a multi-expression, then it was derived * from an anonymous function type. Replace the final Anonymous * tuple kind by a placeholder in this case. */ +static std::vector lookup_class_tuples(const std::string &name) +{ + std::string base = base_type(name); + + if (base_kinds.count(base) == 0) + return { }; + if (name.find("multi_") != std::string::npos) + return add_name(base_kinds.at(base)); + return base_kinds.at(base); +} + +/* Add a template class called "name", of which the methods are described + * by "clazz" and the initial specializations by "class_tuples". + */ void template_cpp_generator::add_template_class(const isl_class &clazz, - const std::string &name, const std::vector &base_kinds) + const std::string &name, const std::vector &class_tuples) { auto isl_namespace = cpp_type_printer().isl_namespace(); auto super = isl_namespace + name; - auto class_tuples = base_kinds; - if (name.find("multi_") != std::string::npos) - class_tuples = add_name(class_tuples); template_classes.emplace(name, template_class{name, super, clazz, class_tuples}); } @@ -1061,11 +1106,11 @@ template_cpp_generator::template_cpp_generator(clang::SourceManager &SM, for (const auto &kvp : classes) { const auto &clazz = kvp.second; std::string name = type2cpp(clazz); - std::string base = base_type(name); + const auto &class_tuples = lookup_class_tuples(name); - if (base_kinds.count(base) == 0) + if (class_tuples.empty()) continue; - add_template_class(clazz, name, base_kinds.at(base)); + add_template_class(clazz, name, class_tuples); } } @@ -1556,22 +1601,25 @@ void template_cpp_generator::method_decl_printer::print_method_sig( } /* Return the total number of arguments in the signature for "method", - * taking into account a possible callback argument. + * taking into account any possible callback arguments. * * In particular, if the method has a callback argument, * then the return kind of the callback appears at the position * of the callback and the kinds of the arguments (except * the user pointer argument) appear in the following positions. + * The user pointer argument that follows the callback argument + * is also removed. */ static int total_params(const Method &method) { int n = method.num_params(); - if (method.callback) { - auto callback_type = method.callback->getType(); - auto callback = generator::extract_prototype(callback_type); + for (const auto &callback : method.callbacks) { + auto callback_type = callback->getType(); + auto proto = generator::extract_prototype(callback_type); - n += callback->getNumArgs() - 1; + n += proto->getNumArgs() - 1; + n -= 1; } return n; @@ -1631,7 +1679,7 @@ void template_cpp_generator::method_impl_printer::print_constructor_body( const auto &base_name = instance.base_name(); os << " : " << base_name; - method.print_cpp_arg_list(os, [&] (int i) { + method.print_cpp_arg_list(os, [&] (int i, int arg) { os << method.fd->getParamDecl(i)->getName().str(); }); os << "\n"; @@ -1644,6 +1692,7 @@ void template_cpp_generator::method_impl_printer::print_constructor_body( * calling "print_arg" with the type and the name of the arguments, * where the type is obtained from "type_printer" with argument positions * shifted by "shift". + * None of the arguments should be skipped. */ static void print_callback_args(std::ostream &os, const FunctionProtoType *callback, const cpp_type_printer &type_printer, @@ -1659,40 +1708,34 @@ static void print_callback_args(std::ostream &os, auto cpptype = type_printer.param(shift + i, type); print_arg(cpptype, name); + + return false; }); } -/* Print a lambda for passing to the plain method corresponding to "method" - * with signature "sig". - * - * The method is assumed to have only the callback as argument, - * which means the arguments of the callback are shifted by 2 - * with respect to the arguments of the signature - * (one for the position of the callback argument plus - * one for the return kind of the callback). +/* Print a lambda corresponding to "callback" + * with signature "sig" and argument positions shifted by "shift". * * The lambda takes arguments with plain isl types and * calls the callback of "method" with templated arguments. */ -static void print_callback_lambda(std::ostream &os, const Method &method, - const Signature &sig) +static void print_callback_lambda(std::ostream &os, ParmVarDecl *callback, + const Signature &sig, int shift) { - auto callback_type = method.callback->getType(); - auto callback_name = method.callback->getName().str(); - auto callback = generator::extract_prototype(callback_type); - - if (method.num_params() != 2) - generator::die("callback is assumed to be single argument"); + auto callback_type = callback->getType(); + auto callback_name = callback->getName().str(); + auto proto = generator::extract_prototype(callback_type); - os << " auto lambda = [&] "; - print_callback_args(os, callback, cpp_type_printer(), 2, + os << " auto lambda_" << callback_name << " = [&] "; + print_callback_args(os, proto, cpp_type_printer(), shift, [&] (const std::string &type, const std::string &name) { os << type << " " << name; }); os << " {\n"; os << " return " << callback_name; - print_callback_args(os, callback, template_cpp_arg_type_printer(sig), 2, + print_callback_args(os, proto, template_cpp_arg_type_printer(sig), + shift, [&] (const std::string &type, const std::string &name) { os << type << "(" << name << ")"; }); @@ -1701,13 +1744,40 @@ static void print_callback_lambda(std::ostream &os, const Method &method, os << " };\n"; } +/* Print lambdas for passing to the plain method corresponding to "method" + * with signature "sig". + * + * The method is assumed to have only callbacks as argument, + * which means the arguments of the first callback are shifted by 2 + * with respect to the arguments of the signature + * (one for the position of the callback argument plus + * one for the return kind of the callback). + * The arguments of a subsequent callback are shifted by + * the number of arguments of the previous callback minus one + * for the user pointer plus one for the return kind. + */ +static void print_callback_lambdas(std::ostream &os, const Method &method, + const Signature &sig) +{ + int shift; + + if (method.num_params() != 1 + 2 * method.callbacks.size()) + generator::die("callbacks are assumed to be only arguments"); + + shift = 2; + for (const auto &callback : method.callbacks) { + print_callback_lambda(os, callback, sig, shift); + shift += generator::prototype_n_args(callback->getType()); + } +} + /* Print a definition of the member method "method", which is known * to have a callback argument, with signature "sig". * - * First print a lambda for passing to the corresponding plain method and + * First print lambdas for passing to the corresponding plain method and * calling the callback of "method" with templated arguments. - * Then call the plain method, replacing the original callback - * by the lambda. + * Then call the plain method, replacing the original callbacks + * by the lambdas. * * The return value is assumed to be isl_bool or isl_stat * so that no conversion to a template type is required. @@ -1723,17 +1793,16 @@ void template_cpp_generator::method_impl_printer::print_callback_method_body( os << "{\n"; - print_callback_lambda(os, method, sig); + print_callback_lambdas(os, method, sig); os << " return "; os << base_name << "::" << method.name; - method.print_cpp_arg_list(os, [&] (int i) { + method.print_cpp_arg_list(os, [&] (int i, int arg) { auto param = method.fd->getParamDecl(i); - if (param == method.callback) - os << "lambda"; - else - os << param->getName().str(); + if (generator::is_callback(param->getType())) + os << "lambda_"; + os << param->getName().str(); }); os << ";\n"; @@ -1755,7 +1824,7 @@ void template_cpp_generator::method_impl_printer::print_method_body( os << "{\n"; os << " auto res = "; os << base_name << "::" << method.name; - method.print_cpp_arg_list(os, [&] (int i) { + method.print_cpp_arg_list(os, [&] (int i, int arg) { os << method.fd->getParamDecl(i)->getName().str(); }); os << ";\n"; @@ -1775,7 +1844,7 @@ void template_cpp_generator::method_impl_printer::print_method_body( * Otherwise print the method header, preceded by the template parameters, * if needed. * The body depends on whether the method is a constructor or - * takes a callback. + * takes any callbacks. */ void template_cpp_generator::method_impl_printer::print_method_sig( const Method &method, const Signature &sig, bool deleted) @@ -1789,7 +1858,7 @@ void template_cpp_generator::method_impl_printer::print_method_sig( os << "\n"; if (method.kind == Method::Kind::constructor) print_constructor_body(method, sig); - else if (method.callback) + else if (method.callbacks.size() != 0) print_callback_method_body(method, sig); else print_method_body(method, sig); @@ -2282,6 +2351,79 @@ void template_cpp_generator::class_printer::add_specialization( instance.template_class.add_specialization(maybe_unified.second); } +/* Does the type of the parameter at position "i" of "method" necessarily + * have a final Anonymous tuple? + * + * If the parameter is not of an isl type or if no specializations + * have been defined for the type, then it can be considered anonymous. + * Otherwise, if any specialization represents an anonymous function, + * then every specialization does, so simply check + * the first specialization. + */ +static bool param_is_anon(const Method &method, int i) +{ + ParmVarDecl *param = method.get_param(i); + QualType type = param->getOriginalType(); + + if (cpp_generator::is_isl_type(type)) { + const auto &name = type->getPointeeType().getAsString(); + const auto &cpp = cpp_generator::type2cpp(name); + const auto &tuples = lookup_class_tuples(cpp); + + if (tuples.empty()) + return true; + return tuples[0].is_anon(); + } + + return true; +} + +/* Replace the final tuple of "arg_kind" by Anonymous in "sig" and + * return the update signature, + * unless this would affect the class instance "instance_kind". + * + * If the original "instance_kind" is a special case + * of the result of the substitution, then "instance_kind" + * is not affected and the substitution can be applied + * to the entire signature. + */ +static Signature specialize_anonymous_arg(const Signature &sig, + const Kind &arg_kind, const Kind &instance_kind) +{ + const auto &subs = compute_unifier(arg_kind.back(), Anonymous); + const auto &specialized_instance = instance_kind.apply(subs); + + if (!specializer(specialized_instance, instance_kind).first) + return sig; + + return sig.apply(subs); +} + +/* If any of the arguments of "method" is of a type that necessarily + * has a final Anonymous tuple, but the corresponding entry + * in the signature "sig" is not Anonymous, then replace + * that entry by Anonymous and return the updated signature, + * unless this would affect the class instance "instance_kind". + */ +static Signature specialize_anonymous_args(const Signature &sig, + const Method &method, const Kind &instance_kind) +{ + auto specialized_sig = sig; + + method.on_cpp_arg_list([&] (int i, int arg) { + const auto &arg_kind = sig.args[arg]; + + if (arg_kind.is_anon()) + return; + if (!param_is_anon(method, i)) + return; + specialized_sig = specialize_anonymous_arg(specialized_sig, + arg_kind, instance_kind); + }); + + return specialized_sig; +} + /* Print a declaration or definition of the method "method" * if the template class specialization matches "match_arg". * Return true if so. @@ -2294,6 +2436,7 @@ void template_cpp_generator::class_printer::add_specialization( * If the template class specialization is a special case of * (the renamed) "match_arg" * then apply the specializer to the complete (renamed) signature, + * specialize any anonymous arguments, * check that the return kind is allowed and, if so, * print the declaration or definition using the specialized signature. * @@ -2310,6 +2453,8 @@ bool template_cpp_generator::class_printer::print_matching_method( if (maybe_specializer.first) { const auto &specializer = maybe_specializer.second; auto specialized_sig = sig.apply(rename).apply(specializer); + specialized_sig = specialize_anonymous_args(specialized_sig, + method, instance.kind); if (!is_return_kind(method, specialized_sig.ret)) return false; @@ -2532,15 +2677,15 @@ const std::string name_without_return(const Method &method) } /* If this method has a callback, then remove the type - * of the first argument of the callback from the name of the method. + * of the first argument of the first callback from the name of the method. * Otherwise, simply return the name of the method. */ const std::string callback_name(const Method &method) { - if (!method.callback) + if (method.callbacks.size() == 0) return method.name; - auto type = method.callback->getType(); + auto type = method.callbacks.at(0)->getType(); auto callback = cpp_generator::extract_prototype(type); auto arg_type = plain_type(callback->getArgType(0)); return generator::drop_suffix(method.name, "_" + arg_type); diff --git a/polly/lib/External/isl/interface/template_cpp.h b/polly/lib/External/isl/interface/template_cpp.h index a141a48..ae3315d 100644 --- a/polly/lib/External/isl/interface/template_cpp.h +++ b/polly/lib/External/isl/interface/template_cpp.h @@ -99,7 +99,7 @@ class template_cpp_generator : public cpp_generator { struct class_impl_printer; void add_template_class(const isl_class &clazz, const std::string &name, - const std::vector &base_kinds); + const std::vector &class_tuples); public: template_cpp_generator(clang::SourceManager &SM, std::set &exported_types, diff --git a/polly/lib/External/isl/isl_aff.c b/polly/lib/External/isl/isl_aff.c index 40ca78d..9bb4b22 100644 --- a/polly/lib/External/isl/isl_aff.c +++ b/polly/lib/External/isl/isl_aff.c @@ -6,6 +6,7 @@ * Copyright 2016 Sven Verdoolaege * Copyright 2018,2020 Cerebras Systems * Copyright 2021 Sven Verdoolaege + * Copyright 2022 Cerebras Systems * * Use of this software is governed by the MIT license * @@ -16,6 +17,7 @@ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, * B.P. 105 - 78153 Le Chesnay, France * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA + * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA */ #include @@ -63,8 +65,12 @@ #include -__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls, - __isl_take isl_vec *v) +/* Construct an isl_aff from the given domain local space "ls" and + * coefficients "v", where the local space is known to be valid + * for an affine expression. + */ +static __isl_give isl_aff *isl_aff_alloc_vec_validated( + __isl_take isl_local_space *ls, __isl_take isl_vec *v) { isl_aff *aff; @@ -86,11 +92,16 @@ error: return NULL; } -__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls) +/* Construct an isl_aff from the given domain local space "ls" and + * coefficients "v". + * + * First check that "ls" is a valid domain local space + * for an affine expression. + */ +__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls, + __isl_take isl_vec *v) { isl_ctx *ctx; - isl_vec *v; - isl_size total; if (!ls) return NULL; @@ -103,6 +114,23 @@ __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls) isl_die(ctx, isl_error_invalid, "domain of affine expression should be a set", goto error); + return isl_aff_alloc_vec_validated(ls, v); +error: + isl_local_space_free(ls); + isl_vec_free(v); + return NULL; +} + +__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls) +{ + isl_ctx *ctx; + isl_vec *v; + isl_size total; + + if (!ls) + return NULL; + + ctx = isl_local_space_get_ctx(ls); total = isl_local_space_dim(ls, isl_dim_all); if (total < 0) @@ -128,8 +156,8 @@ __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff) if (!aff) return NULL; - return isl_aff_alloc_vec(isl_local_space_copy(aff->ls), - isl_vec_copy(aff->v)); + return isl_aff_alloc_vec_validated(isl_local_space_copy(aff->ls), + isl_vec_copy(aff->v)); } __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff) @@ -236,6 +264,10 @@ __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls) /* Return an affine expression that is equal to "val" on * domain local space "ls". + * + * Note that the encoding for the special value NaN + * is the same in isl_val and isl_aff, so this does not need + * to be treated in any special way. */ __isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, __isl_take isl_val *val) @@ -244,9 +276,9 @@ __isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, if (!ls || !val) goto error; - if (!isl_val_is_rat(val)) + if (!isl_val_is_rat(val) && !isl_val_is_nan(val)) isl_die(isl_val_get_ctx(val), isl_error_invalid, - "expecting rational value", goto error); + "expecting rational value or NaN", goto error); aff = isl_aff_alloc(isl_local_space_copy(ls)); if (!aff) @@ -592,43 +624,6 @@ __isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff, return isl_aff_reset_domain_space(aff, domain); } -/* Reorder the coefficients of the affine expression based - * on the given reordering. - * The reordering r is assumed to have been extended with the local - * variables. - */ -static __isl_give isl_vec *vec_reorder(__isl_take isl_vec *vec, - __isl_take isl_reordering *r, int n_div) -{ - isl_space *space; - isl_vec *res; - isl_size dim; - int i; - - if (!vec || !r) - goto error; - - space = isl_reordering_peek_space(r); - dim = isl_space_dim(space, isl_dim_all); - if (dim < 0) - goto error; - res = isl_vec_alloc(vec->ctx, 2 + dim + n_div); - if (!res) - goto error; - isl_seq_cpy(res->el, vec->el, 2); - isl_seq_clr(res->el + 2, res->size - 2); - for (i = 0; i < r->len; ++i) - isl_int_set(res->el[2 + r->pos[i]], vec->el[2 + i]); - - isl_reordering_free(r); - isl_vec_free(vec); - return res; -error: - isl_vec_free(vec); - isl_reordering_free(r); - return NULL; -} - /* Reorder the dimensions of the domain of "aff" according * to the given reordering. */ @@ -640,8 +635,7 @@ __isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff, goto error; r = isl_reordering_extend(r, aff->ls->div->n_row); - aff->v = vec_reorder(aff->v, isl_reordering_copy(r), - aff->ls->div->n_row); + aff->v = isl_vec_reorder(aff->v, 2, isl_reordering_copy(r)); aff->ls = isl_local_space_realign(aff->ls, r); if (!aff->v || !aff->ls) @@ -657,20 +651,17 @@ error: __isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, __isl_take isl_space *model) { + isl_space *domain_space; isl_bool equal_params; - if (!aff || !model) - goto error; - - equal_params = isl_space_has_equal_params(aff->ls->dim, model); + domain_space = isl_aff_peek_domain_space(aff); + equal_params = isl_space_has_equal_params(domain_space, model); if (equal_params < 0) goto error; if (!equal_params) { isl_reordering *exp; - exp = isl_parameter_alignment_reordering(aff->ls->dim, model); - exp = isl_reordering_extend_space(exp, - isl_aff_get_domain_space(aff)); + exp = isl_parameter_alignment_reordering(domain_space, model); aff = isl_aff_realign_domain(aff, exp); } @@ -2590,12 +2581,10 @@ isl_bool isl_aff_involves_locals(__isl_keep isl_aff *aff) __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, enum isl_dim_type type, unsigned first, unsigned n) { - isl_ctx *ctx; - if (!aff) return NULL; if (type == isl_dim_out) - isl_die(aff->v->ctx, isl_error_invalid, + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, "cannot drop output/set dimension", return isl_aff_free(aff)); if (type == isl_dim_in) @@ -2603,7 +2592,6 @@ __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)) return aff; - ctx = isl_aff_get_ctx(aff); if (isl_local_space_check_range(aff->ls, type, first, n) < 0) return isl_aff_free(aff); @@ -2669,12 +2657,10 @@ __isl_give isl_aff *isl_aff_from_range(__isl_take isl_aff *aff) __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, enum isl_dim_type type, unsigned first, unsigned n) { - isl_ctx *ctx; - if (!aff) return NULL; if (type == isl_dim_out) - isl_die(aff->v->ctx, isl_error_invalid, + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, "cannot insert output/set dimensions", return isl_aff_free(aff)); if (type == isl_dim_in) @@ -2682,7 +2668,6 @@ __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)) return aff; - ctx = isl_aff_get_ctx(aff); if (isl_local_space_check_range(aff->ls, type, first, 0) < 0) return isl_aff_free(aff); @@ -2806,15 +2791,20 @@ static __isl_give isl_aff *isl_aff_zero_in_space(__isl_take isl_space *space) #define DEFAULT_IS_ZERO 0 #include +#include #include +#include #include #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -2823,6 +2813,7 @@ static __isl_give isl_aff *isl_aff_zero_in_space(__isl_take isl_space *space) #include #include +#include #undef BASE #define BASE aff @@ -3289,40 +3280,12 @@ __isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff, __isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff) { - int i; - - pwaff = isl_pw_aff_cow(pwaff); - if (!pwaff) - return NULL; - if (pwaff->n == 0) - return pwaff; - - for (i = 0; i < pwaff->n; ++i) { - pwaff->p[i].aff = isl_aff_floor(pwaff->p[i].aff); - if (!pwaff->p[i].aff) - return isl_pw_aff_free(pwaff); - } - - return pwaff; + return isl_pw_aff_un_op(pwaff, &isl_aff_floor); } __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff) { - int i; - - pwaff = isl_pw_aff_cow(pwaff); - if (!pwaff) - return NULL; - if (pwaff->n == 0) - return pwaff; - - for (i = 0; i < pwaff->n; ++i) { - pwaff->p[i].aff = isl_aff_ceil(pwaff->p[i].aff); - if (!pwaff->p[i].aff) - return isl_pw_aff_free(pwaff); - } - - return pwaff; + return isl_pw_aff_un_op(pwaff, &isl_aff_ceil); } /* Assuming that "cond1" and "cond2" are disjoint, @@ -3531,12 +3494,6 @@ __isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add); } -__isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1, - __isl_take isl_pw_aff *pwaff2) -{ - return isl_pw_aff_union_add_(pwaff1, pwaff2); -} - __isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2) { @@ -3634,7 +3591,7 @@ error: return NULL; } -/* Does either of "pa1" or "pa2" involve any NaN2? +/* Does either of "pa1" or "pa2" involve any NaN? */ static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, __isl_keep isl_pw_aff *pa2) @@ -3647,6 +3604,21 @@ static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, return isl_pw_aff_involves_nan(pa2); } +/* Return a piecewise affine expression defined on the specified domain + * that represents NaN. + */ +static __isl_give isl_pw_aff *nan_on_domain_set(__isl_take isl_set *dom) +{ + isl_local_space *ls; + isl_pw_aff *pa; + + ls = isl_local_space_from_space(isl_set_get_space(dom)); + pa = isl_pw_aff_nan_on_domain(ls); + pa = isl_pw_aff_intersect_domain(pa, dom); + + return pa; +} + /* Replace "pa1" and "pa2" (at least one of which involves a NaN) * by a NaN on their shared domain. * @@ -3656,16 +3628,10 @@ static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2) { - isl_local_space *ls; isl_set *dom; - isl_pw_aff *pa; dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2)); - ls = isl_local_space_from_space(isl_set_get_space(dom)); - pa = isl_pw_aff_nan_on_domain(ls); - pa = isl_pw_aff_intersect_domain(pa, dom); - - return pa; + return nan_on_domain_set(dom); } static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1, @@ -3735,26 +3701,133 @@ __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, return pw_aff_min_max(pwaff1, pwaff2, 1); } -static __isl_give isl_pw_aff *pw_aff_list_reduce( - __isl_take isl_pw_aff_list *list, - __isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pwaff1, - __isl_take isl_pw_aff *pwaff2)) +/* Does "pa" not involve any NaN? + */ +static isl_bool pw_aff_no_nan(__isl_keep isl_pw_aff *pa, void *user) +{ + return isl_bool_not(isl_pw_aff_involves_nan(pa)); +} + +/* Does any element of "list" involve any NaN? + * + * That is, is it not the case that every element does not involve any NaN? + */ +static isl_bool isl_pw_aff_list_involves_nan(__isl_keep isl_pw_aff_list *list) +{ + return isl_bool_not(isl_pw_aff_list_every(list, &pw_aff_no_nan, NULL)); +} + +/* Replace "list" (consisting of "n" elements, of which + * at least one element involves a NaN) + * by a NaN on the shared domain of the elements. + * + * In principle, the result could be refined to only being NaN + * on the parts of this domain where at least one of the elements is NaN. + */ +static __isl_give isl_pw_aff *replace_list_by_nan( + __isl_take isl_pw_aff_list *list, int n) { int i; - isl_ctx *ctx; - isl_pw_aff *res; + isl_set *dom; - if (!list) - return NULL; + dom = isl_pw_aff_domain(isl_pw_aff_list_get_at(list, 0)); + for (i = 1; i < n; ++i) { + isl_set *dom_i; - ctx = isl_pw_aff_list_get_ctx(list); - if (list->n < 1) - isl_die(ctx, isl_error_invalid, + dom_i = isl_pw_aff_domain(isl_pw_aff_list_get_at(list, i)); + dom = isl_set_intersect(dom, dom_i); + } + + isl_pw_aff_list_free(list); + return nan_on_domain_set(dom); +} + +/* Return the set where the element at "pos1" of "list" is less than or + * equal to the element at "pos2". + * Equality is only allowed if "pos1" is smaller than "pos2". + */ +static __isl_give isl_set *less(__isl_keep isl_pw_aff_list *list, + int pos1, int pos2) +{ + isl_pw_aff *pa1, *pa2; + + pa1 = isl_pw_aff_list_get_at(list, pos1); + pa2 = isl_pw_aff_list_get_at(list, pos2); + + if (pos1 < pos2) + return isl_pw_aff_le_set(pa1, pa2); + else + return isl_pw_aff_lt_set(pa1, pa2); +} + +/* Return an isl_pw_aff that maps each element in the intersection of the + * domains of the piecewise affine expressions in "list" + * to the maximal (if "max" is set) or minimal (if "max" is not set) + * expression in "list" at that element. + * If any expression involves any NaN, then return a NaN + * on the shared domain as result. + * + * If "list" has n elements, then the result consists of n pieces, + * where, in the case of a minimum, each piece has as value expression + * the value expression of one of the elements and as domain + * the set of elements where that value expression + * is less than (or equal) to the other value expressions. + * In the case of a maximum, the condition is + * that all the other value expressions are less than (or equal) + * to the given value expression. + * + * In order to produce disjoint pieces, a pair of elements + * in the original domain is only allowed to be equal to each other + * on exactly one of the two pieces corresponding to the two elements. + * The position in the list is used to break ties. + * In particular, in the case of a minimum, + * in the piece corresponding to a given element, + * this element is allowed to be equal to any later element in the list, + * but not to any earlier element in the list. + */ +static __isl_give isl_pw_aff *isl_pw_aff_list_opt( + __isl_take isl_pw_aff_list *list, int max) +{ + int i, j; + isl_bool has_nan; + isl_size n; + isl_space *space; + isl_pw_aff *pa, *res; + + n = isl_pw_aff_list_size(list); + if (n < 0) + goto error; + if (n < 1) + isl_die(isl_pw_aff_list_get_ctx(list), isl_error_invalid, "list should contain at least one element", goto error); - res = isl_pw_aff_copy(list->p[0]); - for (i = 1; i < list->n; ++i) - res = fn(res, isl_pw_aff_copy(list->p[i])); + has_nan = isl_pw_aff_list_involves_nan(list); + if (has_nan < 0) + goto error; + if (has_nan) + return replace_list_by_nan(list, n); + + pa = isl_pw_aff_list_get_at(list, 0); + space = isl_pw_aff_get_space(pa); + isl_pw_aff_free(pa); + res = isl_pw_aff_empty(space); + + for (i = 0; i < n; ++i) { + pa = isl_pw_aff_list_get_at(list, i); + for (j = 0; j < n; ++j) { + isl_set *dom; + + if (j == i) + continue; + if (max) + dom = less(list, j, i); + else + dom = less(list, i, j); + + pa = isl_pw_aff_intersect_domain(pa, dom); + } + res = isl_pw_aff_add_disjoint(res, pa); + } isl_pw_aff_list_free(list); return res; @@ -3769,7 +3842,7 @@ error: */ __isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list) { - return pw_aff_list_reduce(list, &isl_pw_aff_min); + return isl_pw_aff_list_opt(list, 0); } /* Return an isl_pw_aff that maps each element in the intersection of the @@ -3778,7 +3851,7 @@ __isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list) */ __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list) { - return pw_aff_list_reduce(list, &isl_pw_aff_max); + return isl_pw_aff_list_opt(list, 1); } /* Mark the domains of "pwaff" as rational. @@ -3900,6 +3973,8 @@ static __isl_give isl_basic_set *isl_multi_aff_domain( #include #include +#include +#include #include #include #include @@ -3975,7 +4050,7 @@ __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( isl_int_set(v->el[0], mat->row[0][0]); isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col); v = isl_vec_normalize(v); - aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v); + aff = isl_aff_alloc_vec_validated(isl_local_space_copy(ls), v); ma = isl_multi_aff_set_aff(ma, i, aff); } @@ -4302,17 +4377,20 @@ __isl_give isl_pw_multi_aff *isl_space_identity_pw_multi_aff_on_domain( static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities( __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq) { + isl_size n; int i; - maff = isl_multi_aff_cow(maff); - if (!maff || !eq) + n = isl_multi_aff_size(maff); + if (n < 0 || !eq) goto error; - for (i = 0; i < maff->n; ++i) { - maff->u.p[i] = isl_aff_substitute_equalities(maff->u.p[i], + for (i = 0; i < n; ++i) { + isl_aff *aff; + + aff = isl_multi_aff_take_at(maff, i); + aff = isl_aff_substitute_equalities(aff, isl_basic_set_copy(eq)); - if (!maff->u.p[i]) - goto error; + maff = isl_multi_aff_restore_at(maff, i, aff); } isl_basic_set_free(eq); @@ -4326,16 +4404,19 @@ error: __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff, isl_int f) { + isl_size n; int i; - maff = isl_multi_aff_cow(maff); - if (!maff) - return NULL; + n = isl_multi_aff_size(maff); + if (n < 0) + return isl_multi_aff_free(maff); - for (i = 0; i < maff->n; ++i) { - maff->u.p[i] = isl_aff_scale(maff->u.p[i], f); - if (!maff->u.p[i]) - return isl_multi_aff_free(maff); + for (i = 0; i < n; ++i) { + isl_aff *aff; + + aff = isl_multi_aff_take_at(maff, i); + aff = isl_aff_scale(aff, f); + maff = isl_multi_aff_restore_at(maff, i, aff); } return maff; @@ -4513,9 +4594,13 @@ __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, #define DEFAULT_IS_ZERO 0 #include +#include #include #include +#include #include +#include +#include #include #include #include @@ -4531,6 +4616,7 @@ __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, #include #include "isl_union_locals_templ.c" #include +#include #undef BASE #define BASE multi_aff @@ -4663,33 +4749,6 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( &isl_multi_aff_sub); } -__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( - __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) -{ - return isl_pw_multi_aff_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. - */ -__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) -{ - return isl_union_pw_multi_aff_union_add_(upma1, upma2); -} - /* Given two piecewise multi-affine expressions A -> B and C -> D, * construct a piecewise multi-affine expression [A -> C] -> [B -> D]. */ @@ -5103,7 +5162,7 @@ static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div( isl_basic_map_free(hull); ls = isl_local_space_from_space(isl_space_copy(space)); - aff = isl_aff_alloc_vec(ls, v); + aff = isl_aff_alloc_vec_validated(ls, v); aff = isl_aff_floor(aff); if (is_set) { isl_space_free(space); @@ -5710,20 +5769,22 @@ __isl_give isl_multi_aff *isl_multi_aff_substitute( __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) { + isl_size n; int i; - maff = isl_multi_aff_cow(maff); - if (!maff || !subs) + n = isl_multi_aff_size(maff); + if (n < 0 || !subs) return isl_multi_aff_free(maff); if (type == isl_dim_in) type = isl_dim_set; - for (i = 0; i < maff->n; ++i) { - maff->u.p[i] = isl_aff_substitute(maff->u.p[i], - type, pos, subs); - if (!maff->u.p[i]) - return isl_multi_aff_free(maff); + for (i = 0; i < n; ++i) { + isl_aff *aff; + + aff = isl_multi_aff_take_at(maff, i); + aff = isl_aff_substitute(aff, type, pos, subs); + maff = isl_multi_aff_restore_at(maff, i, aff); } return maff; @@ -5988,22 +6049,24 @@ __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff( __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2) { int i; + isl_size n; isl_space *space = NULL; isl_multi_aff_align_params_bin(&ma1, &ma2); ma2 = isl_multi_aff_align_divs(ma2); - ma1 = isl_multi_aff_cow(ma1); - if (!ma1 || !ma2) + n = isl_multi_aff_size(ma1); + if (n < 0 || !ma2) goto error; space = isl_space_join(isl_multi_aff_get_space(ma2), isl_multi_aff_get_space(ma1)); - for (i = 0; i < ma1->n; ++i) { - ma1->u.p[i] = isl_aff_pullback_multi_aff(ma1->u.p[i], - isl_multi_aff_copy(ma2)); - if (!ma1->u.p[i]) - goto error; + for (i = 0; i < n; ++i) { + isl_aff *aff; + + aff = isl_multi_aff_take_at(ma1, i); + aff = isl_aff_pullback_multi_aff(aff, isl_multi_aff_copy(ma2)); + ma1 = isl_multi_aff_restore_at(ma1, i, aff); } ma1 = isl_multi_aff_reset_space(ma1, space); @@ -6076,22 +6139,32 @@ error: __isl_give isl_multi_aff *isl_multi_aff_align_divs( __isl_take isl_multi_aff *maff) { + isl_aff *aff_0; + isl_size n; int i; - if (!maff) - return NULL; - if (maff->n == 0) + n = isl_multi_aff_size(maff); + if (n < 0) + return isl_multi_aff_free(maff); + if (n <= 1) return maff; - maff = isl_multi_aff_cow(maff); - if (!maff) - return NULL; - for (i = 1; i < maff->n; ++i) - maff->u.p[0] = isl_aff_align_divs(maff->u.p[0], maff->u.p[i]); - for (i = 1; i < maff->n; ++i) { - maff->u.p[i] = isl_aff_align_divs(maff->u.p[i], maff->u.p[0]); - if (!maff->u.p[i]) - return isl_multi_aff_free(maff); + aff_0 = isl_multi_aff_take_at(maff, 0); + for (i = 1; i < n; ++i) { + isl_aff *aff_i; + + aff_i = isl_multi_aff_peek_at(maff, i); + aff_0 = isl_aff_align_divs(aff_0, aff_i); + } + maff = isl_multi_aff_restore_at(maff, 0, aff_0); + + aff_0 = isl_multi_aff_peek_at(maff, 0); + for (i = 1; i < n; ++i) { + isl_aff *aff_i; + + aff_i = isl_multi_aff_take_at(maff, i); + aff_i = isl_aff_align_divs(aff_i, aff_0); + maff = isl_multi_aff_restore_at(maff, i, aff_i); } return maff; @@ -6120,15 +6193,17 @@ __isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff, { int i; isl_space *space; - isl_size n_div; + isl_aff *aff; + isl_size n, n_div; if (ls) *ls = NULL; - if (!maff) - return NULL; + n = isl_multi_aff_size(maff); + if (n < 0) + return isl_multi_aff_free(maff); - if (maff->n == 0) { + if (n == 0) { if (ls) { isl_space *space = isl_multi_aff_get_domain_space(maff); *ls = isl_local_space_from_space(space); @@ -6138,40 +6213,32 @@ __isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff, return maff; } - maff = isl_multi_aff_cow(maff); maff = isl_multi_aff_align_divs(maff); - if (!maff) - return NULL; - n_div = isl_aff_dim(maff->u.p[0], isl_dim_div); + aff = isl_multi_aff_peek_at(maff, 0); + n_div = isl_aff_dim(aff, isl_dim_div); if (n_div < 0) return isl_multi_aff_free(maff); space = isl_multi_aff_get_space(maff); space = isl_space_lift(isl_space_domain(space), n_div); space = isl_space_extend_domain_with_range(space, isl_multi_aff_get_space(maff)); - if (!space) - return isl_multi_aff_free(maff); - isl_space_free(maff->space); - maff->space = space; + maff = isl_multi_aff_restore_space(maff, space); if (ls) { - *ls = isl_aff_get_domain_local_space(maff->u.p[0]); + aff = isl_multi_aff_peek_at(maff, 0); + *ls = isl_aff_get_domain_local_space(aff); if (!*ls) return isl_multi_aff_free(maff); } - for (i = 0; i < maff->n; ++i) { - maff->u.p[i] = isl_aff_lift(maff->u.p[i]); - if (!maff->u.p[i]) - goto error; + for (i = 0; i < n; ++i) { + aff = isl_multi_aff_take_at(maff, i); + aff = isl_aff_lift(aff); + maff = isl_multi_aff_restore_at(maff, i, aff); } return maff; -error: - if (ls) - isl_local_space_free(*ls); - return isl_multi_aff_free(maff); } #undef TYPE @@ -6586,6 +6653,8 @@ error: #include #include #include +#include +#include #include #include #include @@ -6727,38 +6796,33 @@ __isl_give isl_multi_pw_aff *isl_map_max_multi_pw_aff(__isl_take isl_map *map) return map_opt_mpa(map, &isl_map_dim_max); } -/* Scale the elements of "pma" by the corresponding elements of "mv". +#undef TYPE +#define TYPE isl_pw_multi_aff +#include "isl_type_check_match_range_multi_val.c" + +/* Apply "fn" to the base expressions of "pma" and "mv". */ -__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( - __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) +static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_op_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv, + __isl_give isl_multi_aff *(*fn)(__isl_take isl_multi_aff *ma, + __isl_take isl_multi_val *mv)) { int i; - isl_bool equal_params; + isl_size n; - pma = isl_pw_multi_aff_cow(pma); - if (!pma || !mv) + if (isl_pw_multi_aff_check_match_range_multi_val(pma, mv) < 0) goto error; - if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out, - mv->space, isl_dim_set)) - isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, - "spaces don't match", goto error); - equal_params = isl_space_has_equal_params(pma->dim, mv->space); - if (equal_params < 0) + + n = isl_pw_multi_aff_n_piece(pma); + if (n < 0) goto error; - if (!equal_params) { - pma = isl_pw_multi_aff_align_params(pma, - isl_multi_val_get_space(mv)); - mv = isl_multi_val_align_params(mv, - isl_pw_multi_aff_get_space(pma)); - if (!pma || !mv) - goto error; - } - for (i = 0; i < pma->n; ++i) { - pma->p[i].maff = isl_multi_aff_scale_multi_val(pma->p[i].maff, - isl_multi_val_copy(mv)); - if (!pma->p[i].maff) - goto error; + for (i = 0; i < n; ++i) { + isl_multi_aff *ma; + + ma = isl_pw_multi_aff_take_base_at(pma, i); + ma = fn(ma, isl_multi_val_copy(mv)); + pma = isl_pw_multi_aff_restore_base_at(pma, i, ma); } isl_multi_val_free(mv); @@ -6769,6 +6833,24 @@ error: return NULL; } +/* Scale the elements of "pma" by the corresponding elements of "mv". + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) +{ + return isl_pw_multi_aff_op_multi_val(pma, mv, + &isl_multi_aff_scale_multi_val); +} + +/* Scale the elements of "pma" down by the corresponding elements of "mv". + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_multi_val( + __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) +{ + return isl_pw_multi_aff_op_multi_val(pma, mv, + &isl_multi_aff_scale_down_multi_val); +} + /* This function is called for each entry of an isl_union_pw_multi_aff. * If the space of the entry matches that of data->mv, * then apply isl_pw_multi_aff_scale_multi_val and return the result. @@ -6777,12 +6859,13 @@ error: static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry( __isl_take isl_pw_multi_aff *pma, void *user) { + isl_bool equal; isl_multi_val *mv = user; - if (!pma) - return NULL; - if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out, - mv->space, isl_dim_set)) { + equal = isl_pw_multi_aff_match_range_multi_val(pma, mv); + if (equal < 0) + return isl_pw_multi_aff_free(pma); + if (!equal) { isl_space *space = isl_pw_multi_aff_get_space(pma); isl_pw_multi_aff_free(pma); return isl_pw_multi_aff_empty(space); @@ -7132,148 +7215,15 @@ isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1, return equal; } -/* Compute the pullback of "mpa" by the function represented by "ma". - * In other words, plug in "ma" in "mpa". - * - * The parameters of "mpa" and "ma" are assumed to have been aligned. - * - * If "mpa" has an explicit domain, then it is this domain - * that needs to undergo a pullback, i.e., a preimage. - */ -static __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff_aligned( - __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma) -{ - int i; - isl_space *space = NULL; - - mpa = isl_multi_pw_aff_cow(mpa); - if (!mpa || !ma) - goto error; - - space = isl_space_join(isl_multi_aff_get_space(ma), - isl_multi_pw_aff_get_space(mpa)); - if (!space) - goto error; - - for (i = 0; i < mpa->n; ++i) { - mpa->u.p[i] = isl_pw_aff_pullback_multi_aff(mpa->u.p[i], - isl_multi_aff_copy(ma)); - if (!mpa->u.p[i]) - goto error; - } - if (isl_multi_pw_aff_has_explicit_domain(mpa)) { - mpa->u.dom = isl_set_preimage_multi_aff(mpa->u.dom, - isl_multi_aff_copy(ma)); - if (!mpa->u.dom) - goto error; - } - - isl_multi_aff_free(ma); - isl_space_free(mpa->space); - mpa->space = space; - return mpa; -error: - isl_space_free(space); - isl_multi_pw_aff_free(mpa); - isl_multi_aff_free(ma); - return NULL; -} - -/* Compute the pullback of "mpa" by the function represented by "ma". - * In other words, plug in "ma" in "mpa". - */ -__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff( - __isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma) -{ - isl_bool equal_params; - - if (!mpa || !ma) - goto error; - equal_params = isl_space_has_equal_params(mpa->space, ma->space); - if (equal_params < 0) - goto error; - if (equal_params) - return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma); - mpa = isl_multi_pw_aff_align_params(mpa, isl_multi_aff_get_space(ma)); - ma = isl_multi_aff_align_params(ma, isl_multi_pw_aff_get_space(mpa)); - return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma); -error: - isl_multi_pw_aff_free(mpa); - isl_multi_aff_free(ma); - return NULL; -} - -/* Compute the pullback of "mpa" by the function represented by "pma". - * In other words, plug in "pma" in "mpa". - * - * The parameters of "mpa" and "mpa" are assumed to have been aligned. - * - * If "mpa" has an explicit domain, then it is this domain - * that needs to undergo a pullback, i.e., a preimage. - */ -static __isl_give isl_multi_pw_aff * -isl_multi_pw_aff_pullback_pw_multi_aff_aligned( - __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma) -{ - int i; - isl_space *space = NULL; - - mpa = isl_multi_pw_aff_cow(mpa); - if (!mpa || !pma) - goto error; +#undef BASE +#define BASE multi_aff - space = isl_space_join(isl_pw_multi_aff_get_space(pma), - isl_multi_pw_aff_get_space(mpa)); +#include "isl_multi_pw_aff_pullback_templ.c" - for (i = 0; i < mpa->n; ++i) { - mpa->u.p[i] = isl_pw_aff_pullback_pw_multi_aff_aligned( - mpa->u.p[i], isl_pw_multi_aff_copy(pma)); - if (!mpa->u.p[i]) - goto error; - } - if (isl_multi_pw_aff_has_explicit_domain(mpa)) { - mpa->u.dom = isl_set_preimage_pw_multi_aff(mpa->u.dom, - isl_pw_multi_aff_copy(pma)); - if (!mpa->u.dom) - goto error; - } - - isl_pw_multi_aff_free(pma); - isl_space_free(mpa->space); - mpa->space = space; - return mpa; -error: - isl_space_free(space); - isl_multi_pw_aff_free(mpa); - isl_pw_multi_aff_free(pma); - return NULL; -} - -/* Compute the pullback of "mpa" by the function represented by "pma". - * In other words, plug in "pma" in "mpa". - */ -__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff( - __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma) -{ - isl_bool equal_params; +#undef BASE +#define BASE pw_multi_aff - if (!mpa || !pma) - goto error; - equal_params = isl_space_has_equal_params(mpa->space, pma->dim); - if (equal_params < 0) - goto error; - if (equal_params) - return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma); - mpa = isl_multi_pw_aff_align_params(mpa, - isl_pw_multi_aff_get_space(pma)); - pma = isl_pw_multi_aff_align_params(pma, - isl_multi_pw_aff_get_space(mpa)); - return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma); -error: - isl_multi_pw_aff_free(mpa); - isl_pw_multi_aff_free(pma); - return NULL; -} +#include "isl_multi_pw_aff_pullback_templ.c" /* Apply "aff" to "mpa". The range of "mpa" needs to be compatible * with the domain of "aff". The domain of the result is the same @@ -7447,18 +7397,6 @@ error: /* Compute the pullback of "pa" by the function represented by "mpa". * In other words, plug in "mpa" in "pa". - * "pa" and "mpa" are assumed to have been aligned. - * - * The pullback is computed by applying "pa" to "mpa". - */ -static __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff_aligned( - __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa) -{ - return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); -} - -/* Compute the pullback of "pa" by the function represented by "mpa". - * In other words, plug in "mpa" in "pa". * * The pullback is computed by applying "pa" to "mpa". */ @@ -7468,51 +7406,10 @@ __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff( return isl_multi_pw_aff_apply_pw_aff(mpa, pa); } -/* Compute the pullback of "mpa1" by the function represented by "mpa2". - * In other words, plug in "mpa2" in "mpa1". - * - * We pullback each member of "mpa1" in turn. - * - * If "mpa1" has an explicit domain, then it is this domain - * that needs to undergo a pullback instead, i.e., a preimage. - */ -__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff( - __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2) -{ - int i; - isl_space *space = NULL; - - isl_multi_pw_aff_align_params_bin(&mpa1, &mpa2); - mpa1 = isl_multi_pw_aff_cow(mpa1); - if (!mpa1 || !mpa2) - goto error; - - space = isl_space_join(isl_multi_pw_aff_get_space(mpa2), - isl_multi_pw_aff_get_space(mpa1)); - - for (i = 0; i < mpa1->n; ++i) { - mpa1->u.p[i] = isl_pw_aff_pullback_multi_pw_aff_aligned( - mpa1->u.p[i], isl_multi_pw_aff_copy(mpa2)); - if (!mpa1->u.p[i]) - goto error; - } - - if (isl_multi_pw_aff_has_explicit_domain(mpa1)) { - mpa1->u.dom = isl_set_preimage_multi_pw_aff(mpa1->u.dom, - isl_multi_pw_aff_copy(mpa2)); - if (!mpa1->u.dom) - goto error; - } - mpa1 = isl_multi_pw_aff_reset_space(mpa1, space); +#undef BASE +#define BASE multi_pw_aff - isl_multi_pw_aff_free(mpa2); - return mpa1; -error: - isl_space_free(space); - isl_multi_pw_aff_free(mpa1); - isl_multi_pw_aff_free(mpa2); - return NULL; -} +#include "isl_multi_pw_aff_pullback_templ.c" /* Align the parameters of "mpa1" and "mpa2", check that the ranges * of "mpa1" and "mpa2" live in the same space, construct map space @@ -7792,6 +7689,15 @@ __isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain, return isl_pw_aff_alloc(domain, aff); } +/* This function performs the same operation as isl_pw_aff_val_on_domain, + * but is considered as a function on an isl_set when exported. + */ +__isl_give isl_pw_aff *isl_set_pw_aff_on_domain_val(__isl_take isl_set *domain, + __isl_take isl_val *v) +{ + return isl_pw_aff_val_on_domain(domain, v); +} + /* Return a piecewise affine expression that is equal to the parameter * with identifier "id" on "domain". */ @@ -7809,6 +7715,16 @@ __isl_give isl_pw_aff *isl_pw_aff_param_on_domain_id( return isl_pw_aff_alloc(domain, aff); } +/* This function performs the same operation as + * isl_pw_aff_param_on_domain_id, + * but is considered as a function on an isl_set when exported. + */ +__isl_give isl_pw_aff *isl_set_param_pw_aff_on_domain_id( + __isl_take isl_set *domain, __isl_take isl_id *id) +{ + return isl_pw_aff_param_on_domain_id(domain, id); +} + /* Return a multi affine expression that is equal to "mv" on domain * space "space". */ @@ -8686,6 +8602,8 @@ error: #include #include #include +#include +#include #include #include #include @@ -8789,6 +8707,10 @@ __isl_give isl_multi_union_pw_aff *isl_multi_aff_to_multi_union_pw_aff( /* Construct and return a multi union piecewise affine expression * that is equal to the given multi piecewise affine expression. + * + * If the resulting multi union piecewise affine expression has + * an explicit domain, then assign it the domain of the input. + * In other cases, the domain is stored in the individual elements. */ __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( __isl_take isl_multi_pw_aff *mpa) @@ -8816,6 +8738,14 @@ __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( upa = isl_union_pw_aff_from_pw_aff(pa); mupa = isl_multi_union_pw_aff_restore_check_space(mupa, i, upa); } + if (isl_multi_union_pw_aff_has_explicit_domain(mupa)) { + isl_union_set *dom; + isl_multi_pw_aff *copy; + + copy = isl_multi_pw_aff_copy(mpa); + dom = isl_union_set_from_set(isl_multi_pw_aff_domain(copy)); + mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom); + } isl_multi_pw_aff_free(mpa); diff --git a/polly/lib/External/isl/isl_aff_map.c b/polly/lib/External/isl/isl_aff_map.c index f661b82..3f46d86 100644 --- a/polly/lib/External/isl/isl_aff_map.c +++ b/polly/lib/External/isl/isl_aff_map.c @@ -427,6 +427,9 @@ __isl_give isl_set *isl_pw_multi_aff_as_set(__isl_take isl_pw_multi_aff *pma) * of the piecewise affine expressions to the range of "mpa" * with each dimension in the range equated to the * corresponding piecewise affine expression. + * + * If "mpa" has an explicit domain (i.e., it is zero-dimensional), + * then return a set or map with the same (parameter) domain. */ static __isl_give isl_map *map_from_multi_pw_aff( __isl_take isl_multi_pw_aff *mpa) @@ -459,6 +462,8 @@ static __isl_give isl_map *map_from_multi_pw_aff( map = isl_map_reset_space(map, isl_multi_pw_aff_get_space(mpa)); + map = isl_map_intersect_multi_pw_aff_explicit_domain(map, mpa); + isl_multi_pw_aff_free(mpa); return map; error: diff --git a/polly/lib/External/isl/isl_aff_private.h b/polly/lib/External/isl/isl_aff_private.h index 473add3..eb814ea 100644 --- a/polly/lib/External/isl/isl_aff_private.h +++ b/polly/lib/External/isl/isl_aff_private.h @@ -113,6 +113,8 @@ __isl_give isl_pw_aff *isl_pw_aff_reset_domain_space( __isl_give isl_pw_aff *isl_pw_aff_add_disjoint( __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); +__isl_keep isl_aff *isl_pw_aff_peek_base_at(__isl_keep isl_pw_aff *pa, int pos); + __isl_give isl_pw_aff *isl_pw_aff_domain_factor_domain( __isl_take isl_pw_aff *pa); @@ -157,6 +159,9 @@ __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( #include +__isl_keep isl_multi_aff *isl_pw_multi_aff_peek_base_at( + __isl_keep isl_pw_multi_aff *pma, int pos); + __isl_give isl_pw_multi_aff *isl_pw_multi_aff_move_dims( __isl_take isl_pw_multi_aff *pma, enum isl_dim_type dst_type, unsigned dst_pos, diff --git a/polly/lib/External/isl/isl_ast.c b/polly/lib/External/isl/isl_ast.c index 6bf5178..c7164c4 100644 --- a/polly/lib/External/isl/isl_ast.c +++ b/polly/lib/External/isl/isl_ast.c @@ -1,15 +1,18 @@ /* * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2022 Cerebras Systems * * 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 Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA */ #include #include +#include #include #include @@ -146,6 +149,49 @@ __isl_give isl_ast_print_options *isl_ast_print_options_set_print_for( return options; } +/* Create a new operation expression of operation type "op", + * with arguments "args". + */ +static __isl_give isl_ast_expr *alloc_op(enum isl_ast_expr_op_type op, + __isl_take isl_ast_expr_list *args) +{ + isl_ctx *ctx; + isl_ast_expr *expr; + + if (!args) + return NULL; + + ctx = isl_ast_expr_list_get_ctx(args); + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + goto error; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_op; + expr->u.op.op = op; + expr->u.op.args = args; + + return expr; +error: + isl_ast_expr_list_free(args); + return NULL; +} + +/* Create a new operation expression of operation type "op", + * which will end up having "n_arg" arguments. + * The caller still needs to add those arguments. + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, + enum isl_ast_expr_op_type op, int n_arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_list_alloc(ctx, n_arg); + return alloc_op(op, args); +} + __isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr) { if (!expr) @@ -157,14 +203,11 @@ __isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr) __isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr) { - int i; - isl_ctx *ctx; isl_ast_expr *dup; if (!expr) return NULL; - ctx = isl_ast_expr_get_ctx(expr); switch (expr->type) { case isl_ast_expr_int: dup = isl_ast_expr_from_val(isl_val_copy(expr->u.v)); @@ -173,13 +216,8 @@ __isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr) dup = isl_ast_expr_from_id(isl_id_copy(expr->u.id)); break; case isl_ast_expr_op: - dup = isl_ast_expr_alloc_op(ctx, - expr->u.op.op, expr->u.op.n_arg); - if (!dup) - return NULL; - for (i = 0; i < expr->u.op.n_arg; ++i) - dup->u.op.args[i] = - isl_ast_expr_copy(expr->u.op.args[i]); + dup = alloc_op(expr->u.op.op, + isl_ast_expr_list_copy(expr->u.op.args)); break; case isl_ast_expr_error: dup = NULL; @@ -204,8 +242,6 @@ __isl_give isl_ast_expr *isl_ast_expr_cow(__isl_take isl_ast_expr *expr) __isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr) { - int i; - if (!expr) return NULL; @@ -222,10 +258,7 @@ __isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr) isl_id_free(expr->u.id); break; case isl_ast_expr_op: - if (expr->u.op.args) - for (i = 0; i < expr->u.op.n_arg; ++i) - isl_ast_expr_free(expr->u.op.args[i]); - free(expr->u.op.args); + isl_ast_expr_list_free(expr->u.op.args); break; case isl_ast_expr_error: break; @@ -282,17 +315,25 @@ __isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr) return isl_ast_expr_id_get_id(expr); } +/* Check that "expr" is of type isl_ast_expr_op. + */ +static isl_stat isl_ast_expr_check_op(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return isl_stat_error; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", return isl_stat_error); + return isl_stat_ok; +} + /* Return the type of operation represented by "expr". */ enum isl_ast_expr_op_type isl_ast_expr_op_get_type( __isl_keep isl_ast_expr *expr) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return isl_ast_expr_op_error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", - return isl_ast_expr_op_error); return expr->u.op.op; } @@ -308,12 +349,9 @@ enum isl_ast_expr_op_type isl_ast_expr_get_op_type( */ isl_size isl_ast_expr_op_get_n_arg(__isl_keep isl_ast_expr *expr) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return isl_size_error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", return isl_size_error); - return expr->u.op.n_arg; + return isl_ast_expr_list_size(expr->u.op.args); } /* This is an alternative name for the function above. @@ -328,16 +366,10 @@ isl_size isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr) __isl_give isl_ast_expr *isl_ast_expr_op_get_arg(__isl_keep isl_ast_expr *expr, int pos) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return NULL; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", return NULL); - if (pos < 0 || pos >= expr->u.op.n_arg) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "index out of bounds", return NULL); - return isl_ast_expr_copy(expr->u.op.args[pos]); + return isl_ast_expr_list_get_at(expr->u.op.args, pos); } /* This is an alternative name for the function above. @@ -348,28 +380,130 @@ __isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr, return isl_ast_expr_op_get_arg(expr, pos); } -/* Replace the argument at position "pos" of "expr" by "arg". +/* Return a copy of the arguments of the operation represented by "expr". */ -__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, - int pos, __isl_take isl_ast_expr *arg) +static __isl_give isl_ast_expr_list *isl_ast_expr_op_get_args( + __isl_keep isl_ast_expr *expr) +{ + if (isl_ast_expr_check_op(expr) < 0) + return NULL; + return isl_ast_expr_list_copy(expr->u.op.args); +} + +/* Return the arguments of the operation expression "expr". + * This may be either a copy or the arguments themselves + * if there is only one reference to "expr". + * This allows the arguments to be modified inplace + * if both "expr" and its arguments have only a single reference. + * The caller is not allowed to modify "expr" between this call and + * the subsequent call to isl_ast_expr_op_restore_args. + * The only exception is that isl_ast_expr_free can be called instead. + */ +static __isl_give isl_ast_expr_list *isl_ast_expr_op_take_args( + __isl_keep isl_ast_expr *expr) +{ + isl_ast_expr_list *args; + + if (isl_ast_expr_check_op(expr) < 0) + return NULL; + if (expr->ref != 1) + return isl_ast_expr_op_get_args(expr); + args = expr->u.op.args; + expr->u.op.args = NULL; + return args; +} + +/* Set the arguments of the operation expression "expr" to "args", + * where the arguments of "args" may be missing + * due to a preceding call to isl_ast_expr_op_take_args. + * However, in this case, "expr" only has a single reference and + * then the call to isl_ast_expr_cow has no effect. + */ +static __isl_give isl_ast_expr *isl_ast_expr_op_restore_args( + __isl_take isl_ast_expr *expr, __isl_take isl_ast_expr_list *args) { + if (isl_ast_expr_check_op(expr) < 0 || !args) + goto error; + if (expr->u.op.args == args) { + isl_ast_expr_list_free(args); + return expr; + } + expr = isl_ast_expr_cow(expr); - if (!expr || !arg) + if (!expr) goto error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", goto error); - if (pos < 0 || pos >= expr->u.op.n_arg) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "index out of bounds", goto error); - isl_ast_expr_free(expr->u.op.args[pos]); - expr->u.op.args[pos] = arg; + isl_ast_expr_list_free(expr->u.op.args); + expr->u.op.args = args; return expr; error: - isl_ast_expr_free(arg); - return isl_ast_expr_free(expr); + isl_ast_expr_free(expr); + isl_ast_expr_list_free(args); + return NULL; +} + +/* Add "arg" to the arguments of the operation expression "expr". + */ +__isl_give isl_ast_expr *isl_ast_expr_op_add_arg(__isl_take isl_ast_expr *expr, + __isl_take isl_ast_expr *arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, arg); + expr = isl_ast_expr_op_restore_args(expr, args); + + return expr; +} + +/* Replace the argument at position "pos" of "expr" by "arg". + */ +__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, + int pos, __isl_take isl_ast_expr *arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_set_at(args, pos, arg); + expr = isl_ast_expr_op_restore_args(expr, args); + + return expr; +} + +/* Are the lists of AST expressions "list1" and "list2" the same? + */ +static isl_bool isl_ast_expr_list_is_equal(__isl_keep isl_ast_expr_list *list1, + __isl_keep isl_ast_expr_list *list2) +{ + int i; + isl_size n1, n2; + + if (!list1 || !list2) + return isl_bool_error; + if (list1 == list2) + return isl_bool_true; + + n1 = isl_ast_expr_list_size(list1); + n2 = isl_ast_expr_list_size(list2); + if (n1 < 0 || n2 < 0) + return isl_bool_error; + if (n1 != n2) + return isl_bool_false; + for (i = 0; i < n1; ++i) { + isl_ast_expr *expr1, *expr2; + isl_bool equal; + + expr1 = isl_ast_expr_list_get_at(list1, i); + expr2 = isl_ast_expr_list_get_at(list2, i); + equal = isl_ast_expr_is_equal(expr1, expr2); + isl_ast_expr_free(expr1); + isl_ast_expr_free(expr2); + if (equal < 0 || !equal) + return equal; + } + + return isl_bool_true; } /* Is "expr1" equal to "expr2"? @@ -377,8 +511,6 @@ error: isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, __isl_keep isl_ast_expr *expr2) { - int i; - if (!expr1 || !expr2) return isl_bool_error; @@ -394,16 +526,8 @@ isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, case isl_ast_expr_op: if (expr1->u.op.op != expr2->u.op.op) return isl_bool_false; - if (expr1->u.op.n_arg != expr2->u.op.n_arg) - return isl_bool_false; - for (i = 0; i < expr1->u.op.n_arg; ++i) { - isl_bool equal; - equal = isl_ast_expr_is_equal(expr1->u.op.args[i], - expr2->u.op.args[i]); - if (equal < 0 || !equal) - return equal; - } - return isl_bool_true; + return isl_ast_expr_list_is_equal(expr1->u.op.args, + expr2->u.op.args); case isl_ast_expr_error: return isl_bool_error; } @@ -412,32 +536,6 @@ isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, "unhandled case", return isl_bool_error); } -/* Create a new operation expression of operation type "op", - * with "n_arg" as yet unspecified arguments. - */ -__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, - enum isl_ast_expr_op_type op, int n_arg) -{ - isl_ast_expr *expr; - - expr = isl_calloc_type(ctx, isl_ast_expr); - if (!expr) - return NULL; - - expr->ctx = ctx; - isl_ctx_ref(ctx); - expr->ref = 1; - expr->type = isl_ast_expr_op; - expr->u.op.op = op; - expr->u.op.n_arg = n_arg; - expr->u.op.args = isl_calloc_array(ctx, isl_ast_expr *, n_arg); - - if (n_arg && !expr->u.op.args) - return isl_ast_expr_free(expr); - - return expr; -} - /* Create a new id expression representing "id". */ __isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id) @@ -524,21 +622,19 @@ __isl_give isl_ast_expr *isl_ast_expr_alloc_unary( { isl_ctx *ctx; isl_ast_expr *expr = NULL; + isl_ast_expr_list *args; if (!arg) return NULL; ctx = isl_ast_expr_get_ctx(arg); expr = isl_ast_expr_alloc_op(ctx, type, 1); - if (!expr) - goto error; - expr->u.op.args[0] = arg; + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, arg); + expr = isl_ast_expr_op_restore_args(expr, args); return expr; -error: - isl_ast_expr_free(arg); - return NULL; } /* Create an expression representing the negation of "arg". @@ -573,17 +669,18 @@ __isl_give isl_ast_expr *isl_ast_expr_alloc_binary( { isl_ctx *ctx; isl_ast_expr *expr = NULL; + isl_ast_expr_list *args; if (!expr1 || !expr2) goto error; ctx = isl_ast_expr_get_ctx(expr1); expr = isl_ast_expr_alloc_op(ctx, type, 2); - if (!expr) - goto error; - expr->u.op.args[0] = expr1; - expr->u.op.args[1] = expr2; + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, expr1); + args = isl_ast_expr_list_add(args, expr2); + expr = isl_ast_expr_op_restore_args(expr, args); return expr; error: @@ -725,37 +822,8 @@ static __isl_give isl_ast_expr *ast_expr_with_arguments( enum isl_ast_expr_op_type type, __isl_take isl_ast_expr *arg0, __isl_take isl_ast_expr_list *arguments) { - int i; - isl_size n; - isl_ctx *ctx; - isl_ast_expr *res = NULL; - - if (!arg0 || !arguments) - goto error; - - ctx = isl_ast_expr_get_ctx(arg0); - n = isl_ast_expr_list_n_ast_expr(arguments); - if (n < 0) - goto error; - res = isl_ast_expr_alloc_op(ctx, type, 1 + n); - if (!res) - goto error; - for (i = 0; i < n; ++i) { - isl_ast_expr *arg; - arg = isl_ast_expr_list_get_ast_expr(arguments, i); - res->u.op.args[1 + i] = arg; - if (!arg) - goto error; - } - res->u.op.args[0] = arg0; - - isl_ast_expr_list_free(arguments); - return res; -error: - isl_ast_expr_free(arg0); - isl_ast_expr_list_free(arguments); - isl_ast_expr_free(res); - return NULL; + arguments = isl_ast_expr_list_insert(arguments, 0, arg0); + return alloc_op(type, arguments); } /* Create an expression representing an access to "array" with index @@ -776,6 +844,18 @@ __isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, return ast_expr_with_arguments(isl_ast_expr_op_call, function, arguments); } +/* Wrapper around isl_ast_expr_substitute_ids for use + * as an isl_ast_expr_list_map callback. + */ +static __isl_give isl_ast_expr *substitute_ids(__isl_take isl_ast_expr *expr, + void *user) +{ + isl_id_to_ast_expr *id2expr = user; + + return isl_ast_expr_substitute_ids(expr, + isl_id_to_ast_expr_copy(id2expr)); +} + /* For each subexpression of "expr" of type isl_ast_expr_id, * if it appears in "id2expr", then replace it by the corresponding * expression. @@ -783,8 +863,8 @@ __isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, __isl_give isl_ast_expr *isl_ast_expr_substitute_ids( __isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr) { - int i; isl_maybe_isl_ast_expr m; + isl_ast_expr_list *args; if (!expr || !id2expr) goto error; @@ -802,25 +882,9 @@ __isl_give isl_ast_expr *isl_ast_expr_substitute_ids( expr = m.value; break; case isl_ast_expr_op: - for (i = 0; i < expr->u.op.n_arg; ++i) { - isl_ast_expr *arg; - arg = isl_ast_expr_copy(expr->u.op.args[i]); - arg = isl_ast_expr_substitute_ids(arg, - isl_id_to_ast_expr_copy(id2expr)); - if (arg == expr->u.op.args[i]) { - isl_ast_expr_free(arg); - continue; - } - if (!arg) - expr = isl_ast_expr_free(expr); - expr = isl_ast_expr_cow(expr); - if (!expr) { - isl_ast_expr_free(arg); - break; - } - isl_ast_expr_free(expr->u.op.args[i]); - expr->u.op.args[i] = arg; - } + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_map(args, &substitute_ids, id2expr); + expr = isl_ast_expr_op_restore_args(expr, args); break; case isl_ast_expr_error: expr = isl_ast_expr_free(expr); @@ -939,7 +1003,8 @@ error: /* Create a user node evaluating "expr". */ -__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr) +__isl_give isl_ast_node *isl_ast_node_user_from_expr( + __isl_take isl_ast_expr *expr) { isl_ctx *ctx; isl_ast_node *node; @@ -960,9 +1025,16 @@ error: return NULL; } +/* This is an alternative name for the function above. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr) +{ + return isl_ast_node_user_from_expr(expr); +} + /* Create a block node with the given children. */ -__isl_give isl_ast_node *isl_ast_node_alloc_block( +__isl_give isl_ast_node *isl_ast_node_block_from_children( __isl_take isl_ast_node_list *list) { isl_ast_node *node; @@ -984,6 +1056,14 @@ error: return NULL; } +/* This is an alternative name for the function above. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_block( + __isl_take isl_ast_node_list *list) +{ + return isl_ast_node_block_from_children(list); +} + /* Represent the given list of nodes as a single node, either by * extract the node from a single element list or by creating * a block node with the list of nodes as children. @@ -1018,6 +1098,11 @@ __isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node) return node; } +/* Return a fresh copy of "node". + * + * In the case of a degenerate for node, take into account + * that "cond" and "inc" are NULL. + */ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) { isl_ast_node *dup; @@ -1039,13 +1124,17 @@ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) return isl_ast_node_free(dup); break; case isl_ast_node_for: + dup->u.f.degenerate = node->u.f.degenerate; dup->u.f.iterator = isl_ast_expr_copy(node->u.f.iterator); dup->u.f.init = isl_ast_expr_copy(node->u.f.init); + dup->u.f.body = isl_ast_node_copy(node->u.f.body); + if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.body) + return isl_ast_node_free(dup); + if (node->u.f.degenerate) + break; dup->u.f.cond = isl_ast_expr_copy(node->u.f.cond); dup->u.f.inc = isl_ast_expr_copy(node->u.f.inc); - dup->u.f.body = isl_ast_node_copy(node->u.f.body); - if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.cond || - !dup->u.f.inc || !dup->u.f.body) + if (!dup->u.f.cond || !dup->u.f.inc) return isl_ast_node_free(dup); break; case isl_ast_node_block: @@ -1068,6 +1157,12 @@ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) break; } + if (!node->annotation) + return dup; + dup->annotation = isl_id_copy(node->annotation); + if (!dup->annotation) + return isl_ast_node_free(dup); + return dup; } @@ -1124,36 +1219,137 @@ __isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node) return NULL; } -/* Replace the body of the for node "node" by "body". +/* Check that "node" is of type "type", printing "msg" if not. */ -__isl_give isl_ast_node *isl_ast_node_for_set_body( - __isl_take isl_ast_node *node, __isl_take isl_ast_node *body) +static isl_stat isl_ast_node_check_type(__isl_keep isl_ast_node *node, + enum isl_ast_node_type type, const char *msg) { - node = isl_ast_node_cow(node); - if (!node || !body) - goto error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", goto error); + if (!node) + return isl_stat_error; + if (node->type != type) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, msg, + return isl_stat_error); + return isl_stat_ok; +} - isl_ast_node_free(node->u.f.body); - node->u.f.body = body; +/* Check that "node" is of type isl_ast_node_block. + */ +static isl_stat isl_ast_node_check_block(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_block, + "not a block node"); +} - return node; -error: - isl_ast_node_free(node); - isl_ast_node_free(body); - return NULL; +/* Check that "node" is of type isl_ast_node_if. + */ +static isl_stat isl_ast_node_check_if(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_if, "not an if node"); +} + +/* Check that "node" is of type isl_ast_node_for. + */ +static isl_stat isl_ast_node_check_for(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_for, + "not a for node"); +} + +/* Check that "node" is of type isl_ast_node_mark. + */ +static isl_stat isl_ast_node_check_mark(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_mark, + "not a mark node"); +} + +/* Check that "node" is of type isl_ast_node_user. + */ +static isl_stat isl_ast_node_check_user(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_user, + "not a user node"); +} + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME init +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.init +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME cond +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.cond +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME inc +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.inc +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME body +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.f.body +#include "isl_ast_node_set_field_templ.c" + +/* Return the body of the for-node "node", + * This may be either a copy or the body itself + * if there is only one reference to "node". + * This allows the body to be modified inplace + * if both "node" and its body have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_for_restore_body. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_for_take_body( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *body; + + if (isl_ast_node_check_for(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_for_get_body(node); + body = node->u.f.body; + node->u.f.body = NULL; + return body; +} + +/* Set the body of the for-node "node" to "body", + * where the body of "node" may be missing + * due to a preceding call to isl_ast_node_for_take_body. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_for_restore_body( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *body) +{ + return isl_ast_node_for_set_body(node, body); } __isl_give isl_ast_node *isl_ast_node_for_get_body( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_node_copy(node->u.f.body); } @@ -1171,33 +1367,24 @@ __isl_give isl_ast_node *isl_ast_node_for_mark_degenerate( isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return isl_bool_error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return isl_bool_error); return isl_bool_ok(node->u.f.degenerate); } __isl_give isl_ast_expr *isl_ast_node_for_get_iterator( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_expr_copy(node->u.f.iterator); } __isl_give isl_ast_expr *isl_ast_node_for_get_init( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_expr_copy(node->u.f.init); } @@ -1211,11 +1398,8 @@ __isl_give isl_ast_expr *isl_ast_node_for_get_init( __isl_give isl_ast_expr *isl_ast_node_for_get_cond( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); if (!node->u.f.degenerate) return isl_ast_expr_copy(node->u.f.cond); @@ -1232,48 +1416,64 @@ __isl_give isl_ast_expr *isl_ast_node_for_get_cond( __isl_give isl_ast_expr *isl_ast_node_for_get_inc( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); if (!node->u.f.degenerate) return isl_ast_expr_copy(node->u.f.inc); return isl_ast_expr_alloc_int_si(isl_ast_node_get_ctx(node), 1); } -/* Replace the then branch of the if node "node" by "child". - */ -__isl_give isl_ast_node *isl_ast_node_if_set_then( - __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +#undef NODE_TYPE +#define NODE_TYPE if +#undef FIELD_NAME +#define FIELD_NAME then +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.i.then +#include "isl_ast_node_set_field_templ.c" + +/* Return the then-branch of the if-node "node", + * This may be either a copy or the branch itself + * if there is only one reference to "node". + * This allows the branch to be modified inplace + * if both "node" and its then-branch have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_if_restore_then_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_if_take_then_node( + __isl_keep isl_ast_node *node) { - node = isl_ast_node_cow(node); - if (!node || !child) - goto error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", goto error); - - isl_ast_node_free(node->u.i.then); - node->u.i.then = child; + isl_ast_node *then_node; - return node; -error: - isl_ast_node_free(node); - isl_ast_node_free(child); - return NULL; + if (isl_ast_node_check_if(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_if_get_then_node(node); + then_node = node->u.i.then; + node->u.i.then = NULL; + return then_node; } -/* Return the then-node of the given if-node. +/* Set the then-branch of the if-node "node" to "child", + * where the then-branch of "node" may be missing + * due to a preceding call to isl_ast_node_if_take_then_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_if_restore_then_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_if_set_then(node, child); +} + +/* Return the then-node of the given if-node. */ __isl_give isl_ast_node *isl_ast_node_if_get_then_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return NULL); return isl_ast_node_copy(node->u.i.then); } @@ -1289,11 +1489,8 @@ __isl_give isl_ast_node *isl_ast_node_if_get_then( */ isl_bool isl_ast_node_if_has_else_node(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return isl_bool_error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return isl_bool_error); return isl_bool_ok(node->u.i.else_node != NULL); } @@ -1310,11 +1507,8 @@ isl_bool isl_ast_node_if_has_else(__isl_keep isl_ast_node *node) __isl_give isl_ast_node *isl_ast_node_if_get_else_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return NULL); return isl_ast_node_copy(node->u.i.else_node); } @@ -1326,36 +1520,117 @@ __isl_give isl_ast_node *isl_ast_node_if_get_else( return isl_ast_node_if_get_else_node(node); } +#undef NODE_TYPE +#define NODE_TYPE if +#undef FIELD_NAME +#define FIELD_NAME else_node +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.i.else_node +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the else-branch of the if-node "node", + * This may be either a copy or the branch itself + * if there is only one reference to "node". + * This allows the branch to be modified inplace + * if both "node" and its else-branch have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_if_restore_else_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_if_take_else_node( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *else_node; + + if (isl_ast_node_check_if(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_if_get_else_node(node); + else_node = node->u.i.else_node; + node->u.i.else_node = NULL; + return else_node; +} + +/* Set the else-branch of the if-node "node" to "child", + * where the else-branch of "node" may be missing + * due to a preceding call to isl_ast_node_if_take_else_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_if_restore_else_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_if_set_else_node(node, child); +} + __isl_give isl_ast_expr *isl_ast_node_if_get_cond( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a guard node", return NULL); return isl_ast_expr_copy(node->u.i.guard); } __isl_give isl_ast_node_list *isl_ast_node_block_get_children( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_block(node) < 0) return NULL; - if (node->type != isl_ast_node_block) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a block node", return NULL); return isl_ast_node_list_copy(node->u.b.children); } +#undef NODE_TYPE +#define NODE_TYPE block +#undef FIELD_NAME +#define FIELD_NAME children +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node_list +#undef FIELD +#define FIELD u.b.children +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the children of the block-node "node", + * This may be either a copy or the children themselves + * if there is only one reference to "node". + * This allows the children to be modified inplace + * if both "node" and its children have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_block_restore_children. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node_list *isl_ast_node_block_take_children( + __isl_keep isl_ast_node *node) +{ + isl_ast_node_list *children; + + if (isl_ast_node_check_block(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_block_get_children(node); + children = node->u.b.children; + node->u.b.children = NULL; + return children; +} + +/* Set the children of the block-node "node" to "children", + * where the children of "node" may be missing + * due to a preceding call to isl_ast_node_block_take_children. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_block_restore_children( + __isl_take isl_ast_node *node, __isl_take isl_ast_node_list *children) +{ + return isl_ast_node_block_set_children(node, children); +} + __isl_give isl_ast_expr *isl_ast_node_user_get_expr( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_user(node) < 0) return NULL; - if (node->type != isl_ast_node_user) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a user node", return NULL); return isl_ast_expr_copy(node->u.e.expr); } @@ -1364,11 +1639,8 @@ __isl_give isl_ast_expr *isl_ast_node_user_get_expr( */ __isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_mark(node) < 0) return NULL; - if (node->type != isl_ast_node_mark) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a mark node", return NULL); return isl_id_copy(node->u.m.mark); } @@ -1378,61 +1650,229 @@ __isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node) __isl_give isl_ast_node *isl_ast_node_mark_get_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_mark(node) < 0) return NULL; - if (node->type != isl_ast_node_mark) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a mark node", return NULL); return isl_ast_node_copy(node->u.m.node); } +#undef NODE_TYPE +#define NODE_TYPE mark +#undef FIELD_NAME +#define FIELD_NAME node +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.m.node +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the child of the mark-node "node", + * This may be either a copy or the child itself + * if there is only one reference to "node". + * This allows the child to be modified inplace + * if both "node" and its child have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_mark_restore_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_mark_take_node( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *child; + + if (isl_ast_node_check_mark(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_mark_get_node(node); + child = node->u.m.node; + node->u.m.node = NULL; + return child; +} + +/* Set the child of the mark-node "node" to "child", + * where the child of "node" may be missing + * due to a preceding call to isl_ast_node_mark_take_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_mark_restore_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_mark_set_node(node, child); +} + __isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node) { return node ? isl_id_copy(node->annotation) : NULL; } +/* Check that "node" is of any type. + * That is, simply check that it is a valid node. + */ +static isl_stat isl_ast_node_check_any(__isl_keep isl_ast_node *node) +{ + return isl_stat_non_null(node); +} + +#undef NODE_TYPE +#define NODE_TYPE any +#undef FIELD_NAME +#define FIELD_NAME annotation +#undef FIELD_TYPE +#define FIELD_TYPE isl_id +#undef FIELD +#define FIELD annotation +static +#include "isl_ast_node_set_field_templ.c" + /* Replace node->annotation by "annotation". */ __isl_give isl_ast_node *isl_ast_node_set_annotation( __isl_take isl_ast_node *node, __isl_take isl_id *annotation) { - node = isl_ast_node_cow(node); - if (!node || !annotation) - goto error; - - isl_id_free(node->annotation); - node->annotation = annotation; - - return node; -error: - isl_id_free(annotation); - return isl_ast_node_free(node); + return isl_ast_node_any_set_annotation(node, annotation); } +static __isl_give isl_ast_node *traverse(__isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user); + /* Traverse the elements of "list" and all their descendants - * in depth first preorder. + * in depth first preorder. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. * - * Return isl_stat_ok on success and isl_stat_error on failure. - */ -static isl_stat nodelist_foreach(__isl_keep isl_ast_node_list *list, - isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) + * Return the updated node. + */ +static __isl_give isl_ast_node_list *traverse_list( + __isl_take isl_ast_node_list *list, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user) { int i; + isl_size n; - if (!list) - return isl_stat_error; + n = isl_ast_node_list_size(list); + if (n < 0) + return isl_ast_node_list_free(list); - for (i = 0; i < list->n; ++i) { - isl_stat ok; - isl_ast_node *node = list->p[i]; + for (i = 0; i < n; ++i) { + isl_ast_node *node; - ok = isl_ast_node_foreach_descendant_top_down(node, fn, user); - if (ok < 0) - return isl_stat_error; + node = isl_ast_node_list_get_at(list, i); + node = traverse(node, enter, leave, user); + list = isl_ast_node_list_set_at(list, i, node); } - return isl_stat_ok; + return list; +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first preorder. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. + * + * If "enter" sets the "more" argument to zero, then the subtree rooted + * at the given node is skipped. + * + * Return the updated node. + */ +static __isl_give isl_ast_node *traverse(__isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user) +{ + int more; + isl_bool has_else; + isl_ast_node *child; + isl_ast_node_list *children; + + node = enter(node, &more, user); + if (!node) + return NULL; + if (!more) + return node; + + switch (node->type) { + case isl_ast_node_for: + child = isl_ast_node_for_take_body(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_for_restore_body(node, child); + return leave(node, user); + case isl_ast_node_if: + child = isl_ast_node_if_take_then_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_if_restore_then_node(node, child); + has_else = isl_ast_node_if_has_else_node(node); + if (has_else < 0) + return isl_ast_node_free(node); + if (!has_else) + return leave(node, user); + child = isl_ast_node_if_take_else_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_if_restore_else_node(node, child); + return leave(node, user); + case isl_ast_node_block: + children = isl_ast_node_block_take_children(node); + children = traverse_list(children, enter, leave, user); + node = isl_ast_node_block_restore_children(node, children); + return leave(node, user); + case isl_ast_node_mark: + child = isl_ast_node_mark_take_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_mark_restore_node(node, child); + return leave(node, user); + case isl_ast_node_user: + return leave(node, user); + case isl_ast_node_error: + return isl_ast_node_free(node); + } + + return node; +} + +/* Internal data structure storing the arguments of + * isl_ast_node_foreach_descendant_top_down. + */ +struct isl_ast_node_preorder_data { + isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user); + void *user; +}; + +/* Enter "node" and set *more to continue traversing its descendants. + * + * In the case of a depth first preorder traversal, call data->fn and + * let it decide whether to continue. + */ +static __isl_give isl_ast_node *preorder_enter(__isl_take isl_ast_node *node, + int *more, void *user) +{ + struct isl_ast_node_preorder_data *data = user; + isl_bool m; + + if (!node) + return NULL; + m = data->fn(node, data->user); + if (m < 0) + return isl_ast_node_free(node); + *more = m; + return node; +} + +/* Leave "node". + * + * In the case of a depth first preorder traversal, nothing needs to be done. + */ +static __isl_give isl_ast_node *preorder_leave(__isl_take isl_ast_node *node, + void *user) +{ + return node; } /* Traverse the descendants of "node" (including the node itself) @@ -1449,43 +1889,66 @@ isl_stat isl_ast_node_foreach_descendant_top_down( __isl_keep isl_ast_node *node, isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) { - isl_bool more; - isl_stat ok; + struct isl_ast_node_preorder_data data = { fn, user }; + + node = isl_ast_node_copy(node); + node = traverse(node, &preorder_enter, &preorder_leave, &data); + isl_ast_node_free(node); + + return isl_stat_non_null(node); +} + +/* Internal data structure storing the arguments of + * isl_ast_node_map_descendant_bottom_up. + */ +struct isl_ast_node_postorder_data { + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + void *user); + void *user; +}; + +/* Enter "node" and set *more to continue traversing its descendants. + * + * In the case of a depth-first post-order traversal, + * nothing needs to be done and traversal always continues. + */ +static __isl_give isl_ast_node *postorder_enter(__isl_take isl_ast_node *node, + int *more, void *user) +{ + *more = 1; + return node; +} + +/* Leave "node". + * + * In the case of a depth-first post-order traversal, call data->fn. + */ +static __isl_give isl_ast_node *postorder_leave(__isl_take isl_ast_node *node, + void *user) +{ + struct isl_ast_node_postorder_data *data = user; if (!node) - return isl_stat_error; + return NULL; - more = fn(node, user); - if (more < 0) - return isl_stat_error; - if (!more) - return isl_stat_ok; + node = data->fn(node, data->user); + return node; +} - switch (node->type) { - case isl_ast_node_for: - node = node->u.f.body; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_if: - ok = isl_ast_node_foreach_descendant_top_down(node->u.i.then, - fn, user); - if (ok < 0) - return isl_stat_error; - if (!node->u.i.else_node) - return isl_stat_ok; - node = node->u.i.else_node; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_block: - return nodelist_foreach(node->u.b.children, fn, user); - case isl_ast_node_mark: - node = node->u.m.node; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_user: - break; - case isl_ast_node_error: - return isl_stat_error; - } +/* Traverse the descendants of "node" (including the node itself) + * in depth-first post-order, where the user callback is allowed to modify the + * visited node. + * + * Return the updated node. + */ +__isl_give isl_ast_node *isl_ast_node_map_descendant_bottom_up( + __isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + void *user), void *user) +{ + struct isl_ast_node_postorder_data data = { fn, user }; - return isl_stat_ok; + return traverse(node, &postorder_enter, &postorder_leave, &data); } /* Textual C representation of the various operators. @@ -1644,21 +2107,30 @@ static int sub_expr_need_parens(enum isl_ast_expr_op_type op, return 0; } -/* Print "expr" as a subexpression of an "op" operation in C format. +/* Print the subexpression at position "pos" of operation expression "expr" + * in C format. * If "left" is set, then "expr" is the left-most operand. */ static __isl_give isl_printer *print_sub_expr_c(__isl_take isl_printer *p, - enum isl_ast_expr_op_type op, __isl_keep isl_ast_expr *expr, int left) + __isl_keep isl_ast_expr *expr, int pos, int left) { int need_parens; + isl_ast_expr *arg; - need_parens = sub_expr_need_parens(op, expr, left); + if (!expr) + return isl_printer_free(p); + + arg = isl_ast_expr_list_get_at(expr->u.op.args, pos); + need_parens = sub_expr_need_parens(expr->u.op.op, arg, left); if (need_parens) p = isl_printer_print_str(p, "("); - p = print_ast_expr_c(p, expr); + p = print_ast_expr_c(p, arg); if (need_parens) p = isl_printer_print_str(p, ")"); + + isl_ast_expr_free(arg); + return p; } @@ -1822,21 +2294,40 @@ static const char *get_op_str_c(__isl_keep isl_printer *p, return op_str_c[type]; } +/* Print the expression at position "pos" in "list" in C format. + */ +static __isl_give isl_printer *print_at_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr_list *list, int pos) +{ + isl_ast_expr *expr; + + expr = isl_ast_expr_list_get_at(list, pos); + p = print_ast_expr_c(p, expr); + isl_ast_expr_free(expr); + + return p; +} + /* Print a min or max reduction "expr" in C format. */ static __isl_give isl_printer *print_min_max_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; - for (i = 1; i < expr->u.op.n_arg; ++i) { + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); p = isl_printer_print_str(p, "("); } - p = isl_printer_print_ast_expr(p, expr->u.op.args[0]); - for (i = 1; i < expr->u.op.n_arg; ++i) { + p = print_at_c(p, expr->u.op.args, 0); + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); p = isl_printer_print_str(p, ")"); } @@ -1851,13 +2342,18 @@ static __isl_give isl_printer *print_call_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; - p = print_ast_expr_c(p, expr->u.op.args[0]); + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, "("); - for (i = 1; i < expr->u.op.n_arg; ++i) { + for (i = 1; i < n; ++i) { if (i != 1) p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); } p = isl_printer_print_str(p, ")"); @@ -1872,11 +2368,16 @@ static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; + + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); - p = print_ast_expr_c(p, expr->u.op.args[0]); - for (i = 1; i < expr->u.op.n_arg; ++i) { + p = print_at_c(p, expr->u.op.args, 0); + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, "["); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); p = isl_printer_print_str(p, "]"); } @@ -1888,6 +2389,8 @@ static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p, static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { + isl_size n; + if (!p) return NULL; if (!expr) @@ -1903,11 +2406,13 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, p = print_access_c(p, expr); break; } - if (expr->u.op.n_arg == 1) { + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + if (n == 1) { p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); - p = print_sub_expr_c(p, expr->u.op.op, - expr->u.op.args[0], 0); + p = print_sub_expr_c(p, expr, 0, 0); break; } if (expr->u.op.op == isl_ast_expr_op_fdiv_q) { @@ -1916,9 +2421,9 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, name = get_op_str_c(p, isl_ast_expr_op_fdiv_q); p = isl_printer_print_str(p, name); p = isl_printer_print_str(p, "("); - p = print_ast_expr_c(p, expr->u.op.args[0]); + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[1]); + p = print_at_c(p, expr->u.op.args, 1); p = isl_printer_print_str(p, ")"); break; } @@ -1929,24 +2434,24 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, } if (expr->u.op.op == isl_ast_expr_op_cond || expr->u.op.op == isl_ast_expr_op_select) { - p = print_ast_expr_c(p, expr->u.op.args[0]); + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, " ? "); - p = print_ast_expr_c(p, expr->u.op.args[1]); + p = print_at_c(p, expr->u.op.args, 1); p = isl_printer_print_str(p, " : "); - p = print_ast_expr_c(p, expr->u.op.args[2]); + p = print_at_c(p, expr->u.op.args, 2); break; } - if (expr->u.op.n_arg != 2) + if (n != 2) isl_die(isl_printer_get_ctx(p), isl_error_internal, "operation should have two arguments", return isl_printer_free(p)); - p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[0], 1); + p = print_sub_expr_c(p, expr, 0, 1); if (expr->u.op.op != isl_ast_expr_op_member) p = isl_printer_print_str(p, " "); p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); if (expr->u.op.op != isl_ast_expr_op_member) p = isl_printer_print_str(p, " "); - p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[1], 0); + p = print_sub_expr_c(p, expr, 1, 0); break; case isl_ast_expr_id: p = isl_printer_print_str(p, isl_id_get_name(expr->u.id)); @@ -2030,6 +2535,14 @@ static __isl_give isl_printer *print_arguments(__isl_take isl_printer *p, return p; } +/* Textual representations of the YAML keys for an isl_ast_expr object. + */ +static char *expr_str[] = { + [isl_ast_expr_op] = "op", + [isl_ast_expr_id] = "id", + [isl_ast_expr_int] = "val", +}; + /* Print "expr" to "p" in isl format. * * In particular, print the isl_ast_expr as a YAML document. @@ -2054,21 +2567,21 @@ static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p, op = isl_ast_expr_get_op_type(expr); if (op == isl_ast_expr_op_error) return isl_printer_free(p); - p = isl_printer_print_str(p, "op"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); p = isl_printer_print_str(p, op_str[op]); p = isl_printer_yaml_next(p); p = print_arguments(p, expr); break; case isl_ast_expr_id: - p = isl_printer_print_str(p, "id"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); id = isl_ast_expr_get_id(expr); p = isl_printer_print_id(p, id); isl_id_free(id); break; case isl_ast_expr_int: - p = isl_printer_print_str(p, "val"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); v = isl_ast_expr_get_val(expr); p = isl_printer_print_val(p, v); @@ -2109,6 +2622,176 @@ __isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p, return p; } +#undef KEY +#define KEY enum isl_ast_expr_op_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_expr_op_error +#undef KEY_END +#define KEY_END (isl_ast_expr_op_address_of + 1) +#undef KEY_STR +#define KEY_STR op_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_op_type +#undef KEY_GET +#define KEY_GET get_op_type +#include "extract_key.c" + +/* Return the next token, which is assumed to be a key in a YAML mapping, + * from "s" as a string. + */ +static __isl_give char *next_key(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + char *str; + isl_ctx *ctx; + + if (!s) + return NULL; + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + ctx = isl_stream_get_ctx(s); + str = isl_token_get_str(ctx, tok); + isl_token_free(tok); + return str; +} + +/* Remove the next token, which is assumed to be the key "expected" + * in a YAML mapping, from "s" and move to the corresponding value. + */ +static isl_stat eat_key(__isl_keep isl_stream *s, const char *expected) +{ + char *str; + int ok; + + str = next_key(s); + if (!str) + return isl_stat_error; + ok = !strcmp(str, expected); + free(str); + + if (!ok) { + isl_stream_error(s, NULL, "expecting different key"); + return isl_stat_error; + } + + if (isl_stream_yaml_next(s) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +#undef EL_BASE +#define EL_BASE ast_expr + +#include + +/* Read an isl_ast_expr object of type isl_ast_expr_op from "s", + * where the "op" key has already been read by the caller. + * + * Read the operation type and the arguments and + * return the corresponding isl_ast_expr object. + */ +static __isl_give isl_ast_expr *read_op(__isl_keep isl_stream *s) +{ + enum isl_ast_expr_op_type op; + isl_ast_expr_list *list; + + op = get_op_type(s); + if (op < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + if (eat_key(s, "args") < 0) + return NULL; + + list = isl_stream_yaml_read_ast_expr_list(s); + + return alloc_op(op, list); +} + +/* Read an isl_ast_expr object of type isl_ast_expr_id from "s", + * where the "id" key has already been read by the caller. + */ +static __isl_give isl_ast_expr *read_id(__isl_keep isl_stream *s) +{ + return isl_ast_expr_from_id(isl_stream_read_id(s)); +} + +/* Read an isl_ast_expr object of type isl_ast_expr_int from "s", + * where the "val" key has already been read by the caller. + */ +static __isl_give isl_ast_expr *read_int(__isl_keep isl_stream *s) +{ + return isl_ast_expr_from_val(isl_stream_read_val(s)); +} + +#undef KEY +#define KEY enum isl_ast_expr_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_expr_error +#undef KEY_END +#define KEY_END (isl_ast_expr_int + 1) +#undef KEY_STR +#define KEY_STR expr_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_expr_type +#undef KEY_GET +#define KEY_GET get_expr_type +#include "extract_key.c" + +/* Read an isl_ast_expr object from "s". + * + * The keys in the YAML mapping are assumed to appear + * in the same order as the one in which they are printed + * by print_ast_expr_isl. + * In particular, the isl_ast_expr_op type, which is the only one + * with more than one element, is identified by the "op" key and + * not by the "args" key. + */ +__isl_give isl_ast_expr *isl_stream_read_ast_expr(__isl_keep isl_stream *s) +{ + enum isl_ast_expr_type type; + isl_bool more; + isl_ast_expr *expr; + + 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; + } + + type = get_expr_type(s); + if (type < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + switch (type) { + case isl_ast_expr_op: + expr = read_op(s); + break; + case isl_ast_expr_id: + expr = read_id(s); + break; + case isl_ast_expr_int: + expr = read_int(s); + break; + case isl_ast_expr_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) + return isl_ast_expr_free(expr); + + return expr; +} + static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p, __isl_keep isl_ast_node *node); @@ -2493,11 +3176,8 @@ static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p, __isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) { - if (!node || !options) + if (isl_ast_node_check_for(node) < 0 || !options) goto error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", goto error); p = print_for_c(p, node, options, 0, 0); isl_ast_print_options_free(options); return p; @@ -2512,11 +3192,8 @@ error: __isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) { - if (!node || !options) + if (isl_ast_node_check_if(node) < 0 || !options) goto error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", goto error); p = print_if_c(p, node, options, 1, 0); isl_ast_print_options_free(options); return p; @@ -2603,6 +3280,284 @@ __isl_give isl_printer *isl_ast_node_list_print( return p; } +/* Is the next token on "s" the start of a YAML sequence + * (rather than a YAML mapping)? + * + * A YAML sequence starts with either a '[' or a '-', depending on the format. + */ +static isl_bool next_is_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int type; + int seq; + + tok = isl_stream_next_token(s); + if (!tok) + return isl_bool_error; + type = isl_token_get_type(tok); + seq = type == '[' || type == '-'; + isl_stream_push_token(s, tok); + + return isl_bool_ok(seq); +} + +#undef EL_BASE +#define EL_BASE ast_node + +#include + +/* Read an isl_ast_node object of type isl_ast_node_block from "s". + */ +static __isl_give isl_ast_node *read_block(__isl_keep isl_stream *s) +{ + isl_ast_node_list *children; + + children = isl_stream_yaml_read_ast_node_list(s); + return isl_ast_node_block_from_children(children); +} + +/* Textual representation of the first YAML key used + * while printing an isl_ast_node of a given type. + * + * An isl_ast_node of type isl_ast_node_block is not printed + * as a YAML mapping and is therefore assigned a dummy key. + */ +static char *node_first_str[] = { + [isl_ast_node_for] = "iterator", + [isl_ast_node_mark] = "mark", + [isl_ast_node_user] = "user", + [isl_ast_node_if] = "guard", + [isl_ast_node_block] = "", +}; + +#undef KEY +#define KEY enum isl_ast_node_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_node_error +#undef KEY_END +#define KEY_END (isl_ast_node_user + 1) +#undef KEY_STR +#define KEY_STR node_first_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_node_type +#undef KEY_GET +#define KEY_GET get_node_type +#include "extract_key.c" + +static __isl_give isl_ast_node *read_body(__isl_keep isl_stream *s, + __isl_take isl_ast_node *node) +{ + if (eat_key(s, "body") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_body(node, isl_stream_read_ast_node(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_for from "s", + * where the initial "iterator" key has already been read by the caller. + * + * If the initial value is printed as the value of the key "value", + * then the for-loop is degenerate and can at most have + * a further "body" element. + * Otherwise, the for-loop also has "cond" and "inc" elements. + */ +static __isl_give isl_ast_node *read_for(__isl_keep isl_stream *s) +{ + isl_id *id; + isl_ast_expr *expr; + isl_ast_node *node; + char *key; + isl_bool more; + int is_value, is_init; + + expr = isl_stream_read_ast_expr(s); + id = isl_ast_expr_id_get_id(expr); + isl_ast_expr_free(expr); + if (!id) + return NULL; + if (isl_stream_yaml_next(s) < 0) + id = isl_id_free(id); + + node = isl_ast_node_alloc_for(id); + + key = next_key(s); + if (!key) + return isl_ast_node_free(node); + is_value = !strcmp(key, "value"); + is_init = !strcmp(key, "init"); + free(key); + if (!is_value && !is_init) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "unexpected key", return isl_ast_node_free(node)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_init(node, isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (is_value) { + node = isl_ast_node_for_mark_degenerate(node); + if (more) + node = read_body(s, node); + return node; + } + + if (eat_key(s, "cond") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_cond(node, isl_stream_read_ast_expr(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + if (eat_key(s, "inc") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_inc(node, isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + + if (more) + node = read_body(s, node); + + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_mark from "s", + * where the initial "mark" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_mark(__isl_keep isl_stream *s) +{ + isl_id *id; + isl_ast_node *node; + + id = isl_stream_read_id(s); + if (!id) + return NULL; + if (isl_stream_yaml_next(s) < 0) + goto error; + if (eat_key(s, "node") < 0) + goto error; + node = isl_stream_read_ast_node(s); + node = isl_ast_node_alloc_mark(id, node); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +error: + isl_id_free(id); + return NULL; +} + +/* Read an isl_ast_node object of type isl_ast_node_user from "s", + * where the "user" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_user(__isl_keep isl_stream *s) +{ + isl_ast_node *node; + + node = isl_ast_node_alloc_user(isl_stream_read_ast_expr(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_if from "s", + * where the initial "guard" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_if(__isl_keep isl_stream *s) +{ + isl_bool more; + isl_ast_node *node; + + node = isl_ast_node_alloc_if(isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (!more) + return node; + + if (eat_key(s, "then") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_if_set_then(node, isl_stream_read_ast_node(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (!more) + return node; + + if (eat_key(s, "else") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_if_set_else_node(node, isl_stream_read_ast_node(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + + return node; +} + +/* Read an isl_ast_node object from "s". + * + * A block node is printed as a YAML sequence by print_ast_node_isl. + * Every other node type is printed as a YAML mapping. + * + * First check if the next element is a sequence and if so, + * read a block node. + * Otherwise, read a node based on the first mapping key + * that is used to print a node type. + * Note that the keys in the YAML mapping are assumed to appear + * in the same order as the one in which they are printed + * by print_ast_node_isl. + */ +__isl_give isl_ast_node *isl_stream_read_ast_node(__isl_keep isl_stream *s) +{ + enum isl_ast_node_type type; + isl_bool more; + isl_bool seq; + isl_ast_node *node; + + seq = next_is_sequence(s); + if (seq < 0) + return NULL; + if (seq) + return read_block(s); + + 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; + } + + type = get_node_type(s); + if (type < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + + switch (type) { + case isl_ast_node_block: + isl_die(isl_stream_get_ctx(s), isl_error_internal, + "block cannot be detected as mapping", + return NULL); + case isl_ast_node_for: + node = read_for(s); + break; + case isl_ast_node_mark: + node = read_mark(s); + break; + case isl_ast_node_user: + node = read_user(s); + break; + case isl_ast_node_if: + node = read_if(s); + break; + case isl_ast_node_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) + return isl_ast_node_free(node); + + return node; +} + #define ISL_AST_MACRO_FDIV_Q (1 << 0) #define ISL_AST_MACRO_MIN (1 << 1) #define ISL_AST_MACRO_MAX (1 << 2) @@ -2610,13 +3565,26 @@ __isl_give isl_printer *isl_ast_node_list_print( ISL_AST_MACRO_MIN | \ ISL_AST_MACRO_MAX) +static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros); + +/* Wrapper around ast_expr_required_macros for use + * as an isl_ast_expr_list_foreach callback. + */ +static isl_stat entry_required_macros(__isl_take isl_ast_expr *expr, void *user) +{ + int *macros = user; + + *macros = ast_expr_required_macros(expr, *macros); + isl_ast_expr_free(expr); + + return isl_stat_ok; +} + /* If "expr" contains an isl_ast_expr_op_min, isl_ast_expr_op_max or * isl_ast_expr_op_fdiv_q then set the corresponding bit in "macros". */ static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros) { - int i; - if (macros == ISL_AST_MACRO_ALL) return macros; @@ -2630,8 +3598,8 @@ static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros) if (expr->u.op.op == isl_ast_expr_op_fdiv_q) macros |= ISL_AST_MACRO_FDIV_Q; - for (i = 0; i < expr->u.op.n_arg; ++i) - macros = ast_expr_required_macros(expr->u.op.args[i], macros); + isl_ast_expr_list_foreach(expr->u.op.args, + &entry_required_macros, ¯os); return macros; } diff --git a/polly/lib/External/isl/isl_ast_build.c b/polly/lib/External/isl/isl_ast_build.c index a0776e8..9f04e1c 100644 --- a/polly/lib/External/isl/isl_ast_build.c +++ b/polly/lib/External/isl/isl_ast_build.c @@ -1910,14 +1910,14 @@ error: /* Does "aff" only attain non-negative values over build->domain? * That is, does it not attain any negative values? */ -int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, +isl_bool isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, __isl_keep isl_aff *aff) { isl_set *test; - int empty; + isl_bool empty; if (!build) - return -1; + return isl_bool_error; aff = isl_aff_copy(aff); test = isl_set_from_basic_set(isl_aff_neg_basic_set(aff)); diff --git a/polly/lib/External/isl/isl_ast_build_expr.c b/polly/lib/External/isl/isl_ast_build_expr.c index 3e35416..590fa6f 100644 --- a/polly/lib/External/isl/isl_ast_build_expr.c +++ b/polly/lib/External/isl/isl_ast_build_expr.c @@ -40,6 +40,8 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *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. + * "ls" is the domain local space of the affine expression + * of which a term is being added. * "cst" is the constant term of the expression in which the added term * appears. It may be modified by isl_ast_expr_add_term. * @@ -48,6 +50,7 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff, */ struct isl_ast_add_term_data { isl_ast_build *build; + isl_local_space *ls; isl_val *cst; isl_val *v; }; @@ -72,23 +75,23 @@ struct isl_ast_add_term_data { * 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, +static isl_bool 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; + isl_bool is_zero; + isl_bool non_neg; if (isl_val_sgn(data->cst) != isl_val_sgn(data->v)) - return 0; + return isl_bool_false; 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; + return isl_bool_not(is_zero); } shift = isl_val_mul(shift, isl_val_copy(d)); shifted = isl_aff_copy(aff); @@ -99,7 +102,7 @@ static int is_non_neg_after_stealing(__isl_keep isl_aff *aff, return non_neg; } -/* Given the numerator "aff' of the argument of an integer division +/* 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. @@ -115,7 +118,7 @@ static int is_non_neg_after_stealing(__isl_keep isl_aff *aff, * That is, compute the minimal value "m" of "aff" over * data->build->domain and take * - * s = ceil(m/d) + * s = ceil(-m/d) * * such that * @@ -147,11 +150,26 @@ static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff, return isl_aff_add_constant_val(aff, shift); } -/* Create an isl_ast_expr evaluating the div at position "pos" in "ls". +/* Construct an expression representing the binary operation "type" + * (some division or modulo) applied to the expressions + * constructed from "aff" and "v". + */ +static __isl_give isl_ast_expr *div_mod(enum isl_ast_expr_op_type type, + __isl_take isl_aff *aff, __isl_take isl_val *v, + __isl_keep isl_ast_build *build) +{ + isl_ast_expr *expr1, *expr2; + + expr1 = isl_ast_expr_from_aff(aff, build); + expr2 = isl_ast_expr_from_val(v); + return isl_ast_expr_alloc_binary(type, expr1, expr2); +} + +/* Create an isl_ast_expr evaluating the div at position "pos" in data->ls. * The result is simplified in terms of data->build->domain. * This function may change (the sign of) data->v. * - * "ls" is known to be non-NULL. + * data->ls is known to be non-NULL. * * Let the div be of the form floor(e/d). * If the ast_build_prefer_pdiv option is set then we check if "e" @@ -182,22 +200,21 @@ static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff, * with s the minimal shift that makes the argument non-negative. */ static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data, - __isl_keep isl_local_space *ls, int pos) + int pos) { - isl_ctx *ctx = isl_local_space_get_ctx(ls); + isl_ctx *ctx = isl_local_space_get_ctx(data->ls); isl_aff *aff; - isl_ast_expr *num, *den; isl_val *d; enum isl_ast_expr_op_type type; - aff = isl_local_space_get_div(ls, pos); + aff = isl_local_space_get_div(data->ls, pos); d = isl_aff_get_denominator_val(aff); aff = isl_aff_scale_val(aff, isl_val_copy(d)); - den = isl_ast_expr_from_val(isl_val_copy(d)); type = isl_ast_expr_op_fdiv_q; if (isl_options_get_ast_build_prefer_pdiv(ctx)) { - int non_neg = isl_ast_build_aff_is_nonneg(data->build, aff); + isl_bool non_neg; + 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)); @@ -220,49 +237,47 @@ static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data, type = isl_ast_expr_op_pdiv_q; } - isl_val_free(d); - num = isl_ast_expr_from_aff(aff, data->build); - return isl_ast_expr_alloc_binary(type, num, den); + return div_mod(type, aff, d, data->build); } -/* Create an isl_ast_expr evaluating the specified dimension of "ls". +/* Create an isl_ast_expr evaluating the specified dimension of data->ls. * 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 data->build - * - parameters are constructed from the isl_ids in "ls" + * - parameters are constructed from the isl_ids in data->ls */ 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) + enum isl_dim_type type, int pos) { - isl_ctx *ctx = isl_local_space_get_ctx(ls); + isl_ctx *ctx = isl_local_space_get_ctx(data->ls); isl_id *id; if (type == isl_dim_div) - return var_div(data, ls, pos); + return var_div(data, pos); if (type == isl_dim_set) { id = isl_ast_build_get_iterator_id(data->build, pos); return isl_ast_expr_from_id(id); } - if (!isl_local_space_has_dim_id(ls, type, pos)) + if (!isl_local_space_has_dim_id(data->ls, type, pos)) isl_die(ctx, isl_error_internal, "unnamed dimension", return NULL); - id = isl_local_space_get_dim_id(ls, type, pos); + id = isl_local_space_get_dim_id(data->ls, type, pos); return isl_ast_expr_from_id(id); } /* Does "expr" represent the zero integer? */ -static int ast_expr_is_zero(__isl_keep isl_ast_expr *expr) +static isl_bool ast_expr_is_zero(__isl_keep isl_ast_expr *expr) { if (!expr) - return -1; + return isl_bool_error; if (expr->type != isl_ast_expr_int) - return 0; + return isl_bool_false; return isl_val_is_zero(expr->u.v); } @@ -343,10 +358,8 @@ static __isl_give isl_ast_expr *isl_ast_expr_mod(__isl_keep isl_val *v, if (!aff) return NULL; - expr = isl_ast_expr_from_aff(isl_aff_copy(aff), build); - - c = isl_ast_expr_from_val(isl_val_copy(d)); - expr = isl_ast_expr_alloc_binary(isl_ast_expr_op_pdiv_r, expr, c); + expr = div_mod(isl_ast_expr_op_pdiv_r, + isl_aff_copy(aff), isl_val_copy(d), build); if (!isl_val_is_one(v)) { c = isl_ast_expr_from_val(isl_val_copy(v)); @@ -394,7 +407,7 @@ error: return NULL; } -/* Add an expression for "*v" times the specified dimension of "ls" +/* Add an expression for "*v" times the specified dimension of data->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. @@ -418,8 +431,7 @@ 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_ast_expr *expr, enum isl_dim_type type, int pos, __isl_take isl_val *v, struct isl_ast_add_term_data *data) { isl_ast_expr *term; @@ -428,7 +440,7 @@ static __isl_give isl_ast_expr *isl_ast_expr_add_term( return NULL; data->v = v; - term = var(data, ls, type, pos); + term = var(data, type, pos); v = data->v; if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) { @@ -569,7 +581,7 @@ static isl_bool is_even_test(struct isl_extract_mod_data *data, * * Also, if "lin - 1" is non-negative, then "lin" is non-negative too. */ -static int extract_term_and_mod(struct isl_extract_mod_data *data, +static isl_stat extract_term_and_mod(struct isl_extract_mod_data *data, __isl_take isl_aff *term, __isl_take isl_aff *arg) { isl_bool even; @@ -605,9 +617,9 @@ static int extract_term_and_mod(struct isl_extract_mod_data *data, else data->add = isl_aff_add(data->add, term); if (!data->add) - return -1; + return isl_stat_error; - return 0; + return isl_stat_ok; } /* Given that data->v * div_i in data->aff is of the form @@ -628,7 +640,7 @@ static int extract_term_and_mod(struct isl_extract_mod_data *data, * * to data->neg or data->pos depending on the sign of -f. */ -static int extract_mod(struct isl_extract_mod_data *data) +static isl_stat extract_mod(struct isl_extract_mod_data *data) { return extract_term_and_mod(data, isl_aff_copy(data->div), isl_aff_copy(data->div)); @@ -652,9 +664,9 @@ static int extract_mod(struct isl_extract_mod_data *data) * * This function may modify data->div. */ -static int extract_nonneg_mod(struct isl_extract_mod_data *data) +static isl_stat extract_nonneg_mod(struct isl_extract_mod_data *data) { - int mod; + isl_bool mod; mod = isl_ast_build_aff_is_nonneg(data->build, data->div); if (mod < 0) @@ -671,10 +683,10 @@ static int extract_nonneg_mod(struct isl_extract_mod_data *data) return extract_mod(data); } - return 0; + return isl_stat_ok; error: data->aff = isl_aff_free(data->aff); - return -1; + return isl_stat_error; } /* Is the affine expression of constraint "c" "simpler" than data->nonneg @@ -735,19 +747,21 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, enum isl_dim_type a_type[2] = { isl_dim_param, isl_dim_in }; int i, t; isl_size n[2]; - int parallel = 1, opposite = 1; + isl_bool parallel = isl_bool_true, opposite = isl_bool_true; for (t = 0; t < 2; ++t) { n[t] = isl_constraint_dim(c, c_type[t]); if (n[t] < 0) - return isl_stat_error; + goto error; for (i = 0; i < n[t]; ++i) { - int a, b; + isl_bool a, b; a = isl_constraint_involves_dims(c, c_type[t], i, 1); b = isl_aff_involves_dims(data->div, a_type[t], i, 1); + if (a < 0 || b < 0) + goto error; if (a != b) - parallel = opposite = 0; + parallel = opposite = isl_bool_false; } } @@ -756,7 +770,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, v = isl_val_abs(isl_constraint_get_constant_val(c)); if (isl_val_cmp_si(v, 1 << 15) > 0) - parallel = opposite = 0; + parallel = opposite = isl_bool_false; isl_val_free(v); } @@ -781,6 +795,8 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, } isl_val_free(v1); isl_val_free(v2); + if (parallel < 0 || opposite < 0) + goto error; } } @@ -796,6 +812,9 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, return isl_stat_error; return isl_stat_ok; +error: + isl_constraint_free(c); + return isl_stat_error; } /* Given that data->v * div_i in data->aff is of the form @@ -854,7 +873,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, * multiple of d to make it positive. * * - * Note that the above is a only a very simple heuristic for finding an + * Note that the above is only a very simple heuristic for finding an * appropriate expression. We could try a bit harder by also considering * sums of constraints that involve disjoint sets of variables or * we could consider arbitrary linear combinations of constraints, @@ -877,7 +896,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c, * Alternatively, we could first compute the dual of the domain * and plug in the constraints on the coefficients. */ -static int try_extract_mod(struct isl_extract_mod_data *data) +static isl_stat try_extract_mod(struct isl_extract_mod_data *data) { isl_basic_set *hull; isl_val *v1, *v2; @@ -937,7 +956,7 @@ static int try_extract_mod(struct isl_extract_mod_data *data) isl_aff_copy(data->div), data->nonneg); error: data->aff = isl_aff_free(data->aff); - return -1; + return isl_stat_error; } /* Check if "data->aff" involves any (implicit) modulo computations based @@ -1051,6 +1070,81 @@ static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff, return data.aff; } +/* Call "fn" on every non-zero coefficient of "aff", + * passing it in the type of dimension (in terms of the domain), + * the position and the value, as long as "fn" returns isl_bool_true. + * If "reverse" is set, then the coefficients are considered in reverse order + * within each type. + */ +static isl_bool every_non_zero_coefficient(__isl_keep isl_aff *aff, + int reverse, + isl_bool (*fn)(enum isl_dim_type type, int pos, __isl_take isl_val *v, + void *user), + void *user) +{ + int i, j; + 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_val *v; + + for (i = 0; i < 3; ++i) { + isl_size n; + + n = isl_aff_dim(aff, t[i]); + if (n < 0) + return isl_bool_error; + for (j = 0; j < n; ++j) { + isl_bool ok; + int pos; + + pos = reverse ? n - 1 - j : j; + v = isl_aff_get_coefficient_val(aff, t[i], pos); + ok = isl_val_is_zero(v); + if (ok >= 0 && !ok) + ok = fn(l[i], pos, v, user); + else + isl_val_free(v); + if (ok < 0 || !ok) + return ok; + } + } + + return isl_bool_true; +} + +/* Internal data structure for extract_rational. + * + * "d" is the denominator of the original affine expression. + * "ls" is its domain local space. + * "rat" collects the rational part. + */ +struct isl_ast_extract_rational_data { + isl_val *d; + isl_local_space *ls; + + isl_aff *rat; +}; + +/* Given a non-zero term in an affine expression equal to "v" times + * the variable of type "type" at position "pos", + * add it to data->rat if "v" is not a multiple of data->d. + */ +static isl_bool add_rational(enum isl_dim_type type, int pos, + __isl_take isl_val *v, void *user) +{ + struct isl_ast_extract_rational_data *data = user; + isl_aff *rat; + + if (isl_val_is_divisible_by(v, data->d)) { + isl_val_free(v); + return isl_bool_true; + } + rat = isl_aff_var_on_domain(isl_local_space_copy(data->ls), type, pos); + rat = isl_aff_scale_val(rat, v); + data->rat = isl_aff_add(data->rat, rat); + return isl_bool_true; +} + /* Check if aff involves any non-integer coefficients. * If so, split aff into * @@ -1062,80 +1156,95 @@ static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff, static __isl_give isl_aff *extract_rational(__isl_take isl_aff *aff, __isl_keep isl_ast_expr **expr, __isl_keep isl_ast_build *build) { - int i, j; - isl_size n; - isl_aff *rat = NULL; - isl_local_space *ls = NULL; + struct isl_ast_extract_rational_data data = { NULL }; isl_ast_expr *rat_expr; - isl_val *v, *d; - 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_val *v; if (!aff) return NULL; - d = isl_aff_get_denominator_val(aff); - if (!d) + data.d = isl_aff_get_denominator_val(aff); + if (!data.d) goto error; - if (isl_val_is_one(d)) { - isl_val_free(d); + if (isl_val_is_one(data.d)) { + isl_val_free(data.d); return aff; } - aff = isl_aff_scale_val(aff, isl_val_copy(d)); + aff = isl_aff_scale_val(aff, isl_val_copy(data.d)); - ls = isl_aff_get_domain_local_space(aff); - rat = isl_aff_zero_on_domain(isl_local_space_copy(ls)); + data.ls = isl_aff_get_domain_local_space(aff); + data.rat = isl_aff_zero_on_domain(isl_local_space_copy(data.ls)); - for (i = 0; i < 3; ++i) { - n = isl_aff_dim(aff, t[i]); - if (n < 0) - goto error; - for (j = 0; j < n; ++j) { - isl_aff *rat_j; - - v = isl_aff_get_coefficient_val(aff, t[i], j); - if (!v) - goto error; - if (isl_val_is_divisible_by(v, d)) { - isl_val_free(v); - continue; - } - rat_j = isl_aff_var_on_domain(isl_local_space_copy(ls), - l[i], j); - rat_j = isl_aff_scale_val(rat_j, v); - rat = isl_aff_add(rat, rat_j); - } - } + if (every_non_zero_coefficient(aff, 0, &add_rational, &data) < 0) + goto error; v = isl_aff_get_constant_val(aff); - if (isl_val_is_divisible_by(v, d)) { + if (isl_val_is_divisible_by(v, data.d)) { isl_val_free(v); } else { isl_aff *rat_0; - rat_0 = isl_aff_val_on_domain(isl_local_space_copy(ls), v); - rat = isl_aff_add(rat, rat_0); + rat_0 = isl_aff_val_on_domain(isl_local_space_copy(data.ls), v); + data.rat = isl_aff_add(data.rat, rat_0); } - isl_local_space_free(ls); + isl_local_space_free(data.ls); - aff = isl_aff_sub(aff, isl_aff_copy(rat)); - aff = isl_aff_scale_down_val(aff, isl_val_copy(d)); + aff = isl_aff_sub(aff, isl_aff_copy(data.rat)); + aff = isl_aff_scale_down_val(aff, isl_val_copy(data.d)); - rat_expr = isl_ast_expr_from_aff(rat, build); - rat_expr = isl_ast_expr_div(rat_expr, isl_ast_expr_from_val(d)); + rat_expr = div_mod(isl_ast_expr_op_div, data.rat, data.d, build); *expr = ast_expr_add(*expr, rat_expr); return aff; error: - isl_aff_free(rat); - isl_local_space_free(ls); + isl_aff_free(data.rat); + isl_local_space_free(data.ls); isl_aff_free(aff); - isl_val_free(d); + isl_val_free(data.d); return NULL; } -/* Construct an isl_ast_expr that evaluates the affine expression "aff", +/* Internal data structure for isl_ast_expr_from_aff. + * + * "term" contains the information for adding a term. + * "expr" collects the results. + */ +struct isl_ast_add_terms_data { + struct isl_ast_add_term_data *term; + isl_ast_expr *expr; +}; + +/* Given a non-zero term in an affine expression equal to "v" times + * the variable of type "type" at position "pos", + * add the corresponding AST expression to data->expr. + */ +static isl_bool add_term(enum isl_dim_type type, int pos, + __isl_take isl_val *v, void *user) +{ + struct isl_ast_add_terms_data *data = user; + + data->expr = + isl_ast_expr_add_term(data->expr, type, pos, v, data->term); + + return isl_bool_true; +} + +/* Add terms to "expr" for each variable in "aff". + * The result is simplified in terms of data->build->domain. + */ +static __isl_give isl_ast_expr *add_terms(__isl_take isl_ast_expr *expr, + __isl_keep isl_aff *aff, struct isl_ast_add_term_data *data) +{ + struct isl_ast_add_terms_data terms_data = { data, expr }; + + if (every_non_zero_coefficient(aff, 0, &add_term, &terms_data) < 0) + return isl_ast_expr_free(terms_data.expr); + + return terms_data.expr; +} + +/* Construct an isl_ast_expr that evaluates the affine expression "aff". * The result is simplified in terms of build->domain. * * We first extract hidden modulo computations from the affine expression @@ -1146,15 +1255,9 @@ error: __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, __isl_keep isl_ast_build *build) { - int i, j; - isl_size n; - isl_val *v; isl_ctx *ctx = isl_aff_get_ctx(aff); isl_ast_expr *expr, *expr_neg; - 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; + struct isl_ast_add_term_data term_data; if (!aff) return NULL; @@ -1167,68 +1270,70 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, aff = extract_modulos(aff, &expr, &expr_neg, build); expr = ast_expr_sub(expr, expr_neg); - ls = isl_aff_get_domain_local_space(aff); + term_data.build = build; + term_data.ls = isl_aff_get_domain_local_space(aff); + term_data.cst = isl_aff_get_constant_val(aff); + expr = add_terms(expr, aff, &term_data); - data.build = build; - data.cst = isl_aff_get_constant_val(aff); - for (i = 0; i < 3; ++i) { - n = isl_aff_dim(aff, t[i]); - if (n < 0) - expr = isl_ast_expr_free(expr); - for (j = 0; j < n; ++j) { - v = isl_aff_get_coefficient_val(aff, t[i], j); - if (!v) - expr = isl_ast_expr_free(expr); - if (isl_val_is_zero(v)) { - isl_val_free(v); - continue; - } - expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, &data); - } - } - - expr = isl_ast_expr_add_int(expr, data.cst); + expr = isl_ast_expr_add_int(expr, term_data.cst); + isl_local_space_free(term_data.ls); - isl_local_space_free(ls); isl_aff_free(aff); return expr; } -/* Add terms to "expr" for each variable in "aff" with a coefficient - * with sign equal to "sign". - * The result is simplified in terms of data->build->domain. +/* Internal data structure for coefficients_of_sign. + * + * "sign" is the sign of the coefficients that should be retained. + * "aff" is the affine expression of which some coefficients are zeroed out. */ -static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, - __isl_keep isl_aff *aff, int sign, struct isl_ast_add_term_data *data) +struct isl_ast_coefficients_of_sign_data { + int sign; + isl_aff *aff; +}; + +/* Clear the specified coefficient of data->aff if the value "v" + * does not have the required sign. + */ +static isl_bool clear_opposite_sign(enum isl_dim_type type, int pos, + __isl_take isl_val *v, void *user) { - int i, j; - isl_val *v; - 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_coefficients_of_sign_data *data = user; - ls = isl_aff_get_domain_local_space(aff); + if (type == isl_dim_set) + type = isl_dim_in; + if (data->sign * isl_val_sgn(v) < 0) + data->aff = isl_aff_set_coefficient_si(data->aff, type, pos, 0); + isl_val_free(v); - for (i = 0; i < 3; ++i) { - isl_size n = isl_aff_dim(aff, t[i]); - if (n < 0) - expr = isl_ast_expr_free(expr); - for (j = 0; j < n; ++j) { - v = isl_aff_get_coefficient_val(aff, t[i], j); - if (sign * isl_val_sgn(v) <= 0) { - isl_val_free(v); - continue; - } - v = isl_val_abs(v); - expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, data); - } - } + return isl_bool_true; +} - isl_local_space_free(ls); +/* Extract the coefficients of "aff" (excluding the constant term) + * that have the given sign. + * + * Take a copy of "aff" and clear the coefficients that do not have + * the required sign. + * Consider the coefficients in reverse order since clearing + * the coefficient of an integer division in data.aff + * could result in the removal of that integer division from data.aff, + * changing the positions of all subsequent integer divisions of data.aff, + * while those of "aff" remain the same. + */ +static __isl_give isl_aff *coefficients_of_sign(__isl_take isl_aff *aff, + int sign) +{ + struct isl_ast_coefficients_of_sign_data data; - return expr; + data.sign = sign; + data.aff = isl_aff_copy(aff); + if (every_non_zero_coefficient(aff, 1, &clear_opposite_sign, &data) < 0) + data.aff = isl_aff_free(data.aff); + isl_aff_free(aff); + + data.aff = isl_aff_set_constant_si(data.aff, 0); + + return data.aff; } /* Should the constant term "v" be considered positive? @@ -1240,13 +1345,17 @@ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, * This results in slightly shorter expressions and may reduce the risk * of overflows. */ -static int constant_is_considered_positive(__isl_keep isl_val *v, +static isl_bool constant_is_considered_positive(__isl_keep isl_val *v, __isl_keep isl_ast_expr *pos, __isl_keep isl_ast_expr *neg) { - if (ast_expr_is_zero(pos)) - return 1; - if (ast_expr_is_zero(neg)) - return 0; + isl_bool zero; + + zero = ast_expr_is_zero(pos); + if (zero < 0 || zero) + return zero; + zero = ast_expr_is_zero(neg); + if (zero < 0 || zero) + return isl_bool_not(zero); return isl_val_is_pos(v); } @@ -1276,11 +1385,11 @@ static int constant_is_considered_positive(__isl_keep isl_val *v, * * where e and e' differ by a constant. */ -static int is_stride_constraint(__isl_keep isl_aff *aff, int pos) +static isl_bool is_stride_constraint(__isl_keep isl_aff *aff, int pos) { isl_aff *div; isl_val *c, *d; - int eq; + isl_bool eq; div = isl_aff_get_div(aff, pos); c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos); @@ -1379,28 +1488,44 @@ static __isl_give isl_ast_expr *extract_stride_constraint( return expr; } -/* Construct an isl_ast_expr that evaluates the condition "constraint", - * The result is simplified in terms of build->domain. - * - * We first check if the constraint is an equality of the form +/* Construct an isl_ast_expr evaluating * - * e - d floor(e/d) = 0 - * - * i.e., - * - * e mod d = 0 + * "expr_pos" == "expr_neg", if "eq" is set, or + * "expr_pos" >= "expr_neg", if "eq" is not set * - * If so, we convert it to - * - * (isl_ast_expr_op_eq, - * (isl_ast_expr_op_zdiv_r, expr(e), expr(d)), expr(0)) + * However, if "expr_pos" is an integer constant (and "expr_neg" is not), + * then the two expressions are interchanged. This ensures that, + * e.g., "i <= 5" is constructed rather than "5 >= i". + */ +static __isl_give isl_ast_expr *construct_constraint_expr(int eq, + __isl_take isl_ast_expr *expr_pos, __isl_take isl_ast_expr *expr_neg) +{ + isl_ast_expr *expr; + enum isl_ast_expr_op_type type; + int pos_is_cst, neg_is_cst; + + pos_is_cst = isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int; + neg_is_cst = isl_ast_expr_get_type(expr_neg) == isl_ast_expr_int; + if (pos_is_cst && !neg_is_cst) { + type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_le; + expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos); + } else { + type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_ge; + expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg); + } + + return expr; +} + +/* Construct an isl_ast_expr that evaluates the condition "aff" == 0 + * (if "eq" is set) or "aff" >= 0 (otherwise). + * The result is simplified in terms of build->domain. * - * Otherwise, let the constraint by either "a >= 0" or "a == 0". - * We first extract hidden modulo computations from "a" + * We first extract hidden modulo computations from "aff" * and then collect all the terms with a positive coefficient in cons_pos * and the terms with a negative coefficient in cons_neg. * - * The result is then of the form + * The result is then essentially of the form * * (isl_ast_expr_op_ge, expr(pos), expr(-neg))) * @@ -1408,48 +1533,20 @@ static __isl_give isl_ast_expr *extract_stride_constraint( * * (isl_ast_expr_op_eq, expr(pos), expr(-neg))) * - * However, if the first expression is an integer constant (and the second - * is not), then we swap the two expressions. This ensures that we construct, - * e.g., "i <= 5" rather than "5 >= i". - * - * Furthermore, is there are no terms with positive coefficients (or no terms + * However, if there are no terms with positive coefficients (or no terms * with negative coefficients), then the constant term is added to "pos" * (or "neg"), ignoring the sign of the constant term. */ -static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( - __isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build) +static __isl_give isl_ast_expr *isl_ast_expr_from_constraint_no_stride( + int eq, __isl_take isl_aff *aff, __isl_keep isl_ast_build *build) { - int i; - isl_size n; + isl_bool cst_is_pos; isl_ctx *ctx; isl_ast_expr *expr_pos; isl_ast_expr *expr_neg; - isl_ast_expr *expr; - isl_aff *aff; - int eq; - enum isl_ast_expr_op_type type; + isl_aff *aff_pos, *aff_neg; struct isl_ast_add_term_data data; - if (!constraint) - return NULL; - - aff = isl_constraint_get_aff(constraint); - eq = isl_constraint_is_equality(constraint); - isl_constraint_free(constraint); - - n = isl_aff_dim(aff, isl_dim_div); - if (n < 0) - aff = isl_aff_free(aff); - if (eq && n > 0) - for (i = 0; i < n; ++i) { - int is_stride; - is_stride = is_stride_constraint(aff, i); - if (is_stride < 0) - goto error; - if (is_stride) - return extract_stride_constraint(aff, i, build); - } - ctx = isl_aff_get_ctx(aff); expr_pos = isl_ast_expr_alloc_int_si(ctx, 0); expr_neg = isl_ast_expr_alloc_int_si(ctx, 0); @@ -1457,30 +1554,79 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( aff = extract_modulos(aff, &expr_pos, &expr_neg, build); data.build = build; + data.ls = isl_aff_get_domain_local_space(aff); data.cst = isl_aff_get_constant_val(aff); - expr_pos = add_signed_terms(expr_pos, aff, 1, &data); + + aff_pos = coefficients_of_sign(isl_aff_copy(aff), 1); + aff_neg = isl_aff_neg(coefficients_of_sign(aff, -1)); + + expr_pos = add_terms(expr_pos, aff_pos, &data); data.cst = isl_val_neg(data.cst); - expr_neg = add_signed_terms(expr_neg, aff, -1, &data); + expr_neg = add_terms(expr_neg, aff_neg, &data); data.cst = isl_val_neg(data.cst); + isl_local_space_free(data.ls); + + cst_is_pos = + constant_is_considered_positive(data.cst, expr_pos, expr_neg); + if (cst_is_pos < 0) + expr_pos = isl_ast_expr_free(expr_pos); - if (constant_is_considered_positive(data.cst, expr_pos, expr_neg)) { + if (cst_is_pos) { expr_pos = isl_ast_expr_add_int(expr_pos, data.cst); } else { 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 && - isl_ast_expr_get_type(expr_neg) != isl_ast_expr_int) { - type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_le; - expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos); - } else { - type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_ge; - expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg); - } + isl_aff_free(aff_pos); + isl_aff_free(aff_neg); + return construct_constraint_expr(eq, expr_pos, expr_neg); +} - isl_aff_free(aff); - return expr; +/* Construct an isl_ast_expr that evaluates the condition "constraint". + * The result is simplified in terms of build->domain. + * + * We first check if the constraint is an equality of the form + * + * e - d floor(e/d) = 0 + * + * i.e., + * + * e mod d = 0 + * + * If so, we convert it to + * + * (isl_ast_expr_op_eq, + * (isl_ast_expr_op_zdiv_r, expr(e), expr(d)), expr(0)) + */ +static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( + __isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build) +{ + int i; + isl_size n; + isl_aff *aff; + isl_bool eq; + + aff = isl_constraint_get_aff(constraint); + eq = isl_constraint_is_equality(constraint); + isl_constraint_free(constraint); + if (eq < 0) + goto error; + + n = isl_aff_dim(aff, isl_dim_div); + if (n < 0) + aff = isl_aff_free(aff); + if (eq && n > 0) + for (i = 0; i < n; ++i) { + isl_bool is_stride; + is_stride = is_stride_constraint(aff, i); + if (is_stride < 0) + goto error; + if (is_stride) + return extract_stride_constraint(aff, i, build); + } + + return isl_ast_expr_from_constraint_no_stride(eq, aff, build); error: isl_aff_free(aff); return NULL; @@ -1878,17 +2024,13 @@ static __isl_give isl_ast_expr *ast_expr_from_aff_list( op_type = state == isl_state_min ? isl_ast_expr_op_min : isl_ast_expr_op_max; expr = isl_ast_expr_alloc_op(isl_ast_build_get_ctx(build), op_type, n); - if (!expr) - goto error; for (i = 0; i < n; ++i) { isl_ast_expr *expr_i; aff = isl_aff_list_get_aff(list, i); expr_i = isl_ast_expr_from_aff(aff, build); - if (!expr_i) - goto error; - expr->u.op.args[i] = expr_i; + expr = isl_ast_expr_op_add_arg(expr, expr_i); } isl_aff_list_free(list); @@ -1899,21 +2041,22 @@ error: return NULL; } -/* Extend the expression in "next" to take into account +/* Extend the list of expressions in "next" to take into account * the piece at position "pos" in "data", allowing for a further extension * for the next piece(s). - * In particular, "next" is set to a select operation that selects + * In particular, "next" is extended with a select operation that selects * an isl_ast_expr corresponding to data->aff_list on data->set and * to an expression that will be filled in by later calls. - * Return a pointer to this location. + * Return a pointer to the arguments of this select operation. * Afterwards, the state of "data" is set to isl_state_none. * * The constraints of data->set are added to the generated * constraints of the build such that they can be exploited to simplify * the AST expression constructed from data->aff_list. */ -static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data, - int pos, isl_ast_expr **next) +static isl_ast_expr_list **add_intermediate_piece( + struct isl_from_pw_aff_data *data, + int pos, isl_ast_expr_list **next) { isl_ctx *ctx; isl_ast_build *build; @@ -1926,26 +2069,26 @@ static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data, ternary = isl_ast_expr_alloc_op(ctx, isl_ast_expr_op_select, 3); gist = isl_set_gist(isl_set_copy(set), isl_set_copy(data->dom)); arg = isl_ast_build_expr_from_set_internal(data->build, gist); - ternary = isl_ast_expr_set_op_arg(ternary, 0, arg); + ternary = isl_ast_expr_op_add_arg(ternary, arg); build = isl_ast_build_copy(data->build); build = isl_ast_build_restrict_generated(build, set); arg = ast_expr_from_aff_list(data->p[pos].aff_list, data->p[pos].state, build); data->p[pos].aff_list = NULL; isl_ast_build_free(build); - ternary = isl_ast_expr_set_op_arg(ternary, 1, arg); + ternary = isl_ast_expr_op_add_arg(ternary, arg); data->p[pos].state = isl_state_none; if (!ternary) return NULL; - *next = ternary; - return &ternary->u.op.args[2]; + *next = isl_ast_expr_list_add(*next, ternary); + return &ternary->u.op.args; } -/* Extend the expression in "next" to take into account +/* Extend the list of expressions in "next" to take into account * the final piece, located at position "pos" in "data". - * In particular, "next" is set to evaluate data->aff_list - * and the domain is ignored. + * In particular, "next" is extended with an expression + * to evaluate data->aff_list and the domain is ignored. * Return isl_stat_ok on success and isl_stat_error on failure. * * The constraints of data->set are however added to the generated @@ -1953,9 +2096,10 @@ static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data, * the AST expression constructed from data->aff_list. */ static isl_stat add_last_piece(struct isl_from_pw_aff_data *data, - int pos, isl_ast_expr **next) + int pos, isl_ast_expr_list **next) { isl_ast_build *build; + isl_ast_expr *last; if (data->p[pos].state == isl_state_none) isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid, @@ -1964,8 +2108,9 @@ static isl_stat add_last_piece(struct isl_from_pw_aff_data *data, build = isl_ast_build_copy(data->build); build = isl_ast_build_restrict_generated(build, data->p[pos].set); data->p[pos].set = NULL; - *next = ast_expr_from_aff_list(data->p[pos].aff_list, + last = ast_expr_from_aff_list(data->p[pos].aff_list, data->p[pos].state, build); + *next = isl_ast_expr_list_add(*next, last); data->p[pos].aff_list = NULL; isl_ast_build_free(build); data->p[pos].state = isl_state_none; @@ -2006,17 +2151,25 @@ static int sort_pieces_cmp(const void *p1, const void *p2, void *arg) * * Construct intermediate AST expressions for the initial pieces and * finish off with the final pieces. + * + * Any piece that is not the very first is added to the list of arguments + * of the previously constructed piece. + * In order not to have to special case the first piece, + * an extra list is created to hold the final result. */ static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data) { int i; - isl_ast_expr *res = NULL; - isl_ast_expr **next = &res; + isl_ctx *ctx; + isl_ast_expr_list *res_list; + isl_ast_expr_list **next = &res_list; + isl_ast_expr *res; if (data->p[data->n].state != isl_state_none) data->n++; + ctx = isl_ast_build_get_ctx(data->build); if (data->n == 0) - isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid, + isl_die(ctx, isl_error_invalid, "cannot handle void expression", return NULL); for (i = 0; i < data->n; ++i) { @@ -2028,18 +2181,26 @@ static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data) if (isl_sort(data->p, data->n, sizeof(data->p[0]), &sort_pieces_cmp, NULL) < 0) - return isl_ast_expr_free(res); + return NULL; + res_list = isl_ast_expr_list_alloc(ctx, 1); + if (!res_list) + return NULL; for (i = 0; i + 1 < data->n; ++i) { next = add_intermediate_piece(data, i, next); if (!next) - return isl_ast_expr_free(res); + goto error; } if (add_last_piece(data, data->n - 1, next) < 0) - return isl_ast_expr_free(res); + goto error; + res = isl_ast_expr_list_get_at(res_list, 0); + isl_ast_expr_list_free(res_list); return res; +error: + isl_ast_expr_list_free(res_list); + return NULL; } /* Is the domain of the current entry of "data", which is assumed @@ -2364,14 +2525,14 @@ static __isl_give isl_ast_expr *isl_ast_build_with_arguments( n = isl_multi_pw_aff_dim(mpa, isl_dim_out); expr = n >= 0 ? isl_ast_expr_alloc_op(ctx, type, 1 + n) : NULL; - expr = isl_ast_expr_set_op_arg(expr, 0, arg0); + expr = isl_ast_expr_op_add_arg(expr, arg0); for (i = 0; i < n; ++i) { isl_pw_aff *pa; isl_ast_expr *arg; pa = isl_multi_pw_aff_get_pw_aff(mpa, i); arg = isl_ast_build_expr_from_pw_aff_internal(build, pa); - expr = isl_ast_expr_set_op_arg(expr, 1 + i, arg); + expr = isl_ast_expr_op_add_arg(expr, arg); } isl_multi_pw_aff_free(mpa); diff --git a/polly/lib/External/isl/isl_ast_build_private.h b/polly/lib/External/isl/isl_ast_build_private.h index 1128e63..cb10fb4 100644 --- a/polly/lib/External/isl/isl_ast_build_private.h +++ b/polly/lib/External/isl/isl_ast_build_private.h @@ -290,7 +290,7 @@ __isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff( __isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain( __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap); -int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, +isl_bool isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build, __isl_keep isl_aff *aff); isl_bool isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos); diff --git a/polly/lib/External/isl/isl_ast_codegen.c b/polly/lib/External/isl/isl_ast_codegen.c index d337c4e..774dfab 100644 --- a/polly/lib/External/isl/isl_ast_codegen.c +++ b/polly/lib/External/isl/isl_ast_codegen.c @@ -702,8 +702,6 @@ static __isl_give isl_ast_expr *reduce_list(enum isl_ast_expr_op_type type, ctx = isl_pw_aff_list_get_ctx(list); expr = isl_ast_expr_alloc_op(ctx, type, n); - if (!expr) - return NULL; list = isl_pw_aff_list_copy(list); list = isl_pw_aff_list_sort(list, &reduce_list_cmp, NULL); @@ -715,17 +713,11 @@ static __isl_give isl_ast_expr *reduce_list(enum isl_ast_expr_op_type type, expr_i = isl_ast_build_expr_from_pw_aff_internal(build, isl_pw_aff_list_get_pw_aff(list, i)); - if (!expr_i) - goto error; - expr->u.op.args[i] = expr_i; + expr = isl_ast_expr_op_add_arg(expr, expr_i); } isl_pw_aff_list_free(list); return expr; -error: - isl_pw_aff_list_free(list); - isl_ast_expr_free(expr); - return NULL; } /* Add guards implied by the "generated constraints", @@ -794,15 +786,16 @@ static __isl_give isl_ast_graft *refine_degenerate( __isl_keep isl_ast_build *sub_build) { isl_pw_aff *value; + isl_ast_expr *init; if (!graft || !sub_build) return isl_ast_graft_free(graft); value = isl_pw_aff_copy(sub_build->value); - graft->node->u.f.init = isl_ast_build_expr_from_pw_aff_internal(build, - value); - if (!graft->node->u.f.init) + init = isl_ast_build_expr_from_pw_aff_internal(build, value); + graft->node = isl_ast_node_for_set_init(graft->node, init); + if (!graft->node) return isl_ast_graft_free(graft); return graft; @@ -1031,10 +1024,10 @@ static __isl_give isl_ast_graft *set_for_cond_from_list( bound = reduce_list(isl_ast_expr_op_min, list, build); iterator = isl_ast_expr_copy(graft->node->u.f.iterator); cond = isl_ast_expr_alloc_binary(type, iterator, bound); - graft->node->u.f.cond = cond; + graft->node = isl_ast_node_for_set_cond(graft->node, cond); isl_pw_aff_list_free(list); - if (!graft->node->u.f.cond) + if (!graft->node) return isl_ast_graft_free(graft); return graft; } @@ -1052,8 +1045,8 @@ static __isl_give isl_ast_graft *set_for_cond_from_set( return NULL; cond = isl_ast_build_expr_from_set_internal(build, isl_set_copy(set)); - graft->node->u.f.cond = cond; - if (!graft->node->u.f.cond) + graft->node = isl_ast_node_for_set_cond(graft->node, cond); + if (!graft->node) return isl_ast_graft_free(graft); return graft; } @@ -1120,18 +1113,16 @@ static __isl_give isl_ast_graft *set_for_node_expressions( int use_list, __isl_keep isl_pw_aff_list *upper_list, __isl_keep isl_set *upper_set, __isl_keep isl_ast_build *build) { - isl_ast_node *node; + isl_ast_expr *init; if (!graft) return NULL; - build = isl_ast_build_copy(build); - - node = graft->node; - node->u.f.init = reduce_list(isl_ast_expr_op_max, lower, build); - node->u.f.inc = for_inc(build); + init = reduce_list(isl_ast_expr_op_max, lower, build); + graft->node = isl_ast_node_for_set_init(graft->node, init); + graft->node = isl_ast_node_for_set_inc(graft->node, for_inc(build)); - if (!node->u.f.init || !node->u.f.inc) + if (!graft->node) graft = isl_ast_graft_free(graft); if (use_list) @@ -1139,8 +1130,6 @@ static __isl_give isl_ast_graft *set_for_node_expressions( else graft = set_for_cond_from_set(graft, upper_set, build); - isl_ast_build_free(build); - return graft; } @@ -1247,7 +1236,7 @@ struct isl_ast_count_constraints_data { }; /* Increment data->n_indep, data->lower or data->upper depending - * on whether "c" is independenct of dimensions data->pos, + * on whether "c" is independent of dimensions data->pos, * a lower bound or an upper bound. */ static isl_stat count_constraints(__isl_take isl_constraint *c, void *user) diff --git a/polly/lib/External/isl/isl_ast_graft.c b/polly/lib/External/isl/isl_ast_graft.c index 03e8449..d833776 100644 --- a/polly/lib/External/isl/isl_ast_graft.c +++ b/polly/lib/External/isl/isl_ast_graft.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -22,11 +23,14 @@ static __isl_give isl_ast_graft *isl_ast_graft_copy( __isl_keep isl_ast_graft *graft); +static __isl_give isl_ast_graft *isl_stream_read_ast_graft( + __isl_keep isl_stream *s); #undef EL_BASE #define EL_BASE ast_graft #include +#include #undef BASE #define BASE ast_graft @@ -45,39 +49,56 @@ __isl_give isl_ast_node *isl_ast_graft_get_node( return graft ? isl_ast_node_copy(graft->node) : NULL; } -/* Create a graft for "node" with no guards and no enforced conditions. +/* Create a graft for "node" with guards "guard" and + * enforced conditions "enforced". */ -__isl_give isl_ast_graft *isl_ast_graft_alloc( - __isl_take isl_ast_node *node, __isl_keep isl_ast_build *build) +static isl_ast_graft *graft_alloc(__isl_take isl_ast_node *node, + __isl_take isl_set *guard, __isl_take isl_basic_set *enforced) { isl_ctx *ctx; - isl_space *space; isl_ast_graft *graft; - if (!node) - return NULL; + if (!node || !guard || !enforced) + goto error; ctx = isl_ast_node_get_ctx(node); graft = isl_calloc_type(ctx, isl_ast_graft); if (!graft) goto error; - space = isl_ast_build_get_space(build, 1); - graft->ref = 1; graft->node = node; - graft->guard = isl_set_universe(isl_space_copy(space)); - graft->enforced = isl_basic_set_universe(space); - - if (!graft->guard || !graft->enforced) - return isl_ast_graft_free(graft); + graft->guard = guard; + graft->enforced = enforced; return graft; error: isl_ast_node_free(node); + isl_set_free(guard); + isl_basic_set_free(enforced); return NULL; } +/* Create a graft for "node" with no guards and no enforced conditions. + */ +__isl_give isl_ast_graft *isl_ast_graft_alloc( + __isl_take isl_ast_node *node, __isl_keep isl_ast_build *build) +{ + isl_space *space; + isl_set *guard; + isl_basic_set *enforced; + + if (!node) + return NULL; + + space = isl_ast_build_get_space(build, 1); + + guard = isl_set_universe(isl_space_copy(space)); + enforced = isl_basic_set_universe(space); + + return graft_alloc(node, guard, enforced); +} + /* Create a graft with no guards and no enforced conditions * encapsulating a call to the domain element specified by "executed". * "executed" is assumed to be single-valued. @@ -364,9 +385,7 @@ static __isl_give isl_ast_graft *insert_if_node( return graft; } - build = isl_ast_build_copy(build); graft->node = ast_node_insert_if(graft->node, guard, build); - isl_ast_build_free(build); if (!graft->node) return isl_ast_graft_free(graft); @@ -1443,6 +1462,25 @@ __isl_give isl_ast_graft_list *isl_ast_graft_list_group_on_guard( return list; } +/* An enumeration of the keys that appear in the textual representation + * of an isl_sat_graft object. + */ +enum isl_graft_key { + isl_graft_key_error = -1, + isl_graft_key_guard, + isl_graft_key_enforced, + isl_graft_key_node, + isl_graft_key_end +}; + +/* Textual representations of the keys for an isl_sat_graft object. + */ +static char *key_str[] = { + [isl_graft_key_guard] = "guard", + [isl_graft_key_enforced] = "enforced", + [isl_graft_key_node] = "node", +}; + __isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p, __isl_keep isl_ast_graft *graft) { @@ -1452,15 +1490,91 @@ __isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p, return isl_printer_free(p); p = isl_printer_print_str(p, "("); - p = isl_printer_print_str(p, "guard: "); + p = isl_printer_print_str(p, key_str[isl_graft_key_guard]); + p = isl_printer_print_str(p, ": "); p = isl_printer_print_set(p, graft->guard); p = isl_printer_print_str(p, ", "); - p = isl_printer_print_str(p, "enforced: "); + p = isl_printer_print_str(p, key_str[isl_graft_key_enforced]); + p = isl_printer_print_str(p, ": "); p = isl_printer_print_basic_set(p, graft->enforced); p = isl_printer_print_str(p, ", "); - p = isl_printer_print_str(p, "node: "); + p = isl_printer_print_str(p, key_str[isl_graft_key_node]); + p = isl_printer_print_str(p, ": "); p = isl_printer_print_ast_node(p, graft->node); p = isl_printer_print_str(p, ")"); return p; } + +#undef KEY +#define KEY enum isl_graft_key +#undef KEY_ERROR +#define KEY_ERROR isl_graft_key_error +#undef KEY_END +#define KEY_END isl_graft_key_end +#undef KEY_STR +#define KEY_STR key_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_key +#undef KEY_GET +#define KEY_GET get_key +#include "extract_key.c" + +/* Read the key "key" from "s", along with the subsequent colon. + */ +static isl_stat read_key(__isl_keep isl_stream *s, enum isl_graft_key key) +{ + enum isl_graft_key extracted; + + extracted = get_key(s); + if (extracted < 0) + return isl_stat_error; + if (extracted != key) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "expecting different field", return isl_stat_error); + if (isl_stream_eat(s, ':') < 0) + return isl_stat_error; + return isl_stat_ok; +} + +/* Read an isl_ast_graft object from "s". + * + * Read the pieces in the way they are printed in isl_printer_print_ast_graft. + */ +static __isl_give isl_ast_graft *isl_stream_read_ast_graft( + __isl_keep isl_stream *s) +{ + isl_set *guard; + isl_basic_set *enforced = NULL; + isl_ast_node *node = NULL; + + if (isl_stream_eat(s, '(') < 0) + return NULL; + if (read_key(s, isl_graft_key_guard) < 0) + return NULL; + guard = isl_stream_read_set(s); + if (!guard) + goto error; + if (isl_stream_eat(s, ',') < 0) + goto error; + if (read_key(s, isl_graft_key_enforced) < 0) + goto error; + enforced = isl_stream_read_basic_set(s); + if (!enforced) + goto error; + if (isl_stream_eat(s, ',') < 0) + goto error; + if (read_key(s, isl_graft_key_node) < 0) + goto error; + node = isl_stream_read_ast_node(s); + if (!node) + goto error; + if (isl_stream_eat(s, ')') < 0) + goto error; + return graft_alloc(node, guard, enforced); +error: + isl_set_free(guard); + isl_basic_set_free(enforced); + isl_ast_node_free(node); + return NULL; +} diff --git a/polly/lib/External/isl/isl_ast_graft_private.h b/polly/lib/External/isl/isl_ast_graft_private.h index 5ca7c03..5bf010b 100644 --- a/polly/lib/External/isl/isl_ast_graft_private.h +++ b/polly/lib/External/isl/isl_ast_graft_private.h @@ -6,6 +6,7 @@ #include #include #include +#include struct isl_ast_graft; typedef struct isl_ast_graft isl_ast_graft; @@ -102,4 +103,6 @@ __isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards( __isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p, __isl_keep isl_ast_graft *graft); +__isl_give isl_ast_graft_list *isl_stream_read_ast_graft_list(isl_stream *s); + #endif diff --git a/polly/lib/External/isl/isl_ast_node_set_field_templ.c b/polly/lib/External/isl/isl_ast_node_set_field_templ.c new file mode 100644 index 0000000..6eed55b --- /dev/null +++ b/polly/lib/External/isl/isl_ast_node_set_field_templ.c @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 + */ + +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* Replace the field FIELD of "node" by "field", + * where the field may or may not have already been set in "node". + * However, if the field has not already been set, + * then "node" is required to have a single reference. + * In this case the call to isl_ast_node_cow has no effect. + */ +__isl_give isl_ast_node *FN(FN(FN(isl_ast_node,NODE_TYPE),set),FIELD_NAME)( + __isl_take isl_ast_node *node, __isl_take FIELD_TYPE *field) +{ + if (FN(isl_ast_node_check,NODE_TYPE)(node) < 0 || !field) + goto error; + if (node->FIELD == field) { + FN(FIELD_TYPE,free)(field); + return node; + } + + node = isl_ast_node_cow(node); + if (!node) + goto error; + + FN(FIELD_TYPE,free)(node->FIELD); + node->FIELD = field; + + return node; +error: + isl_ast_node_free(node); + FN(FIELD_TYPE,free)(field); + return NULL; +} diff --git a/polly/lib/External/isl/isl_ast_private.h b/polly/lib/External/isl/isl_ast_private.h index a7726a2..8bff794 100644 --- a/polly/lib/External/isl/isl_ast_private.h +++ b/polly/lib/External/isl/isl_ast_private.h @@ -7,6 +7,12 @@ #include #include #include +#include + +#undef EL +#define EL isl_ast_expr + +#include /* An expression is either an integer, an identifier or an operation * with zero or more arguments. @@ -23,24 +29,22 @@ struct isl_ast_expr { isl_id *id; struct { enum isl_ast_expr_op_type op; - unsigned n_arg; - isl_ast_expr **args; + isl_ast_expr_list *args; } op; } u; }; -#undef EL -#define EL isl_ast_expr - -#include - __isl_give isl_ast_expr *isl_ast_expr_alloc_int_si(isl_ctx *ctx, int i); __isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, enum isl_ast_expr_op_type op, int n_arg); +__isl_give isl_ast_expr *isl_ast_expr_op_add_arg(__isl_take isl_ast_expr *expr, + __isl_take isl_ast_expr *arg); __isl_give isl_ast_expr *isl_ast_expr_alloc_binary( enum isl_ast_expr_op_type type, __isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2); +__isl_give isl_ast_expr *isl_stream_read_ast_expr(__isl_keep isl_stream *s); + #undef EL #define EL isl_ast_node @@ -96,11 +100,19 @@ __isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id, __isl_take isl_ast_node *node); __isl_give isl_ast_node *isl_ast_node_from_ast_node_list( __isl_take isl_ast_node_list *list); +__isl_give isl_ast_node *isl_ast_node_for_set_init( + __isl_take isl_ast_node *node, __isl_take isl_ast_expr *init); +__isl_give isl_ast_node *isl_ast_node_for_set_cond( + __isl_take isl_ast_node *node, __isl_take isl_ast_expr *init); +__isl_give isl_ast_node *isl_ast_node_for_set_inc( + __isl_take isl_ast_node *node, __isl_take isl_ast_expr *init); __isl_give isl_ast_node *isl_ast_node_for_set_body( __isl_take isl_ast_node *node, __isl_take isl_ast_node *body); __isl_give isl_ast_node *isl_ast_node_if_set_then( __isl_take isl_ast_node *node, __isl_take isl_ast_node *child); +__isl_give isl_ast_node *isl_stream_read_ast_node(__isl_keep isl_stream *s); + struct isl_ast_print_options { int ref; isl_ctx *ctx; diff --git a/polly/lib/External/isl/isl_box.c b/polly/lib/External/isl/isl_box.c index d4eb54f..34a49ea 100644 --- a/polly/lib/External/isl/isl_box.c +++ b/polly/lib/External/isl/isl_box.c @@ -409,6 +409,24 @@ __isl_give isl_fixed_box *isl_map_get_range_simple_fixed_box_hull( return box; } +/* Compute a fixed box from "set" using "map_box" by treating it as a map + * with a zero-dimensional domain and + * project out the domain again from the result. + */ +static __isl_give isl_fixed_box *fixed_box_as_map(__isl_keep isl_set *set, + __isl_give isl_fixed_box *(*map_box)(__isl_keep isl_map *map)) +{ + isl_map *map; + isl_fixed_box *box; + + map = isl_map_from_range(isl_set_copy(set)); + box = map_box(map); + isl_map_free(map); + box = isl_fixed_box_project_domain_on_params(box); + + return box; +} + /* Try and construct a fixed-size rectangular box with an offset * in terms of the parameters of "set" that contains "set". * If no such box can be constructed, then return an invalidated box, @@ -421,15 +439,7 @@ __isl_give isl_fixed_box *isl_map_get_range_simple_fixed_box_hull( __isl_give isl_fixed_box *isl_set_get_simple_fixed_box_hull( __isl_keep isl_set *set) { - isl_map *map; - isl_fixed_box *box; - - map = isl_map_from_range(isl_set_copy(set)); - box = isl_map_get_range_simple_fixed_box_hull(map); - isl_map_free(map); - box = isl_fixed_box_project_domain_on_params(box); - - return box; + return fixed_box_as_map(set, &isl_map_get_range_simple_fixed_box_hull); } /* Check whether the output elements lie on a rectangular lattice, @@ -474,6 +484,20 @@ __isl_give isl_fixed_box *isl_map_get_range_lattice_tile( return box; } +/* Check whether the elements lie on a rectangular lattice, + * possibly depending on the parameters. + * Return a tile in this lattice. + * If no stride information can be found, then return a tile of size 1 + * (and offset 0). + * + * Consider the set as a map with a zero-dimensional domain and + * obtain a lattice tile of that map. + */ +__isl_give isl_fixed_box *isl_set_get_lattice_tile(__isl_keep isl_set *set) +{ + return fixed_box_as_map(set, &isl_map_get_range_lattice_tile); +} + #undef BASE #define BASE multi_val #include "print_yaml_field_templ.c" diff --git a/polly/lib/External/isl/isl_coalesce.c b/polly/lib/External/isl/isl_coalesce.c index 910c214..5d0d173 100644 --- a/polly/lib/External/isl/isl_coalesce.c +++ b/polly/lib/External/isl/isl_coalesce.c @@ -1554,6 +1554,8 @@ static isl_stat add_selected_wraps_around_facet(struct isl_wraps *wraps, if (isl_tab_detect_redundant(info->tab) < 0) return isl_stat_error; if (info->tab->empty) { + if (isl_tab_rollback(info->tab, snap) < 0) + return isl_stat_error; if (!add_valid) return wraps_mark_failed(wraps); return isl_stat_ok; @@ -3178,7 +3180,7 @@ static isl_stat tab_insert_divs(struct isl_coalesce_info *info, return isl_stat_error; info->bmap = isl_basic_map_cow(info->bmap); info->bmap = isl_basic_map_free_inequality(info->bmap, 2 * n); - if (info->bmap < 0) + if (!info->bmap) return isl_stat_error; return fix_constant_divs(info, n, expanded); diff --git a/polly/lib/External/isl/isl_ctx.c b/polly/lib/External/isl/isl_ctx.c index 176fd6f..017e4af 100644 --- a/polly/lib/External/isl/isl_ctx.c +++ b/polly/lib/External/isl/isl_ctx.c @@ -291,7 +291,7 @@ void isl_ctx_free(struct isl_ctx *ctx) return; if (ctx->ref != 0) isl_die(ctx, isl_error_invalid, - "isl_ctx freed, but some objects still reference it", + "isl_ctx not freed as some objects still reference it", return); if (ctx->opt->print_stats) diff --git a/polly/lib/External/isl/isl_dim_map.c b/polly/lib/External/isl/isl_dim_map.c index b0b067d..3bace2c 100644 --- a/polly/lib/External/isl/isl_dim_map.c +++ b/polly/lib/External/isl/isl_dim_map.c @@ -243,7 +243,7 @@ __isl_give isl_dim_map *isl_dim_map_from_reordering( if (!dim_map) return NULL; - for (i = 0; i < exp->len; ++i) { + for (i = 0; i < exp->src_len; ++i) { dim_map->m[1 + exp->pos[i]].pos = 1 + i; dim_map->m[1 + exp->pos[i]].sgn = 1; } diff --git a/polly/lib/External/isl/isl_flow.c b/polly/lib/External/isl/isl_flow.c index 3be3ad5..c083a96 100644 --- a/polly/lib/External/isl/isl_flow.c +++ b/polly/lib/External/isl/isl_flow.c @@ -1873,6 +1873,12 @@ __isl_give char *isl_union_access_info_to_str( #define KEY_ERROR isl_ai_key_error #undef KEY_END #define KEY_END isl_ai_key_end +#undef KEY_STR +#define KEY_STR key_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_key +#undef KEY_GET +#define KEY_GET get_key #include "extract_key.c" #undef BASE @@ -1893,17 +1899,18 @@ __isl_give isl_union_access_info *isl_stream_read_union_access_info( { isl_ctx *ctx; isl_union_access_info *info; - int more; + isl_bool more; int sink_set = 0; int schedule_set = 0; - if (isl_stream_yaml_read_start_mapping(s)) + if (isl_stream_yaml_read_start_mapping(s) < 0) return NULL; ctx = isl_stream_get_ctx(s); info = isl_union_access_info_alloc(ctx); - while ((more = isl_stream_yaml_next(s)) > 0) { + while ((more = isl_stream_yaml_next(s)) == isl_bool_true) { enum isl_ai_key key; + enum isl_access_type type; isl_union_map *access, *schedule_map; isl_schedule *schedule; @@ -1919,8 +1926,9 @@ __isl_give isl_union_access_info *isl_stream_read_union_access_info( case isl_ai_key_must_source: case isl_ai_key_may_source: case isl_ai_key_kill: + type = (enum isl_access_type) key; access = read_union_map(s); - info = isl_union_access_info_set(info, key, access); + info = isl_union_access_info_set(info, type, access); if (!info) return NULL; break; @@ -1945,10 +1953,8 @@ __isl_give isl_union_access_info *isl_stream_read_union_access_info( if (more < 0) return isl_union_access_info_free(info); - if (isl_stream_yaml_read_end_mapping(s) < 0) { - isl_stream_error(s, NULL, "unexpected extra elements"); + if (isl_stream_yaml_read_end_mapping(s) < 0) return isl_union_access_info_free(info); - } if (!sink_set) { isl_stream_error(s, NULL, "no sink specified"); diff --git a/polly/lib/External/isl/isl_fold.c b/polly/lib/External/isl/isl_fold.c index 2d7f85c0..33ea278 100644 --- a/polly/lib/External/isl/isl_fold.c +++ b/polly/lib/External/isl/isl_fold.c @@ -951,7 +951,10 @@ static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_zero_in_space( #define DEFAULT_IS_ZERO 1 #include +#include #include +#include +#include #include #include #include @@ -961,8 +964,6 @@ static __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_zero_in_space( #undef BASE #define BASE pw_qpolynomial_fold -#define NO_SUB - #include #include diff --git a/polly/lib/External/isl/isl_from_range_templ.c b/polly/lib/External/isl/isl_from_range_templ.c new file mode 100644 index 0000000..08c640d --- /dev/null +++ b/polly/lib/External/isl/isl_from_range_templ.c @@ -0,0 +1,29 @@ +/* + * 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 + */ + +/* Convert an object defined over a parameter domain + * into one that is defined over a zero-dimensional set. + */ +__isl_give TYPE *FN(TYPE,from_range)(__isl_take TYPE *obj) +{ + isl_space *space; + + if (!obj) + return NULL; + if (!isl_space_is_set(FN(TYPE,peek_space)(obj))) + isl_die(FN(TYPE,get_ctx)(obj), isl_error_invalid, + "not living in a set space", + return FN(TYPE,free)(obj)); + + space = FN(TYPE,get_space)(obj); + space = isl_space_from_range(space); + obj = FN(TYPE,reset_space)(obj, space); + + return obj; +} diff --git a/polly/lib/External/isl/isl_hash.c b/polly/lib/External/isl/isl_hash.c index 59cb06e..d0f6564 100644 --- a/polly/lib/External/isl/isl_hash.c +++ b/polly/lib/External/isl/isl_hash.c @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include "isl_config.h" @@ -192,6 +192,26 @@ struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx, return &table->entries[h]; } +/* Return the first entry containing data in "table". + * Return isl_hash_table_entry_none is there is no such entry and + * NULL on error. + */ +struct isl_hash_table_entry *isl_hash_table_first(struct isl_hash_table *table) +{ + size_t size; + uint32_t h; + + if (!table->entries) + return NULL; + + size = 1 << table->bits; + for (h = 0; h < size; ++ h) + if (table->entries[h].data) + return &table->entries[h]; + + return isl_hash_table_entry_none; +} + isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table, isl_stat (*fn)(void **entry, void *user), void *user) { @@ -210,6 +230,31 @@ isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table, return isl_stat_ok; } +/* Does "test" succeed on every (non-empty) entry of "table"? + */ +isl_bool isl_hash_table_every(isl_ctx *ctx, struct isl_hash_table *table, + isl_bool (*test)(void **entry, void *user), void *user) +{ + size_t size; + uint32_t h; + + if (!table->entries) + return isl_bool_error; + + size = 1 << table->bits; + for (h = 0; h < size; ++ h) { + isl_bool r; + + if (!table->entries[h].data) + continue; + r = test(&table->entries[h].data, user); + if (r < 0 || !r) + return r; + } + + return isl_bool_true; +} + void isl_hash_table_remove(struct isl_ctx *ctx, struct isl_hash_table *table, struct isl_hash_table_entry *entry) diff --git a/polly/lib/External/isl/isl_hash_private.h b/polly/lib/External/isl/isl_hash_private.h new file mode 100644 index 0000000..bc5acb4 --- /dev/null +++ b/polly/lib/External/isl/isl_hash_private.h @@ -0,0 +1,8 @@ +#ifndef ISL_HASH_PRIVATE_H +#define ISL_HASH_PRIVATE_H + +#include + +struct isl_hash_table_entry *isl_hash_table_first(struct isl_hash_table *table); + +#endif diff --git a/polly/lib/External/isl/isl_id.c b/polly/lib/External/isl/isl_id.c index ab0f75b..d1f575e 100644 --- a/polly/lib/External/isl/isl_id.c +++ b/polly/lib/External/isl/isl_id.c @@ -191,6 +191,16 @@ __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, return id; } +/* Retrieve the callback set by isl_id_set_free_user, + * or NULL if no such callback was set. + */ +void (*isl_id_get_free_user(__isl_keep isl_id *id))(void *user) +{ + if (!id) + return NULL; + return id->free_user; +} + /* If the id has a negative refcount, then it is a static isl_id * and should not be freed. */ @@ -273,18 +283,9 @@ __isl_give isl_id *isl_stream_read_id(__isl_keep isl_stream *s) return id; } -/* Read an isl_id object from the string "str". - */ -__isl_give isl_id *isl_id_read_from_str(isl_ctx *ctx, const char *str) -{ - isl_id *id; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - id = isl_stream_read_id(s); - isl_stream_free(s); - return id; -} +#undef TYPE_BASE +#define TYPE_BASE id +#include "isl_read_from_str_templ.c" /* Is "id1" (obviously) equal to "id2"? * diff --git a/polly/lib/External/isl/isl_id_private.h b/polly/lib/External/isl/isl_id_private.h index 3b053e8..bcc2217 100644 --- a/polly/lib/External/isl/isl_id_private.h +++ b/polly/lib/External/isl/isl_id_private.h @@ -36,7 +36,6 @@ struct isl_id { uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id); int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2); -__isl_give isl_id *isl_stream_read_id(__isl_keep isl_stream *s); extern isl_id isl_id_none; diff --git a/polly/lib/External/isl/isl_id_to_ast_expr.c b/polly/lib/External/isl/isl_id_to_ast_expr.c index 4bfa953..5a41ab6 100644 --- a/polly/lib/External/isl/isl_id_to_ast_expr.c +++ b/polly/lib/External/isl/isl_id_to_ast_expr.c @@ -1,6 +1,7 @@ #include #include -#include + +#include "isl_ast_private.h" #define isl_id_is_equal(id1,id2) isl_bool_ok(id1 == id2) @@ -8,9 +9,13 @@ #define ISL_VAL isl_ast_expr #define ISL_HMAP_SUFFIX id_to_ast_expr #define ISL_HMAP isl_id_to_ast_expr +#define ISL_HMAP_IS_EQUAL isl_id_to_ast_expr_is_equal #define ISL_KEY_IS_EQUAL isl_id_is_equal #define ISL_VAL_IS_EQUAL isl_ast_expr_is_equal #define ISL_KEY_PRINT isl_printer_print_id #define ISL_VAL_PRINT isl_printer_print_ast_expr +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_KEY_READ isl_stream_read_id +#define ISL_VAL_READ isl_stream_read_ast_expr #include diff --git a/polly/lib/External/isl/isl_id_to_id.c b/polly/lib/External/isl/isl_id_to_id.c index e92e8f6..ca42f0d 100644 --- a/polly/lib/External/isl/isl_id_to_id.c +++ b/polly/lib/External/isl/isl_id_to_id.c @@ -8,9 +8,13 @@ #define ISL_VAL isl_id #define ISL_HMAP_SUFFIX id_to_id #define ISL_HMAP isl_id_to_id +#define ISL_HMAP_IS_EQUAL isl_id_to_id_is_equal #define ISL_KEY_IS_EQUAL isl_id_is_equal #define ISL_VAL_IS_EQUAL isl_id_is_equal #define ISL_KEY_PRINT isl_printer_print_id #define ISL_VAL_PRINT isl_printer_print_id +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_KEY_READ isl_stream_read_id +#define ISL_VAL_READ isl_stream_read_id #include diff --git a/polly/lib/External/isl/isl_id_to_pw_aff.c b/polly/lib/External/isl/isl_id_to_pw_aff.c index 1ef27b5..fcfa8c1 100644 --- a/polly/lib/External/isl/isl_id_to_pw_aff.c +++ b/polly/lib/External/isl/isl_id_to_pw_aff.c @@ -1,6 +1,7 @@ #include #include -#include + +#include "isl_aff_private.h" #define isl_id_is_equal(id1,id2) isl_bool_ok(id1 == id2) @@ -8,9 +9,13 @@ #define ISL_VAL isl_pw_aff #define ISL_HMAP_SUFFIX id_to_pw_aff #define ISL_HMAP isl_id_to_pw_aff +#define ISL_HMAP_IS_EQUAL isl_id_to_pw_aff_plain_is_equal #define ISL_KEY_IS_EQUAL isl_id_is_equal #define ISL_VAL_IS_EQUAL isl_pw_aff_plain_is_equal #define ISL_KEY_PRINT isl_printer_print_id #define ISL_VAL_PRINT isl_printer_print_pw_aff +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_KEY_READ isl_stream_read_id +#define ISL_VAL_READ isl_stream_read_pw_aff #include diff --git a/polly/lib/External/isl/isl_ilp.c b/polly/lib/External/isl/isl_ilp.c index fe623ba..2c004ef 100644 --- a/polly/lib/External/isl/isl_ilp.c +++ b/polly/lib/External/isl/isl_ilp.c @@ -696,6 +696,10 @@ static __isl_give isl_val *isl_pw_aff_opt_val(__isl_take isl_pw_aff *pa, } #undef TYPE +#define TYPE isl_pw_aff +#include "isl_ilp_opt_fn_val_templ.c" + +#undef TYPE #define TYPE isl_pw_multi_aff #include "isl_ilp_opt_multi_val_templ.c" @@ -752,27 +756,9 @@ static __isl_give isl_val *isl_union_pw_aff_opt_val( return data.res; } -/* Return the minimum of the integer piecewise affine - * expression "upa" over its definition domain. - * - * Return negative infinity if the optimal value is unbounded and - * NaN if the domain of the expression is empty. - */ -__isl_give isl_val *isl_union_pw_aff_min_val(__isl_take isl_union_pw_aff *upa) -{ - return isl_union_pw_aff_opt_val(upa, 0); -} - -/* Return the maximum of the integer piecewise affine - * expression "upa" over its definition domain. - * - * Return infinity if the optimal value is unbounded and - * NaN if the domain of the expression is empty. - */ -__isl_give isl_val *isl_union_pw_aff_max_val(__isl_take isl_union_pw_aff *upa) -{ - return isl_union_pw_aff_opt_val(upa, 1); -} +#undef TYPE +#define TYPE isl_union_pw_aff +#include "isl_ilp_opt_fn_val_templ.c" /* Return a list of minima (maxima if "max" is set) * for each of the expressions in "mupa" over their domains. diff --git a/polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c b/polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c new file mode 100644 index 0000000..6b2c532 --- /dev/null +++ b/polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c @@ -0,0 +1,32 @@ +/* + * Copyright 2018 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* Return the minimum of the integer piecewise affine + * expression "f" over its definition domain. + * + * Return negative infinity if the optimal value is unbounded and + * NaN if the domain of the expression is empty. + */ +__isl_give isl_val *FN(TYPE,min_val)(__isl_take TYPE *f) +{ + return FN(TYPE,opt_val)(f, 0); +} + +/* Return the maximum of the integer piecewise affine + * expression "f" over its definition domain. + * + * Return infinity if the optimal value is unbounded and + * NaN if the domain of the expression is empty. + */ +__isl_give isl_val *FN(TYPE,max_val)(__isl_take TYPE *f) +{ + return FN(TYPE,opt_val)(f, 1); +} diff --git a/polly/lib/External/isl/isl_input.c b/polly/lib/External/isl/isl_input.c index 4c6839d..e289d74 100644 --- a/polly/lib/External/isl/isl_input.c +++ b/polly/lib/External/isl/isl_input.c @@ -2,7 +2,7 @@ * Copyright 2008-2009 Katholieke Universiteit Leuven * Copyright 2010 INRIA Saclay * Copyright 2012-2013 Ecole Normale Superieure - * Copyright 2019 Cerebras Systems + * Copyright 2019,2022 Cerebras Systems * * Use of this software is governed by the MIT license * @@ -182,7 +182,9 @@ error: * "-" "infty" -> -infty * "NaN" -> NaN * n "/" d -> n/d + * "-" n "/" d -> -n/d * v -> v + * "-" v -> -v * * where n, d and v are integer constants. */ @@ -190,8 +192,11 @@ __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s) { struct isl_token *tok = NULL; struct isl_token *tok2 = NULL; + int sign = 1; isl_val *val; + if (isl_stream_eat_if_available(s, '-')) + sign = -1; tok = next_token(s); if (!tok) { isl_stream_error(s, NULL, "unexpected EOF"); @@ -199,14 +204,12 @@ __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s) } if (tok->type == ISL_TOKEN_INFTY) { isl_token_free(tok); - return isl_val_infty(s->ctx); - } - if (tok->type == '-' && - isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) { - isl_token_free(tok); - return isl_val_neginfty(s->ctx); + if (sign > 0) + return isl_val_infty(s->ctx); + else + return isl_val_neginfty(s->ctx); } - if (tok->type == ISL_TOKEN_NAN) { + if (sign > 0 && tok->type == ISL_TOKEN_NAN) { isl_token_free(tok); return isl_val_nan(s->ctx); } @@ -215,6 +218,9 @@ __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s) goto error; } + if (sign < 0) + isl_int_neg(tok->u.v, tok->u.v); + if (isl_stream_eat_if_available(s, '/')) { tok2 = next_token(s); if (!tok2) { @@ -240,46 +246,16 @@ error: return NULL; } -/* Read an isl_val from "str". - */ -__isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str) -{ - isl_val *val; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - val = isl_stream_read_val(s); - isl_stream_free(s); - return val; -} - -/* Perform an integer division on *f and - * an integer value read from the stream. - */ -static isl_stat int_div_by_cst(__isl_keep isl_stream *s, isl_int *f) -{ - struct isl_token *tok; - - tok = next_token(s); - if (!tok || tok->type != ISL_TOKEN_VALUE) { - isl_stream_error(s, tok, "expecting constant value"); - goto error; - } - - isl_int_fdiv_q(*f, *f, tok->u.v); - - isl_token_free(tok); - - return isl_stat_ok; -error: - isl_token_free(tok); - return isl_stat_error; -} +#undef TYPE_BASE +#define TYPE_BASE val +#include "isl_read_from_str_templ.c" static isl_stat accept_cst_factor(__isl_keep isl_stream *s, isl_int *f) { struct isl_token *tok; + if (isl_stream_eat_if_available(s, '-')) + isl_int_neg(*f, *f); tok = next_token(s); if (!tok || tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting constant value"); @@ -369,6 +345,68 @@ error: return NULL; } +/* Divide "pa" by an integer constant read from the stream. + */ +static __isl_give isl_pw_aff *pw_aff_div_by_cst(__isl_keep isl_stream *s, + __isl_take isl_pw_aff *pa) +{ + struct isl_token *tok; + + tok = next_token(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, "expecting denominator"); + isl_token_free(tok); + return isl_pw_aff_free(pa); + } + + pa = isl_pw_aff_scale_down(pa, tok->u.v); + + isl_token_free(tok); + + return pa; +} + +/* Return the (signed) value that is next on the stream, + * using "next" to read the next token and printing "msg" in case of an error. + */ +static struct isl_token *next_signed_value_fn(__isl_keep isl_stream *s, + struct isl_token *(*next)(__isl_keep isl_stream *s), char *msg) +{ + struct isl_token *tok; + int sign = 1; + + if (isl_stream_eat_if_available(s, '-')) + sign = -1; + tok = next(s); + if (!tok || tok->type != ISL_TOKEN_VALUE) { + isl_stream_error(s, tok, msg); + isl_token_free(tok); + return NULL; + } + if (sign < 0) + isl_int_neg(tok->u.v, tok->u.v); + return tok; +} + +/* Return the (signed) value that is next on the stream, + * printing "msg" in case of an error. + */ +static struct isl_token *next_signed_value(__isl_keep isl_stream *s, char *msg) +{ + return next_signed_value_fn(s, &isl_stream_next_token, msg); +} + +/* Return the (signed) value that is next on the stream, + * provided it is on the same line, + * printing "msg" in case of an error. + */ +static struct isl_token *next_signed_value_on_same_line( + __isl_keep isl_stream *s, char *msg) +{ + return next_signed_value_fn(s, + &isl_stream_next_token_on_same_line, msg); +} + /* Is "tok" the start of an integer division? */ static int is_start_of_div(struct isl_token *tok) @@ -401,7 +439,6 @@ static int is_start_of_div(struct isl_token *tok) static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s, __isl_take isl_space *space, struct vars *v) { - struct isl_token *tok; int f = 0; int c = 0; int extra = 0; @@ -429,16 +466,7 @@ static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s, if (isl_stream_eat(s, ',')) goto error; - tok = next_token(s); - if (!tok) - goto error; - if (tok->type != ISL_TOKEN_VALUE) { - isl_stream_error(s, tok, "expected denominator"); - isl_stream_push_token(s, tok); - goto error; - } - pwaff = isl_pw_aff_scale_down(pwaff, tok->u.v); - isl_token_free(tok); + pwaff = pw_aff_div_by_cst(s, pwaff); } if (c) @@ -462,22 +490,6 @@ error: return NULL; } -/* Divide "pa" by an integer constant read from the stream. - */ -static __isl_give isl_pw_aff *pw_aff_div_by_cst(__isl_keep isl_stream *s, - __isl_take isl_pw_aff *pa) -{ - isl_int f; - isl_int_init(f); - isl_int_set_si(f, 1); - if (accept_cst_factor(s, &f) < 0) - pa = isl_pw_aff_free(pa); - pa = isl_pw_aff_scale_down(pa, f); - isl_int_clear(f); - - return pa; -} - static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s, __isl_take isl_space *space, struct vars *v) { @@ -515,7 +527,10 @@ static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s, res = isl_pw_aff_from_aff(aff); isl_token_free(tok); } else if (tok->type == ISL_TOKEN_VALUE) { - if (isl_stream_eat_if_available(s, '*')) { + if (isl_stream_eat_if_available(s, '*') || + isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) { + if (isl_stream_eat_if_available(s, '-')) + isl_int_neg(tok->u.v, tok->u.v); res = accept_affine_factor(s, isl_space_copy(space), v); res = isl_pw_aff_scale(res, tok->u.v); } else { @@ -578,18 +593,6 @@ error2: return NULL; } -static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v) -{ - isl_aff *aff; - isl_space *space; - - space = isl_pw_aff_get_domain_space(pwaff); - aff = isl_aff_zero_on_domain(isl_local_space_from_space(space)); - aff = isl_aff_add_constant(aff, v); - - return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff)); -} - /* Return a piecewise affine expression defined on the specified domain * that represents NaN. */ @@ -604,6 +607,7 @@ static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, struct isl_token *tok = NULL; isl_local_space *ls; isl_pw_aff *res; + int op = 1; int sign = 1; ls = isl_local_space_from_space(isl_space_copy(space)); @@ -625,39 +629,23 @@ static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, if (tok->type == '(' || is_start_of_div(tok) || tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX || tok->type == ISL_TOKEN_IDENT || + tok->type == ISL_TOKEN_VALUE || tok->type == ISL_TOKEN_AFF) { isl_pw_aff *term; + if (tok->type == ISL_TOKEN_VALUE && sign < 0) { + isl_int_neg(tok->u.v, tok->u.v); + sign = 1; + } isl_stream_push_token(s, tok); tok = NULL; term = accept_affine_factor(s, isl_space_copy(space), v); - if (sign < 0) + if (op * sign < 0) res = isl_pw_aff_sub(res, term); else res = isl_pw_aff_add(res, term); if (!res) goto error; - sign = 1; - } else if (tok->type == ISL_TOKEN_VALUE) { - if (sign < 0) - isl_int_neg(tok->u.v, tok->u.v); - if (isl_stream_eat_if_available(s, '*') || - isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) { - isl_pw_aff *term; - term = accept_affine_factor(s, - isl_space_copy(space), v); - term = isl_pw_aff_scale(term, tok->u.v); - res = isl_pw_aff_add(res, term); - if (!res) - goto error; - } else { - if (isl_stream_eat_if_available(s, - ISL_TOKEN_INT_DIV) && - int_div_by_cst(s, &tok->u.v) < 0) - goto error; - res = add_cst(res, tok->u.v); - } - sign = 1; } else if (tok->type == ISL_TOKEN_NAN) { res = isl_pw_aff_add(res, nan_on_domain(space)); } else { @@ -670,15 +658,13 @@ static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s, isl_token_free(tok); tok = next_token(s); + sign = 1; if (tok && tok->type == '-') { - sign = -sign; + op = -1; isl_token_free(tok); } else if (tok && tok->type == '+') { - /* nothing */ + op = 1; isl_token_free(tok); - } else if (tok && tok->type == ISL_TOKEN_VALUE && - isl_int_is_neg(tok->u.v)) { - isl_stream_push_token(s, tok); } else { if (tok) isl_stream_push_token(s, tok); @@ -1094,6 +1080,20 @@ static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space, return space; } +/* Set the name of the last (output) dimension of "space" to "name", + * ignoring any primes in "name". + */ +static __isl_give isl_space *space_set_last_dim_name( + __isl_take isl_space *space, char *name) +{ + isl_size pos; + + pos = isl_space_dim(space, isl_dim_out); + if (pos < 0) + return isl_space_free(space); + return space_set_dim_name(space, pos - 1, name); +} + /* Construct an isl_pw_aff defined on a "space" (with v->n variables) * that is equal to the last of those variables. */ @@ -1354,12 +1354,12 @@ static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s, pa = accept_extended_affine(s, isl_space_copy(space), v, rational); } - if (isl_stream_eat_if_available(s, ':')) + if (pa && isl_stream_eat_if_available(s, ':')) pa = update_piecewise_affine_colon(pa, s, v, rational); res = isl_pw_aff_union_add(res, pa); - if (seen_paren && isl_stream_eat(s, ')')) + if (!res || (seen_paren && isl_stream_eat(s, ')'))) goto error; } while (isl_stream_eat_if_available(s, ';')); @@ -1477,7 +1477,7 @@ static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s, } else res = read_tuple_list(s, v, isl_space_copy(space), rational, comma, read_el, user); - if (isl_stream_eat(s, ']')) + if (!res || isl_stream_eat(s, ']')) goto error; if (name) { @@ -1543,11 +1543,7 @@ static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s, isl_token_free(tok); pa = identity_tuple_el(v); } else if (new_name) { - isl_size pos = isl_space_dim(space, isl_dim_out); - if (pos < 0) - goto error; - pos -= 1; - space = space_set_dim_name(space, pos, v->v->name); + space = space_set_last_dim_name(space, v->v->name); isl_token_free(tok); if (isl_stream_eat_if_available(s, '=')) pa = read_tuple_var_def(s, v, rational); @@ -1719,6 +1715,151 @@ static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s, return map_from_tuple(tuple, map, type, v, rational); } +/* Read the parameter domain of an expression from "s" (if any) and + * check that it does not involve any constraints. + * "v" contains a description of the identifiers parsed so far + * (of which there should not be any at this point) and is extended + * by this function. + */ +static __isl_give isl_set *read_universe_params(__isl_keep isl_stream *s, + struct vars *v) +{ + isl_set *dom; + + 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)) + return isl_set_free(dom); + } + if (!isl_set_plain_is_universe(dom)) + isl_die(s->ctx, isl_error_invalid, + "expecting universe parameter domain", + return isl_set_free(dom)); + + return dom; +} + +/* Read the parameter domain of an expression from "s" (if any), + * check that it does not involve any constraints and return its space. + * "v" contains a description of the identifiers parsed so far + * (of which there should not be any at this point) and is extended + * by this function. + */ +static __isl_give isl_space *read_params(__isl_keep isl_stream *s, + struct vars *v) +{ + isl_space *space; + isl_set *set; + + set = read_universe_params(s, v); + space = isl_set_get_space(set); + isl_set_free(set); + + return space; +} + +/* This function is called for each element in a tuple inside read_space_tuples. + * Add a new variable to "v" and adjust "space" accordingly + * if the variable has a name. + */ +static __isl_give isl_space *read_tuple_id(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *space, int rational, void *user) +{ + struct isl_token *tok; + + 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; + if (p < n) { + isl_stream_error(s, tok, "expecting fresh identifier"); + goto error; + } + space = space_set_last_dim_name(space, v->v->name); + } else if (tok->type == '*') { + if (vars_add_anon(v) < 0) + goto error; + } else { + isl_stream_error(s, tok, "expecting identifier or '*'"); + goto error; + } + + isl_token_free(tok); + return space; +error: + isl_token_free(tok); + return isl_space_free(space); +} + +/* Given a parameter space "params", extend it with one or two tuples + * read from "s". + * "v" contains a description of the identifiers parsed so far and is extended + * by this function. + */ +static __isl_give isl_space *read_space_tuples(__isl_keep isl_stream *s, + struct vars *v, __isl_take isl_space *params) +{ + isl_space *space, *ran; + + space = read_tuple_space(s, v, isl_space_copy(params), 1, 1, + &read_tuple_id, NULL); + if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { + ran = read_tuple_space(s, v, isl_space_copy(params), 1, 1, + &read_tuple_id, NULL); + space = isl_space_unwrap(isl_space_product(space, ran)); + } + isl_space_free(params); + + return space; +} + +/* Read an isl_space object from "s". + * + * First read the parameters (if any). + * + * Then check if the description is of the special form "{ : }", + * in which case it represents a parameter space. + * Otherwise, it has one or two tuples. + */ +__isl_give isl_space *isl_stream_read_space(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_space *space; + + v = vars_new(s->ctx); + if (!v) + return NULL; + space = read_params(s, v); + + if (isl_stream_eat(s, '{')) + goto error; + + if (!isl_stream_eat_if_available(s, ':')) + space = read_space_tuples(s, v, space); + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + return space; +error: + vars_free(v); + isl_space_free(space); + return NULL; +} + +#undef TYPE_BASE +#define TYPE_BASE space +#include "isl_read_from_str_templ.c" + /* Given two equal-length lists of piecewise affine expression with the space * of "set" as domain, construct a set in the same space that expresses * that "left" and "right" satisfy the comparison "type". @@ -2168,13 +2309,12 @@ static __isl_give isl_basic_map *basic_map_read_polylib_constraint( tok = isl_stream_next_token(s); if (!tok || tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting coefficient"); - if (tok) - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } if (!tok->on_new_line) { isl_stream_error(s, tok, "coefficient should appear on new line"); - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } @@ -2197,19 +2337,10 @@ static __isl_give isl_basic_map *basic_map_read_polylib_constraint( return isl_basic_map_free(bmap); for (j = 0; j < 1 + total; ++j) { isl_size pos; - tok = isl_stream_next_token(s); - if (!tok || tok->type != ISL_TOKEN_VALUE) { - isl_stream_error(s, tok, "expecting coefficient"); - if (tok) - isl_stream_push_token(s, tok); - goto error; - } - if (tok->on_new_line) { - isl_stream_error(s, tok, - "coefficient should not appear on new line"); - isl_stream_push_token(s, tok); + tok = next_signed_value_on_same_line(s, + "expecting coefficient on same line"); + if (!tok) goto error; - } pos = polylib_pos_to_isl_pos(bmap, j); if (pos >= 0) isl_int_set(c[pos], tok->u.v); @@ -2248,8 +2379,8 @@ static __isl_give isl_basic_map *basic_map_read_polylib( return NULL; } if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) { - isl_stream_push_token(s, tok2); - isl_stream_push_token(s, tok); + isl_token_free(tok2); + isl_token_free(tok); isl_stream_error(s, NULL, "expecting constraint matrix dimensions"); return NULL; @@ -2267,7 +2398,7 @@ static __isl_give isl_basic_map *basic_map_read_polylib( if (tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting number of output dimensions"); - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } out = isl_int_get_si(tok->u.v); @@ -2277,8 +2408,7 @@ static __isl_give isl_basic_map *basic_map_read_polylib( if (!tok || tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting number of input dimensions"); - if (tok) - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } in = isl_int_get_si(tok->u.v); @@ -2288,8 +2418,7 @@ static __isl_give isl_basic_map *basic_map_read_polylib( if (!tok || tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting number of existentials"); - if (tok) - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } local = isl_int_get_si(tok->u.v); @@ -2299,8 +2428,7 @@ static __isl_give isl_basic_map *basic_map_read_polylib( if (!tok || tok->type != ISL_TOKEN_VALUE) { isl_stream_error(s, tok, "expecting number of parameters"); - if (tok) - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } nparam = isl_int_get_si(tok->u.v); @@ -2326,10 +2454,13 @@ static __isl_give isl_basic_map *basic_map_read_polylib( for (i = 0; i < n_row; ++i) bmap = basic_map_read_polylib_constraint(s, bmap); + if (!bmap) + return NULL; + tok = isl_stream_next_token_on_same_line(s); if (tok) { isl_stream_error(s, tok, "unexpected extra token on line"); - isl_stream_push_token(s, tok); + isl_token_free(tok); goto error; } @@ -2540,13 +2671,6 @@ static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s, isl_token_free(tok); pwqp2 = read_factor(s, map, v); pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2); - } else if (tok->type == ISL_TOKEN_VALUE && - isl_int_is_neg(tok->u.v)) { - isl_pw_qpolynomial *pwqp2; - - isl_stream_push_token(s, tok); - pwqp2 = read_factor(s, map, v); - pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2); } else { isl_stream_push_token(s, tok); break; @@ -3107,7 +3231,8 @@ __isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s) return extract_union_set(s->ctx, obj); } -static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s) +static __isl_give isl_basic_map *isl_stream_read_basic_map( + __isl_keep isl_stream *s) { struct isl_obj obj; struct isl_map *map; @@ -3139,10 +3264,12 @@ error: return NULL; } -static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s) +/* Read an isl_basic_set object from "s". + */ +__isl_give isl_basic_set *isl_stream_read_basic_set(__isl_keep isl_stream *s) { isl_basic_map *bmap; - bmap = basic_map_read(s); + bmap = isl_stream_read_basic_map(s); if (!bmap) return NULL; if (!isl_basic_map_may_be_set(bmap)) @@ -3161,7 +3288,7 @@ __isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx, isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; - bmap = basic_map_read(s); + bmap = isl_stream_read_basic_map(s); isl_stream_free(s); return bmap; } @@ -3173,34 +3300,18 @@ __isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx, isl_stream *s = isl_stream_new_file(ctx, input); if (!s) return NULL; - bset = basic_set_read(s); + bset = isl_stream_read_basic_set(s); isl_stream_free(s); return bset; } -__isl_give isl_basic_map *isl_basic_map_read_from_str(isl_ctx *ctx, - const char *str) -{ - struct isl_basic_map *bmap; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - bmap = basic_map_read(s); - isl_stream_free(s); - return bmap; -} +#undef TYPE_BASE +#define TYPE_BASE basic_map +#include "isl_read_from_str_templ.c" -__isl_give isl_basic_set *isl_basic_set_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_basic_set *bset; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - bset = basic_set_read(s); - isl_stream_free(s); - return bset; -} +#undef TYPE_BASE +#define TYPE_BASE basic_set +#include "isl_read_from_str_templ.c" __isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx, FILE *input) @@ -3214,17 +3325,9 @@ __isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx, return map; } -__isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx, - const char *str) -{ - struct isl_map *map; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - map = isl_stream_read_map(s); - isl_stream_free(s); - return map; -} +#undef TYPE_BASE +#define TYPE_BASE map +#include "isl_read_from_str_templ.c" __isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx, FILE *input) @@ -3238,16 +3341,9 @@ __isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx, return set; } -__isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, const char *str) -{ - isl_set *set; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - set = isl_stream_read_set(s); - isl_stream_free(s); - return set; -} +#undef TYPE_BASE +#define TYPE_BASE set +#include "isl_read_from_str_templ.c" __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, FILE *input) @@ -3261,17 +3357,9 @@ __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx, return umap; } -__isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx, - const char *str) -{ - isl_union_map *umap; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - umap = isl_stream_read_union_map(s); - isl_stream_free(s); - return umap; -} +#undef TYPE_BASE +#define TYPE_BASE union_map +#include "isl_read_from_str_templ.c" __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx, FILE *input) @@ -3285,17 +3373,9 @@ __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx, return uset; } -__isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx, - const char *str) -{ - isl_union_set *uset; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - uset = isl_stream_read_union_set(s); - isl_stream_free(s); - return uset; -} +#undef TYPE_BASE +#define TYPE_BASE union_set +#include "isl_read_from_str_templ.c" static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s) { @@ -3316,11 +3396,9 @@ static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s) vec = isl_vec_alloc(s->ctx, size); for (j = 0; j < size; ++j) { - tok = isl_stream_next_token(s); - if (!tok || tok->type != ISL_TOKEN_VALUE) { - isl_stream_error(s, tok, "expecting constant value"); + tok = next_signed_value(s, "expecting constant value"); + if (!tok) goto error; - } isl_int_set(vec->el[j], tok->u.v); isl_token_free(tok); } @@ -3364,17 +3442,9 @@ error: return NULL; } -__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_pw_qpolynomial *pwqp; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - pwqp = isl_stream_read_pw_qpolynomial(s); - isl_stream_free(s); - return pwqp; -} +#undef TYPE_BASE +#define TYPE_BASE pw_qpolynomial +#include "isl_read_from_str_templ.c" __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx, FILE *input) @@ -3407,22 +3477,9 @@ error: return NULL; } -/* Read an isl_pw_qpolynomial_fold from "str". - */ -__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_read_from_str( - isl_ctx *ctx, const char *str) -{ - isl_pw_qpolynomial_fold *pwqp; - isl_stream *s; - - s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - pwqp = isl_stream_read_pw_qpolynomial_fold(s); - isl_stream_free(s); - - return pwqp; -} +#undef TYPE_BASE +#define TYPE_BASE pw_qpolynomial_fold +#include "isl_read_from_str_templ.c" /* Is the next token an identifier not in "v"? */ @@ -3541,156 +3598,124 @@ error: return NULL; } -__isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s) +/* Read an affine expression, together with optional constraints + * on the domain from "s". "dom" represents the initial constraints + * on the parameter domain. + * "v" contains a description of the identifiers parsed so far. + */ +static __isl_give isl_pw_aff *read_conditional_aff(__isl_keep isl_stream *s, + __isl_take isl_set *dom, struct vars *v) { - struct vars *v; - isl_set *dom = NULL; isl_set *aff_dom; - isl_pw_aff *pa = NULL; + isl_pw_aff *pa; int n; - 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_stream_eat(s, '{')) - goto error; - n = v->n; - aff_dom = read_aff_domain(s, isl_set_copy(dom), v); + aff_dom = read_aff_domain(s, dom, v); pa = read_pw_aff_with_dom(s, aff_dom, v); vars_drop(v, v->n - n); - while (isl_stream_eat_if_available(s, ';')) { - isl_pw_aff *pa_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); - - pa = isl_pw_aff_union_add(pa, pa_i); - } - - if (isl_stream_eat(s, '}')) - goto error; - - vars_free(v); - isl_set_free(dom); return pa; -error: - vars_free(v); - isl_set_free(dom); - isl_pw_aff_free(pa); - return NULL; } -__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str) +#undef BASE +#define BASE aff +#include "isl_stream_read_pw_with_params_templ.c" + +#undef TYPE_BASE +#define TYPE_BASE aff +#include "isl_read_from_str_templ.c" + +#undef TYPE_BASE +#define TYPE_BASE pw_aff +#include "isl_stream_read_with_params_templ.c" +#include "isl_read_from_str_templ.c" + +/* Given that "pa" is the element at position "pos" of a tuple + * returned by read_tuple, check that it does not involve any + * output/set dimensions (appearing at the "n" positions starting at "first"), + * remove those from the domain and replace the domain space + * with "domain_space". + * + * In particular, the result of read_tuple is of the form + * [input, output] -> [output], with anonymous domain. + * The function read_tuple accepts tuples where some output or + * set dimensions are defined in terms of other output or set dimensions + * since this function is also used to read maps. As a special case, + * read_tuple also accepts dimensions that are defined in terms of themselves + * (i.e., that are not defined). + * These cases are not allowed here. + */ +static __isl_give isl_pw_aff *separate_tuple_entry(__isl_take isl_pw_aff *pa, + int pos, unsigned first, unsigned n, __isl_take isl_space *domain_space) { - isl_aff *aff; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - aff = isl_stream_read_aff(s); - isl_stream_free(s); - return aff; -} + isl_bool involves; + + involves = isl_pw_aff_involves_dims(pa, isl_dim_in, first, pos + 1); + if (involves < 0) { + pa = isl_pw_aff_free(pa); + } else if (involves) { + isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, + "not an affine expression", + pa = isl_pw_aff_free(pa)); + } + pa = isl_pw_aff_drop_dims(pa, isl_dim_in, first, n); + pa = isl_pw_aff_reset_domain_space(pa, domain_space); -__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str) -{ - isl_pw_aff *pa; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - pa = isl_stream_read_pw_aff(s); - isl_stream_free(s); return pa; } -/* Extract an isl_multi_pw_aff with domain space "dom_space" - * from a tuple "tuple" read by read_tuple. +/* Set entry "pos" of "mpa" to the corresponding entry in "tuple", + * as obtained from read_tuple(). + * The "n" output dimensions also appear among the input dimensions + * at position "first". * - * Note that the function read_tuple accepts tuples where some output or - * set dimensions are defined in terms of other output or set dimensions - * since this function is also used to read maps. As a special case, - * read_tuple also accept dimensions that are defined in terms of themselves - * (i.e., that are not defined). - * These cases are not allowed when extracting an isl_multi_pw_aff so check - * that the definitions of the output/set dimensions do not involve any - * output/set dimensions. - * Finally, drop the output dimensions from the domain of the result - * of read_tuple (which is of the form [input, output] -> [output], - * with anonymous domain) and reset the space. + * The entry is not allowed to depend on any (other) output dimensions. */ -static __isl_give isl_multi_pw_aff *extract_mpa_from_tuple( - __isl_take isl_space *dom_space, __isl_keep isl_multi_pw_aff *tuple) +static __isl_give isl_multi_pw_aff *isl_multi_pw_aff_set_tuple_entry( + __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *tuple_el, + int pos, unsigned first, unsigned n) { - int i; - isl_size dim, n; isl_space *space; - isl_multi_pw_aff *mpa; + isl_pw_aff *pa; - n = isl_multi_pw_aff_dim(tuple, isl_dim_out); - dim = isl_space_dim(dom_space, isl_dim_all); - if (n < 0 || dim < 0) - dom_space = isl_space_free(dom_space); - space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); - space = isl_space_align_params(space, isl_space_copy(dom_space)); - if (!isl_space_is_params(dom_space)) - space = isl_space_map_from_domain_and_range( - isl_space_copy(dom_space), space); - isl_space_free(dom_space); - mpa = isl_multi_pw_aff_alloc(space); + space = isl_multi_pw_aff_get_domain_space(mpa); + pa = separate_tuple_entry(tuple_el, pos, first, n, space); + return isl_multi_pw_aff_set_pw_aff(mpa, pos, pa); +} - for (i = 0; i < n; ++i) { - isl_pw_aff *pa; - pa = isl_multi_pw_aff_get_pw_aff(tuple, i); - if (!pa) - return isl_multi_pw_aff_free(mpa); - if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) { - isl_ctx *ctx = isl_pw_aff_get_ctx(pa); - isl_pw_aff_free(pa); - isl_die(ctx, isl_error_invalid, - "not an affine expression", - return isl_multi_pw_aff_free(mpa)); - } - pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n); - space = isl_multi_pw_aff_get_domain_space(mpa); - pa = isl_pw_aff_reset_domain_space(pa, space); - mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa); - } +#undef BASE +#define BASE pw_aff - return mpa; -} +#include -/* Read a tuple of affine expressions, together with optional constraints - * on the domain from "s". "dom" represents the initial constraints - * on the domain. +/* Read a tuple of piecewise affine expressions, + * including optional constraints on the domain from "s". + * "dom" represents the initial constraints on the domain. + * + * The input format is similar to that of a map, except that any conditions + * on the domains should be specified inside the tuple since each + * piecewise affine expression may have a different domain. + * However, additional, shared conditions can also be specified. + * This is especially useful for setting the explicit domain + * of a zero-dimensional isl_multi_pw_aff. * - * The isl_multi_aff may live in either a set or a map space. + * The isl_multi_pw_aff may live in either a set or a map space. * First read the first tuple and check if it is followed by a "->". * If so, convert the tuple into the domain of the isl_multi_pw_aff and * read in the next tuple. This tuple (or the first tuple if it was * not followed by a "->") is then converted into an isl_multi_pw_aff - * through a call to extract_mpa_from_tuple. - * The result is converted to an isl_pw_multi_aff and - * its domain is intersected with the domain. + * through a call to isl_multi_pw_aff_from_tuple. + * The domain of the result is intersected with the domain. * * Note that the last tuple may introduce new identifiers, * but these cannot be referenced in the description of the domain. */ -static __isl_give isl_pw_multi_aff *read_conditional_multi_aff( +static __isl_give isl_multi_pw_aff *read_conditional_multi_pw_aff( __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) { isl_multi_pw_aff *tuple; isl_multi_pw_aff *mpa; - isl_pw_multi_aff *pma; int n = v->n; int n_dom; @@ -3706,8 +3731,7 @@ static __isl_give isl_pw_multi_aff *read_conditional_multi_aff( if (!tuple) goto error; } - mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple); - isl_multi_pw_aff_free(tuple); + mpa = isl_multi_pw_aff_from_tuple(isl_set_get_space(dom), tuple); if (!mpa) dom = isl_set_free(dom); @@ -3716,40 +3740,42 @@ static __isl_give isl_pw_multi_aff *read_conditional_multi_aff( vars_drop(v, v->n - n); - pma = isl_pw_multi_aff_from_multi_pw_aff(mpa); - pma = isl_pw_multi_aff_intersect_domain(pma, dom); + mpa = isl_multi_pw_aff_intersect_domain(mpa, dom); - return pma; + return mpa; error: isl_set_free(dom); return NULL; } -/* Read an isl_union_pw_multi_aff from "s". +/* Read a tuple of affine expressions, together with optional constraints + * on the domain from "s". "dom" represents the initial constraints + * on the domain. * - * In particular, first read the parameters and then read a sequence - * of zero or more tuples of affine expressions with optional conditions and - * add them up. + * Read a tuple of piecewise affine expressions with optional constraints and + * convert the result to an isl_pw_multi_aff on the shared domain. */ -__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff( - __isl_keep isl_stream *s) +static __isl_give isl_pw_multi_aff *read_conditional_multi_aff( + __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v) { - struct vars *v; - isl_set *dom; - isl_union_pw_multi_aff *upma = NULL; + isl_multi_pw_aff *mpa; - v = vars_new(s->ctx); - if (!v) - return NULL; + mpa = read_conditional_multi_pw_aff(s, dom, v); + return isl_pw_multi_aff_from_multi_pw_aff(mpa); +} - 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_stream_eat(s, '{')) - goto error; +/* Read an isl_union_pw_multi_aff from "s" with parameter domain "dom". + * "v" contains a description of the identifiers parsed so far. + * + * In particular, read a sequence + * of zero or more tuples of affine expressions with optional conditions and + * add them up. + */ +static __isl_give isl_union_pw_multi_aff * +isl_stream_read_with_params_union_pw_multi_aff(__isl_keep isl_stream *s, + __isl_keep isl_set *dom, struct vars *v) +{ + isl_union_pw_multi_aff *upma; upma = isl_union_pw_multi_aff_empty(isl_set_get_space(dom)); @@ -3764,95 +3790,25 @@ __isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff( upma2 = isl_union_pw_multi_aff_from_pw_multi_aff(pma); upma = isl_union_pw_multi_aff_union_add(upma, upma2); if (!upma) - goto error; + return NULL; } while (isl_stream_eat_if_available(s, ';')); - if (isl_stream_eat(s, '}')) - goto error; - - isl_set_free(dom); - vars_free(v); return upma; -error: - isl_union_pw_multi_aff_free(upma); - isl_set_free(dom); - vars_free(v); - return NULL; } -/* Read an isl_pw_multi_aff from "s". - * - * Read a more generic isl_union_pw_multi_aff first and - * then check that the result lives in a single space. - */ -__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff( - __isl_keep isl_stream *s) -{ - isl_bool single_space; - isl_union_pw_multi_aff *upma; - - upma = isl_stream_read_union_pw_multi_aff(s); - single_space = isl_union_pw_multi_aff_isa_pw_multi_aff(upma); - if (single_space < 0) - upma = isl_union_pw_multi_aff_free(upma); - else if (!single_space) - isl_die(s->ctx, isl_error_invalid, - "expecting expression in single space", - upma = isl_union_pw_multi_aff_free(upma)); - return isl_union_pw_multi_aff_as_pw_multi_aff(upma); -} - -__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_pw_multi_aff *pma; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - pma = isl_stream_read_pw_multi_aff(s); - isl_stream_free(s); - return pma; -} +#undef BASE +#define BASE multi_aff +#include "isl_stream_read_pw_with_params_templ.c" -/* Read an isl_union_pw_multi_aff from "str". - */ -__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str( - isl_ctx *ctx, const char *str) -{ - isl_union_pw_multi_aff *upma; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - upma = isl_stream_read_union_pw_multi_aff(s); - isl_stream_free(s); - return upma; -} +#undef TYPE_BASE +#define TYPE_BASE pw_multi_aff +#include "isl_stream_read_with_params_templ.c" +#include "isl_read_from_str_templ.c" -/* Assuming "pa" represents a single affine expression defined on a universe - * domain, extract this affine expression. - */ -static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa) -{ - isl_aff *aff; - - if (!pa) - return NULL; - if (pa->n != 1) - isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, - "expecting single affine expression", - goto error); - if (!isl_set_plain_is_universe(pa->p[0].set)) - isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, - "expecting universe domain", - goto error); - - aff = isl_aff_copy(pa->p[0].aff); - isl_pw_aff_free(pa); - return aff; -error: - isl_pw_aff_free(pa); - return NULL; -} +#undef TYPE_BASE +#define TYPE_BASE union_pw_multi_aff +#include "isl_stream_read_with_params_templ.c" +#include "isl_read_from_str_templ.c" #undef BASE #define BASE val @@ -3864,37 +3820,52 @@ error: #include +/* Set entry "pos" of "ma" to the corresponding entry in "tuple", + * as obtained from read_tuple(). + * The "n" output dimensions also appear among the input dimensions + * at position "first". + * + * The entry is not allowed to depend on any (other) output dimensions. + */ +static __isl_give isl_multi_aff *isl_multi_aff_set_tuple_entry( + __isl_take isl_multi_aff *ma, __isl_take isl_pw_aff *tuple_el, + int pos, unsigned first, unsigned n) +{ + isl_space *space; + isl_pw_aff *pa; + isl_aff *aff; + + space = isl_multi_aff_get_domain_space(ma); + pa = separate_tuple_entry(tuple_el, pos, first, n, space); + aff = isl_pw_aff_as_aff(pa); + return isl_multi_aff_set_aff(ma, pos, aff); +} + +#undef BASE +#define BASE aff + +#include + /* 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. * The tuple representing the actual expressions needs to consist - * of only affine expressions. Moreover, these expressions can - * only depend on parameters and input dimensions and not on other - * output dimensions. + * of only affine expressions. */ __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) { struct vars *v; - isl_set *dom = NULL; isl_multi_pw_aff *tuple = NULL; - int i; - isl_size dim, n; - isl_space *space, *dom_space; + isl_space *dom_space = NULL; isl_multi_aff *ma = NULL; 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); + dom_space = read_params(s, v); + if (!dom_space) + goto error; if (isl_stream_eat(s, '{')) goto error; @@ -3902,7 +3873,6 @@ __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) if (!tuple) goto error; if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { - isl_set *set; isl_space *space; isl_bool has_expr; @@ -3913,8 +3883,7 @@ __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) isl_die(s->ctx, isl_error_invalid, "expecting universe domain", goto error); space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); - set = isl_set_universe(space); - dom = isl_set_intersect_params(set, dom); + dom_space = isl_space_align_params(space, dom_space); isl_multi_pw_aff_free(tuple); tuple = read_tuple(s, v, 0, 0); if (!tuple) @@ -3924,151 +3893,35 @@ __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s) if (isl_stream_eat(s, '}')) goto error; - n = isl_multi_pw_aff_dim(tuple, isl_dim_out); - dim = isl_set_dim(dom, isl_dim_all); - if (n < 0 || dim < 0) - goto error; - dom_space = isl_set_get_space(dom); - space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); - space = isl_space_align_params(space, isl_space_copy(dom_space)); - if (!isl_space_is_params(dom_space)) - space = isl_space_map_from_domain_and_range( - isl_space_copy(dom_space), space); - isl_space_free(dom_space); - ma = isl_multi_aff_alloc(space); - - for (i = 0; i < n; ++i) { - isl_pw_aff *pa; - isl_aff *aff; - pa = isl_multi_pw_aff_get_pw_aff(tuple, i); - aff = aff_from_pw_aff(pa); - if (!aff) - goto error; - if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) { - isl_aff_free(aff); - isl_die(s->ctx, isl_error_invalid, - "not an affine expression", goto error); - } - aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n); - space = isl_multi_aff_get_domain_space(ma); - aff = isl_aff_reset_domain_space(aff, space); - ma = isl_multi_aff_set_aff(ma, i, aff); - } + ma = isl_multi_aff_from_tuple(dom_space, tuple); - isl_multi_pw_aff_free(tuple); vars_free(v); - isl_set_free(dom); return ma; error: isl_multi_pw_aff_free(tuple); vars_free(v); - isl_set_free(dom); + isl_space_free(dom_space); isl_multi_aff_free(ma); return NULL; } -__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_multi_aff *maff; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - maff = isl_stream_read_multi_aff(s); - isl_stream_free(s); - return maff; -} +#undef TYPE_BASE +#define TYPE_BASE multi_aff +#include "isl_read_from_str_templ.c" -/* Read an isl_multi_pw_aff from "s". - * - * The input format is similar to that of map, except that any conditions - * on the domains should be specified inside the tuple since each - * piecewise affine expression may have a different domain. - * However, additional, shared conditions can also be specified. - * This is especially useful for setting the explicit domain - * of a zero-dimensional isl_multi_pw_aff. - * - * Since we do not know in advance if the isl_multi_pw_aff lives - * in a set or a map space, we first read the first tuple and check - * if it is followed by a "->". If so, we convert the tuple into - * the domain of the isl_multi_pw_aff and read in the next tuple. - * This tuple (or the first tuple if it was not followed by a "->") - * is then converted into the isl_multi_pw_aff through a call - * to extract_mpa_from_tuple and the domain of the result - * is intersected with the domain. - * - * Note that the last tuple may introduce new identifiers, - * but these cannot be referenced in the description of the domain. +/* Read an isl_multi_pw_aff from "s" with parameter domain "dom".. + * "v" contains a description of the identifiers parsed so far. */ -__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff( - __isl_keep isl_stream *s) +static __isl_give isl_multi_pw_aff *isl_stream_read_with_params_multi_pw_aff( + __isl_keep isl_stream *s, __isl_keep isl_set *dom, struct vars *v) { - int n_dom; - struct vars *v; - isl_set *dom = NULL; - isl_multi_pw_aff *tuple = NULL; - isl_multi_pw_aff *mpa = NULL; - - 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_stream_eat(s, '{')) - goto error; - - n_dom = v->n; - tuple = read_tuple(s, v, 0, 0); - if (!tuple) - goto error; - if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) { - isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0); - dom = isl_map_domain(map); - n_dom = v->n; - tuple = read_tuple(s, v, 0, 0); - if (!tuple) - goto error; - } - - vars_drop(v, v->n - n_dom); - if (isl_stream_eat_if_available(s, ':')) - dom = read_formula(s, v, dom, 0); - - if (isl_stream_eat(s, '}')) - goto error; - - mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple); - - isl_multi_pw_aff_free(tuple); - vars_free(v); - mpa = isl_multi_pw_aff_intersect_domain(mpa, dom); - return mpa; -error: - isl_multi_pw_aff_free(tuple); - vars_free(v); - isl_set_free(dom); - isl_multi_pw_aff_free(mpa); - return NULL; + return read_conditional_multi_pw_aff(s, isl_set_copy(dom), v); } -/* Read an isl_multi_pw_aff from "str". - */ -__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_multi_pw_aff *mpa; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - mpa = isl_stream_read_multi_pw_aff(s); - isl_stream_free(s); - return mpa; -} +#undef TYPE_BASE +#define TYPE_BASE multi_pw_aff +#include "isl_stream_read_with_params_templ.c" +#include "isl_read_from_str_templ.c" /* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom". */ @@ -4104,60 +3957,19 @@ static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom( return upa; } -/* Read an isl_union_pw_aff from "s". - * - * First check if there are any paramters, then read in the opening brace - * and use read_union_pw_aff_with_dom to read in the body of - * the isl_union_pw_aff. Finally, read the closing brace. +/* Read an isl_union_pw_aff from "s" with parameter domain "dom". + * "v" contains a description of the identifiers parsed so far. */ -__isl_give isl_union_pw_aff *isl_stream_read_union_pw_aff( - __isl_keep isl_stream *s) +static __isl_give isl_union_pw_aff *isl_stream_read_with_params_union_pw_aff( + __isl_keep isl_stream *s, __isl_keep isl_set *dom, struct vars *v) { - struct vars *v; - isl_set *dom; - isl_union_pw_aff *upa = NULL; - - 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_stream_eat(s, '{')) - goto error; - - upa = read_union_pw_aff_with_dom(s, isl_set_copy(dom), v); - - if (isl_stream_eat(s, '}')) - goto error; - - vars_free(v); - isl_set_free(dom); - return upa; -error: - vars_free(v); - isl_set_free(dom); - isl_union_pw_aff_free(upa); - return NULL; + return read_union_pw_aff_with_dom(s, isl_set_copy(dom), v); } -/* Read an isl_union_pw_aff from "str". - */ -__isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx, - const char *str) -{ - isl_union_pw_aff *upa; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - upa = isl_stream_read_union_pw_aff(s); - isl_stream_free(s); - return upa; -} +#undef TYPE_BASE +#define TYPE_BASE union_pw_aff +#include "isl_stream_read_with_params_templ.c" +#include "isl_read_from_str_templ.c" /* This function is called for each element in a tuple inside * isl_stream_read_multi_union_pw_aff. @@ -4444,19 +4256,9 @@ __isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff( return mupa; } -/* 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; -} +#undef TYPE_BASE +#define TYPE_BASE multi_union_pw_aff +#include "isl_read_from_str_templ.c" __isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial( __isl_keep isl_stream *s) @@ -4478,14 +4280,6 @@ error: return NULL; } -__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str( - isl_ctx *ctx, const char *str) -{ - isl_union_pw_qpolynomial *upwqp; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - upwqp = isl_stream_read_union_pw_qpolynomial(s); - isl_stream_free(s); - return upwqp; -} +#undef TYPE_BASE +#define TYPE_BASE union_pw_qpolynomial +#include "isl_read_from_str_templ.c" diff --git a/polly/lib/External/isl/isl_int_sioimath.h b/polly/lib/External/isl/isl_int_sioimath.h index dc691b8..a2112cd 100644 --- a/polly/lib/External/isl/isl_int_sioimath.h +++ b/polly/lib/External/isl/isl_int_sioimath.h @@ -868,6 +868,7 @@ inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, isl_sioimath_bigarg_src(rhs, &rhsscratch), isl_sioimath_reinit_big(dst), NULL); isl_sioimath_try_demote(dst); + return; } /* Divide lhs by an unsigned long rhs, rounding to zero (Truncate). diff --git a/polly/lib/External/isl/isl_list_read_templ.c b/polly/lib/External/isl/isl_list_read_templ.c index d9a2c40..11c2bd5 100644 --- a/polly/lib/External/isl/isl_list_read_templ.c +++ b/polly/lib/External/isl/isl_list_read_templ.c @@ -16,7 +16,7 @@ * In particular, the elements are separated by a comma and * the entire list is surrounded by parentheses. */ -static __isl_give LIST(EL) *FN(isl_stream_read,LIST(EL_BASE))(isl_stream *s) +__isl_give LIST(EL) *FN(isl_stream_read,LIST(EL_BASE))(isl_stream *s) { isl_ctx *ctx; LIST(EL) *list; @@ -44,22 +44,6 @@ static __isl_give LIST(EL) *FN(isl_stream_read,LIST(EL_BASE))(isl_stream *s) return list; } -/* Read a list of elements of type EL from the string "str". - * The input format corresponds to the way lists are printed - * by isl_printer_print_list_*. - * In particular, the elements are separated by a comma and - * the entire list is surrounded by parentheses. - */ -__isl_give LIST(EL) *FN(LIST(EL),read_from_str)(isl_ctx *ctx, - const char *str) -{ - LIST(EL) *list; - isl_stream *s; - - s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - list = FN(isl_stream_read,LIST(EL_BASE))(s); - isl_stream_free(s); - return list; -} +#undef TYPE_BASE +#define TYPE_BASE LIST(EL_BASE) +#include "isl_read_from_str_templ.c" diff --git a/polly/lib/External/isl/isl_list_read_yaml_templ.c b/polly/lib/External/isl/isl_list_read_yaml_templ.c new file mode 100644 index 0000000..5b6143d --- /dev/null +++ b/polly/lib/External/isl/isl_list_read_yaml_templ.c @@ -0,0 +1,40 @@ +/* + * 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 + +#include + +/* Read a sequence of EL objects and return them as a list. + */ +static __isl_give LIST(EL) *FN(isl_stream_yaml_read,LIST(EL_BASE))( + isl_stream *s) +{ + isl_ctx *ctx; + LIST(EL) *list; + isl_bool more; + + ctx = isl_stream_get_ctx(s); + + if (isl_stream_yaml_read_start_sequence(s) < 0) + return NULL; + + list = FN(LIST(EL),alloc)(ctx, 0); + while ((more = isl_stream_yaml_next(s)) == isl_bool_true) { + EL *el; + + el = FN(isl_stream_read,EL_BASE)(s); + list = FN(LIST(EL),add)(list, el); + } + + if (more < 0 || isl_stream_yaml_read_end_sequence(s) < 0) + return FN(LIST(EL),free)(list); + + return list; +} diff --git a/polly/lib/External/isl/isl_list_templ.c b/polly/lib/External/isl/isl_list_templ.c index cfb4f33..4b04052 100644 --- a/polly/lib/External/isl/isl_list_templ.c +++ b/polly/lib/External/isl/isl_list_templ.c @@ -289,7 +289,7 @@ __isl_give EL *FN(FN(LIST(EL),get),EL_BASE)(__isl_keep LIST(EL) *list, /* Replace the element at position "index" in "list" by "el". */ -__isl_give LIST(EL) *FN(FN(LIST(EL),set),EL_BASE)(__isl_take LIST(EL) *list, +__isl_give LIST(EL) *FN(LIST(EL),set_at)(__isl_take LIST(EL) *list, int index, __isl_take EL *el) { if (!list || !el) @@ -312,6 +312,14 @@ error: return NULL; } +/* This is an alternative name for the function above. + */ +__isl_give LIST(EL) *FN(FN(LIST(EL),set),EL_BASE)(__isl_take LIST(EL) *list, + int index, __isl_take EL *el) +{ + return FN(LIST(EL),set_at)(list, index, el); +} + /* Return the element at position "index" of "list". * This may be either a copy or the element itself * if there is only one reference to "list". diff --git a/polly/lib/External/isl/isl_local.c b/polly/lib/External/isl/isl_local.c index e409359..5b50ea7 100644 --- a/polly/lib/External/isl/isl_local.c +++ b/polly/lib/External/isl/isl_local.c @@ -1,6 +1,7 @@ /* * Copyright 2011 INRIA Saclay * Copyright 2014 Ecole Normale Superieure + * Copyright 2015 Sven Verdoolaege * * Use of this software is governed by the MIT license * @@ -38,6 +39,13 @@ __isl_give isl_local *isl_local_alloc_from_mat(__isl_take isl_mat *mat) return mat; } +/* Return a new reference to "local". + */ +__isl_give isl_local *isl_local_copy(__isl_keep isl_local *local) +{ + return isl_local_alloc_from_mat(isl_mat_copy(local)); +} + /* Free "local" and return NULL. */ __isl_null isl_local *isl_local_free(__isl_take isl_local *local) @@ -222,6 +230,32 @@ int isl_local_cmp(__isl_keep isl_local *local1, __isl_keep isl_local *local2) return 0; } +/* Return the position of the variables of the given type + * within the sequence of variables of "local". + * + * Only the position of the local variables can be obtained. + * It is equal to the total number of variables minus + * the number of local variables. + */ +isl_size isl_local_var_offset(__isl_keep isl_local *local, + enum isl_dim_type type) +{ + isl_size n_div, n_all; + + if (!local) + return isl_size_error; + if (type != isl_dim_div) + isl_die(isl_local_get_ctx(local), isl_error_unsupported, + "only the offset of the local variables " + "can be obtained", return isl_size_error); + + n_div = isl_local_dim(local, isl_dim_div); + n_all = isl_local_dim(local, isl_dim_all); + if (n_div < 0 || n_all < 0) + return isl_size_error; + return n_all - n_div; +} + /* Reorder the columns of the given local variables according to the * given reordering. * The order of the local variables themselves is assumed not to change. @@ -231,19 +265,13 @@ __isl_give isl_local *isl_local_reorder(__isl_take isl_local *local, { isl_mat *div = local; int i, j; - isl_size dim; - isl_space *space; isl_mat *mat; int extra; if (!local || !r) goto error; - space = isl_reordering_peek_space(r); - dim = isl_space_dim(space, isl_dim_all); - if (dim < 0) - goto error; - extra = dim + div->n_row - r->len; + extra = r->dst_len - r->src_len; mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra); if (!mat) goto error; @@ -251,7 +279,7 @@ __isl_give isl_local *isl_local_reorder(__isl_take isl_local *local, for (i = 0; i < div->n_row; ++i) { isl_seq_cpy(mat->row[i], div->row[i], 2); isl_seq_clr(mat->row[i] + 2, mat->n_col - 2); - for (j = 0; j < r->len; ++j) + for (j = 0; j < r->src_len; ++j) isl_int_set(mat->row[i][2 + r->pos[j]], div->row[i][2 + j]); } @@ -265,6 +293,32 @@ error: return NULL; } +/* Move the "n" variables starting at "src_pos" of "local" to "dst_pos". + * + * Moving local variables is not allowed. + */ +__isl_give isl_local *isl_local_move_vars(__isl_take isl_local *local, + unsigned dst_pos, unsigned src_pos, unsigned n) +{ + isl_mat *mat = local; + isl_size v_div; + + v_div = isl_local_var_offset(local, isl_dim_div); + if (v_div < 0) + return isl_local_free(local); + if (n == 0) + return local; + + if (dst_pos >= v_div || src_pos >= v_div) + isl_die(isl_local_get_ctx(local), isl_error_invalid, + "cannot move local variables", + return isl_local_free(local)); + + mat = isl_mat_move_cols(mat, 2 + dst_pos, 2 + src_pos, n); + + return isl_local_alloc_from_mat(mat); +} + /* Extend a vector "v" representing an integer point * in the domain space of "local" * to one that also includes values for the local variables. diff --git a/polly/lib/External/isl/isl_local.h b/polly/lib/External/isl/isl_local.h index a52622e..7652703 100644 --- a/polly/lib/External/isl/isl_local.h +++ b/polly/lib/External/isl/isl_local.h @@ -6,6 +6,7 @@ typedef isl_mat isl_local; +__isl_give isl_local *isl_local_copy(__isl_keep isl_local *local); __isl_null isl_local *isl_local_free(__isl_take isl_local *local); isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_local *local, int pos); @@ -14,9 +15,15 @@ isl_bool isl_local_divs_known(__isl_keep isl_local *local); int isl_local_cmp(__isl_keep isl_local *local1, __isl_keep isl_local *local2); +isl_size isl_local_var_offset(__isl_keep isl_local *local, + enum isl_dim_type type); + __isl_give isl_local *isl_local_reorder(__isl_take isl_local *local, __isl_take isl_reordering *r); +__isl_give isl_local *isl_local_move_vars(__isl_take isl_local *local, + unsigned dst_pos, unsigned src_pos, unsigned n); + __isl_give isl_vec *isl_local_extend_point_vec(__isl_keep isl_local *local, __isl_take isl_vec *v); diff --git a/polly/lib/External/isl/isl_local_space.c b/polly/lib/External/isl/isl_local_space.c index 1eebd44..604e276 100644 --- a/polly/lib/External/isl/isl_local_space.c +++ b/polly/lib/External/isl/isl_local_space.c @@ -245,22 +245,44 @@ isl_size isl_local_space_dim(__isl_keep isl_local_space *ls, #define TYPE isl_local_space #include "check_type_range_templ.c" -unsigned isl_local_space_offset(__isl_keep isl_local_space *ls, +/* Return the position of the variables of the given type + * within the sequence of variables of "ls". + */ +isl_size isl_local_space_var_offset(__isl_keep isl_local_space *ls, enum isl_dim_type type) { isl_space *space; + space = isl_local_space_peek_space(ls); + if (space < 0) + return isl_size_error; + switch (type) { + case isl_dim_param: + case isl_dim_in: + case isl_dim_out: return isl_space_offset(space, type); + case isl_dim_div: return isl_space_dim(space, isl_dim_all); + case isl_dim_cst: + default: + isl_die(isl_local_space_get_ctx(ls), isl_error_invalid, + "invalid dimension type", return isl_size_error); + } +} + +/* Return the position of the coefficients of the variables of the given type + * within the sequence of coefficients of "ls". + */ +unsigned isl_local_space_offset(__isl_keep isl_local_space *ls, + enum isl_dim_type type) +{ if (!ls) return 0; - space = ls->dim; switch (type) { case isl_dim_cst: return 0; - case isl_dim_param: return 1; - case isl_dim_in: return 1 + space->nparam; - case isl_dim_out: return 1 + space->nparam + space->n_in; - case isl_dim_div: - return 1 + space->nparam + space->n_in + space->n_out; + case isl_dim_param: + case isl_dim_in: + case isl_dim_out: + case isl_dim_div: return 1 + isl_local_space_var_offset(ls, type); default: return 0; } } @@ -464,6 +486,66 @@ __isl_keep isl_local *isl_local_space_peek_local(__isl_keep isl_local_space *ls) return ls ? ls->div : NULL; } +/* Return a copy of the local variables of "ls". + */ +__isl_keep isl_local *isl_local_space_get_local(__isl_keep isl_local_space *ls) +{ + return isl_local_copy(isl_local_space_peek_local(ls)); +} + +/* Return the local variables of "ls". + * This may be either a copy or the local variables itself + * if there is only one reference to "ls". + * This allows the local variables to be modified inplace + * if both the local space and its local variables have only a single reference. + * The caller is not allowed to modify "ls" between this call and + * the subsequent call to isl_local_space_restore_local. + * The only exception is that isl_local_space_free can be called instead. + */ +static __isl_give isl_local *isl_local_space_take_local( + __isl_keep isl_local_space *ls) +{ + isl_local *local; + + if (!ls) + return NULL; + if (ls->ref != 1) + return isl_local_space_get_local(ls); + local = ls->div; + ls->div = NULL; + return local; +} + +/* Set the local variables of "ls" to "local", + * where the local variables of "ls" may be missing + * due to a preceding call to isl_local_space_take_local. + * However, in this case, "ls" only has a single reference and + * then the call to isl_local_space_cow has no effect. + */ +static __isl_give isl_local_space *isl_local_space_restore_local( + __isl_take isl_local_space *ls, __isl_take isl_local *local) +{ + if (!ls || !local) + goto error; + + if (ls->div == local) { + isl_local_free(local); + return ls; + } + + ls = isl_local_space_cow(ls); + if (!ls) + goto error; + isl_local_free(ls->div); + ls->div = local; + + return ls; +error: + isl_local_space_free(ls); + isl_local_free(local); + return NULL; +} + /* Replace the identifier of the tuple of type "type" by "id". */ __isl_give isl_local_space *isl_local_space_set_tuple_id( @@ -551,22 +633,16 @@ error: __isl_give isl_local_space *isl_local_space_realign( __isl_take isl_local_space *ls, __isl_take isl_reordering *r) { - ls = isl_local_space_cow(ls); - if (!ls || !r) - goto error; + isl_local *local; - ls->div = isl_local_reorder(ls->div, isl_reordering_copy(r)); - if (!ls->div) - goto error; + local = isl_local_space_take_local(ls); + local = isl_local_reorder(local, isl_reordering_copy(r)); + ls = isl_local_space_restore_local(ls, local); ls = isl_local_space_reset_space(ls, isl_reordering_get_space(r)); isl_reordering_free(r); return ls; -error: - isl_local_space_free(ls); - isl_reordering_free(r); - return NULL; } __isl_give isl_local_space *isl_local_space_add_div( @@ -1557,6 +1633,9 @@ __isl_give isl_local_space *isl_local_space_move_dims( enum isl_dim_type dst_type, unsigned dst_pos, enum isl_dim_type src_type, unsigned src_pos, unsigned n) { + isl_space *space; + isl_local *local; + isl_size v_src, v_dst; unsigned g_dst_pos; unsigned g_src_pos; @@ -1584,21 +1663,23 @@ __isl_give isl_local_space *isl_local_space_move_dims( "moving dims within the same type not supported", return isl_local_space_free(ls)); - ls = isl_local_space_cow(ls); - if (!ls) - return NULL; - - g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos; - g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos; + v_src = isl_local_space_var_offset(ls, src_type); + v_dst = isl_local_space_var_offset(ls, dst_type); + if (v_src < 0 || v_dst < 0) + return isl_local_space_free(ls); + g_src_pos = v_src + src_pos; + g_dst_pos = v_dst + dst_pos; if (dst_type > src_type) g_dst_pos -= n; - ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n); - if (!ls->div) - return isl_local_space_free(ls); - ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos, + + local = isl_local_space_take_local(ls); + local = isl_local_move_vars(local, g_dst_pos, g_src_pos, n); + ls = isl_local_space_restore_local(ls, local); + + space = isl_local_space_take_space(ls); + space = isl_space_move_dims(space, dst_type, dst_pos, src_type, src_pos, n); - if (!ls->dim) - return isl_local_space_free(ls); + ls = isl_local_space_restore_space(ls, space); return ls; } diff --git a/polly/lib/External/isl/isl_local_space_private.h b/polly/lib/External/isl/isl_local_space_private.h index 42c2ad0..fbf2159 100644 --- a/polly/lib/External/isl/isl_local_space_private.h +++ b/polly/lib/External/isl/isl_local_space_private.h @@ -34,6 +34,8 @@ int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j); __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2, int *exp1, int *exp2); +isl_size isl_local_space_var_offset(__isl_keep isl_local_space *ls, + enum isl_dim_type type); unsigned isl_local_space_offset(__isl_keep isl_local_space *ls, enum isl_dim_type type); diff --git a/polly/lib/External/isl/isl_lp.c b/polly/lib/External/isl/isl_lp.c index 5fe179a..c6cc838 100644 --- a/polly/lib/External/isl/isl_lp.c +++ b/polly/lib/External/isl/isl_lp.c @@ -22,7 +22,7 @@ #include #include -enum isl_lp_result isl_tab_solve_lp(__isl_keep isl_basic_map *bmap, +static enum isl_lp_result isl_tab_solve_lp(__isl_keep isl_basic_map *bmap, int maximize, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom, __isl_give isl_vec **sol) { diff --git a/polly/lib/External/isl/isl_map.c b/polly/lib/External/isl/isl_map.c index 516106cf..5cb7a56 100644 --- a/polly/lib/External/isl/isl_map.c +++ b/polly/lib/External/isl/isl_map.c @@ -1464,14 +1464,7 @@ __isl_give isl_basic_set *isl_basic_set_dup(__isl_keep isl_basic_set *bset) __isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset) { - if (!bset) - return NULL; - - if (ISL_F_ISSET(bset, ISL_BASIC_SET_FINAL)) { - bset->ref++; - return bset; - } - return isl_basic_set_dup(bset); + return bset_from_bmap(isl_basic_map_copy(bset_to_bmap(bset))); } __isl_give isl_set *isl_set_copy(__isl_keep isl_set *set) @@ -4622,6 +4615,7 @@ error: #undef TYPE #define TYPE isl_map #include "isl_project_out_all_params_templ.c" +#include "isl_project_out_param_templ.c" /* Turn all the dimensions of type "type", except the "n" starting at "first" * into existentially quantified variables. @@ -4655,19 +4649,7 @@ __isl_give isl_set *isl_set_project_out(__isl_take isl_set *set, __isl_give isl_set *isl_set_project_out_param_id(__isl_take isl_set *set, __isl_take isl_id *id) { - int pos; - - if (!set || !id) - goto error; - pos = isl_set_find_dim_by_id(set, isl_dim_param, id); - isl_id_free(id); - if (pos < 0) - return set; - return isl_set_project_out(set, isl_dim_param, pos, 1); -error: - isl_set_free(set); - isl_id_free(id); - return NULL; + return set_from_map(isl_map_project_out_param_id(set_to_map(set), id)); } /* If "set" involves any of the parameters with identifiers in "list", @@ -4676,25 +4658,11 @@ error: __isl_give isl_set *isl_set_project_out_param_id_list(__isl_take isl_set *set, __isl_take isl_id_list *list) { - int i; - isl_size n; - - n = isl_id_list_size(list); - if (n < 0) - goto error; - for (i = 0; i < n; ++i) { - isl_id *id; - - id = isl_id_list_get_at(list, i); - set = isl_set_project_out_param_id(set, id); - } + isl_map *map; - isl_id_list_free(list); - return set; -error: - isl_id_list_free(list); - isl_set_free(set); - return NULL; + map = set_to_map(set); + map = isl_map_project_out_param_id_list(map, list); + return set_from_map(map); } /* Project out all parameters from "set" by existentially quantifying @@ -8587,6 +8555,46 @@ __isl_give isl_set *isl_set_intersect_factor_range(__isl_take isl_set *set, set_to_map(range), &control)); } +/* Given a map "map" in a space [A -> B] -> C and a set "domain" + * in the space A, return the intersection. + * + * The set "domain" is extended to a set living in the space [A -> B] and + * the domain of "map" is intersected with this set. + */ +__isl_give isl_map *isl_map_intersect_domain_wrapped_domain( + __isl_take isl_map *map, __isl_take isl_set *domain) +{ + isl_space *space; + isl_set *factor; + + isl_map_align_params_set(&map, &domain); + space = isl_map_get_space(map); + space = isl_space_domain_wrapped_range(space); + factor = isl_set_universe(space); + domain = isl_set_product(domain, factor); + return isl_map_intersect_domain(map, domain); +} + +/* Given a map "map" in a space A -> [B -> C] and a set "domain" + * in the space B, return the intersection. + * + * The set "domain" is extended to a set living in the space [B -> C] and + * the range of "map" is intersected with this set. + */ +__isl_give isl_map *isl_map_intersect_range_wrapped_domain( + __isl_take isl_map *map, __isl_take isl_set *domain) +{ + isl_space *space; + isl_set *factor; + + isl_map_align_params_set(&map, &domain); + space = isl_map_get_space(map); + space = isl_space_range_wrapped_range(space); + factor = isl_set_universe(space); + domain = isl_set_product(domain, factor); + return isl_map_intersect_range(map, domain); +} + __isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1, __isl_take isl_map *map2) { @@ -10361,6 +10369,18 @@ int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1, return cmp; } for (i = 0; i < bmap1->n_div; ++i) { + isl_bool unknown1, unknown2; + + unknown1 = isl_basic_map_div_is_marked_unknown(bmap1, i); + unknown2 = isl_basic_map_div_is_marked_unknown(bmap2, i); + if (unknown1 < 0 || unknown2 < 0) + return -1; + if (unknown1 && unknown2) + continue; + if (unknown1) + return 1; + if (unknown2) + return -1; cmp = isl_seq_cmp(bmap1->div[i], bmap2->div[i], 1+1+total); if (cmp) return cmp; @@ -12469,10 +12489,11 @@ __isl_give isl_map *isl_map_align_params(__isl_take isl_map *map, if (aligned < 0) goto error; if (!aligned) { + isl_space *space; isl_reordering *exp; - exp = isl_parameter_alignment_reordering(map->dim, model); - exp = isl_reordering_extend_space(exp, isl_map_get_space(map)); + space = isl_map_peek_space(map); + exp = isl_parameter_alignment_reordering(space, model); map = isl_map_realign(map, exp); } @@ -12498,6 +12519,7 @@ __isl_give isl_basic_map *isl_basic_map_align_params( { isl_ctx *ctx; isl_bool equal_params; + isl_space *bmap_space; if (!bmap || !model) goto error; @@ -12508,16 +12530,15 @@ __isl_give isl_basic_map *isl_basic_map_align_params( "model has unnamed parameters", goto error); if (isl_basic_map_check_named_params(bmap) < 0) goto error; - equal_params = isl_space_has_equal_params(bmap->dim, model); + bmap_space = isl_basic_map_peek_space(bmap); + equal_params = isl_space_has_equal_params(bmap_space, model); if (equal_params < 0) goto error; if (!equal_params) { isl_reordering *exp; struct isl_dim_map *dim_map; - exp = isl_parameter_alignment_reordering(bmap->dim, model); - exp = isl_reordering_extend_space(exp, - isl_basic_map_get_space(bmap)); + exp = isl_parameter_alignment_reordering(bmap_space, model); dim_map = isl_dim_map_from_reordering(exp); bmap = isl_basic_map_realign(bmap, isl_reordering_get_space(exp), diff --git a/polly/lib/External/isl/isl_map_simplify.c b/polly/lib/External/isl/isl_map_simplify.c index 9759c0d..72e0e9b 100644 --- a/polly/lib/External/isl/isl_map_simplify.c +++ b/polly/lib/External/isl/isl_map_simplify.c @@ -1198,7 +1198,7 @@ static isl_bool better_div_constraint(__isl_keep isl_basic_map *bmap, * a "better" expression for a div for which we already have an expression. * "sum" is the sum of the constant terms of the constraints. * If this sum is strictly smaller than the coefficient of one - * of the divs, then this pair can be used define the div. + * of the divs, then this pair can be used to define the div. * To avoid the introduction of circular definitions of divs, we * do not use the pair if the resulting expression would refer to * any other undefined divs or if any known div is defined in diff --git a/polly/lib/External/isl/isl_map_subtract.c b/polly/lib/External/isl/isl_map_subtract.c index 6431b3d..68ce54f 100644 --- a/polly/lib/External/isl/isl_map_subtract.c +++ b/polly/lib/External/isl/isl_map_subtract.c @@ -235,8 +235,8 @@ static int tab_freeze_constraints(struct isl_tab *tab) } /* Check for redundant constraints starting at offset. - * Put the indices of the redundant constraints in index - * and return the number of redundant constraints. + * Put the indices of the non-redundant constraints in index + * and return the number of non-redundant constraints. */ static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab, int offset, int **index) diff --git a/polly/lib/External/isl/isl_map_to_basic_set.c b/polly/lib/External/isl/isl_map_to_basic_set.c index f0c8d50..9e96e60 100644 --- a/polly/lib/External/isl/isl_map_to_basic_set.c +++ b/polly/lib/External/isl/isl_map_to_basic_set.c @@ -6,9 +6,13 @@ #define ISL_VAL isl_basic_set #define ISL_HMAP_SUFFIX map_to_basic_set #define ISL_HMAP isl_map_to_basic_set +#define ISL_HMAP_IS_EQUAL isl_map_to_basic_set_plain_is_equal #define ISL_KEY_IS_EQUAL isl_map_plain_is_equal #define ISL_VAL_IS_EQUAL isl_basic_set_plain_is_equal #define ISL_KEY_PRINT isl_printer_print_map #define ISL_VAL_PRINT isl_printer_print_basic_set +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_KEY_READ isl_stream_read_map +#define ISL_VAL_READ isl_stream_read_basic_set #include diff --git a/polly/lib/External/isl/isl_multi_add_constant_templ.c b/polly/lib/External/isl/isl_multi_add_constant_templ.c index fa4971f..a54f3fa 100644 --- a/polly/lib/External/isl/isl_multi_add_constant_templ.c +++ b/polly/lib/External/isl/isl_multi_add_constant_templ.c @@ -15,31 +15,16 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),add_constant_val)( __isl_take MULTI(BASE) *multi, __isl_take isl_val *v) { isl_bool zero; - isl_size n; - int i; zero = isl_val_is_zero(v); - n = FN(MULTI(BASE),size)(multi); - if (zero < 0 || n < 0) + if (zero < 0) goto error; - if (zero || n == 0) { + if (zero) { isl_val_free(v); return multi; } - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - goto error; - - for (i = 0; i < n; ++i) { - multi->u.p[i] = FN(EL,add_constant_val)(multi->u.p[i], - isl_val_copy(v)); - if (!multi->u.p[i]) - goto error; - } - - isl_val_free(v); - return multi; + return FN(MULTI(BASE),fn_val)(multi, &FN(EL,add_constant_val), v); error: FN(MULTI(BASE),free)(multi); isl_val_free(v); @@ -52,40 +37,19 @@ error: __isl_give MULTI(BASE) *FN(MULTI(BASE),add_constant_multi_val)( __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv) { - isl_space *multi_space, *mv_space; - isl_bool zero, equal; - isl_size n; - int i; + isl_bool zero; zero = isl_multi_val_is_zero(mv); - n = FN(MULTI(BASE),size)(multi); - multi_space = FN(MULTI(BASE),peek_space)(multi); - mv_space = isl_multi_val_peek_space(mv); - equal = isl_space_tuple_is_equal(multi_space, isl_dim_out, - mv_space, isl_dim_out); - if (zero < 0 || n < 0 || equal < 0) + if (zero < 0) goto error; - if (!equal) - isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, - "spaces don't match", goto error); - if (zero || n == 0) { + if (zero) { isl_multi_val_free(mv); return multi; } - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - goto error; + return FN(MULTI(BASE),fn_multi_val)(multi, &FN(EL,add_constant_val), + mv); - for (i = 0; i < n; ++i) { - isl_val *v = isl_multi_val_get_at(mv, i); - multi->u.p[i] = FN(EL,add_constant_val)(multi->u.p[i], v); - if (!multi->u.p[i]) - goto error; - } - - isl_multi_val_free(mv); - return multi; error: FN(MULTI(BASE),free)(multi); isl_multi_val_free(mv); diff --git a/polly/lib/External/isl/isl_multi_apply_templ.c b/polly/lib/External/isl/isl_multi_apply_templ.c index 870f2676..31e27f2 100644 --- a/polly/lib/External/isl/isl_multi_apply_templ.c +++ b/polly/lib/External/isl/isl_multi_apply_templ.c @@ -19,24 +19,19 @@ __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)) { + isl_size n; int i; - if (!multi || !set) + n = FN(MULTI(BASE),size)(multi); + if (n < 0 || !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 < n; ++i) { + EL *el; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = fn(multi->u.p[i], FN(APPLY_DOM,copy)(set)); - if (!multi->u.p[i]) - goto error; + el = FN(MULTI(BASE),take_at)(multi, i); + el = fn(el, FN(APPLY_DOM,copy)(set)); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } FN(APPLY_DOM,free)(set); diff --git a/polly/lib/External/isl/isl_multi_arith_templ.c b/polly/lib/External/isl/isl_multi_arith_templ.c index 6765bd2..dd49713 100644 --- a/polly/lib/External/isl/isl_multi_arith_templ.c +++ b/polly/lib/External/isl/isl_multi_arith_templ.c @@ -29,13 +29,13 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1, return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub)); } -/* Multiply the elements of "multi" by "v" and return the result. +/* Depending on "fn", multiply or divide the elements of "multi" by "v" and + * return the result. */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi, - __isl_take isl_val *v) +static __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val_fn)( + __isl_take MULTI(BASE) *multi, __isl_take isl_val *v, + __isl_give EL *(*fn)(__isl_take EL *el, __isl_take isl_val *v)) { - int i; - if (!multi || !v) goto error; @@ -48,59 +48,31 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi, isl_die(isl_val_get_ctx(v), isl_error_invalid, "expecting rational factor", goto error); - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; - - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i], - isl_val_copy(v)); - if (!multi->u.p[i]) - goto error; - } - - isl_val_free(v); - return multi; + return FN(MULTI(BASE),fn_val)(multi, fn, v); error: isl_val_free(v); return FN(MULTI(BASE),free)(multi); } +/* 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, + __isl_take isl_val *v) +{ + return FN(MULTI(BASE),scale_val_fn)(multi, v, &FN(EL,scale_val)); +} + /* Divide the elements of "multi" by "v" and return the result. */ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)( __isl_take MULTI(BASE) *multi, __isl_take isl_val *v) { - int i; - - if (!multi || !v) + if (!v) goto error; - - if (isl_val_is_one(v)) { - isl_val_free(v); - return multi; - } - - if (!isl_val_is_rat(v)) - isl_die(isl_val_get_ctx(v), isl_error_invalid, - "expecting rational factor", goto error); if (isl_val_is_zero(v)) isl_die(isl_val_get_ctx(v), isl_error_invalid, "cannot scale down by zero", goto error); - - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; - - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i], - isl_val_copy(v)); - if (!multi->u.p[i]) - goto error; - } - - isl_val_free(v); - return multi; + return FN(MULTI(BASE),scale_val_fn)(multi, v, &FN(EL,scale_down_val)); error: isl_val_free(v); return FN(MULTI(BASE),free)(multi); @@ -112,34 +84,7 @@ error: __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_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) - goto error; - - for (i = 0; i < multi->n; ++i) { - isl_val *v; - - v = isl_multi_val_get_val(mv, i); - multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i], v); - if (!multi->u.p[i]) - goto error; - } - - isl_multi_val_free(mv); - return multi; -error: - isl_multi_val_free(mv); - return FN(MULTI(BASE),free)(multi); + return FN(MULTI(BASE),fn_multi_val)(multi, &FN(EL,scale_val), mv); } /* Divide the elements of "multi" by the corresponding element of "mv" @@ -148,34 +93,7 @@ error: __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_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->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i], v); - if (!multi->u.p[i]) - goto error; - } - - isl_multi_val_free(mv); - return multi; -error: - isl_multi_val_free(mv); - return FN(MULTI(BASE),free)(multi); + return FN(MULTI(BASE),fn_multi_val)(multi, &FN(EL,scale_down_val), mv); } /* Compute the residues of the elements of "multi" modulo @@ -184,51 +102,12 @@ error: __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) - goto error; - - for (i = 0; i < multi->n; ++i) { - isl_val *v; - - v = isl_multi_val_get_val(mv, i); - multi->u.p[i] = FN(EL,mod_val)(multi->u.p[i], v); - if (!multi->u.p[i]) - goto error; - } - - isl_multi_val_free(mv); - return multi; -error: - isl_multi_val_free(mv); - return FN(MULTI(BASE),free)(multi); + return FN(MULTI(BASE),fn_multi_val)(multi, &FN(EL,mod_val), mv); } /* 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->u.p[i] = FN(EL,neg)(multi->u.p[i]); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); - } - - return multi; + return FN(MULTI(BASE),un_op)(multi, &FN(EL,neg)); } diff --git a/polly/lib/External/isl/isl_multi_bin_val_templ.c b/polly/lib/External/isl/isl_multi_bin_val_templ.c new file mode 100644 index 0000000..a7a3913 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_bin_val_templ.c @@ -0,0 +1,73 @@ +/* + * 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 + */ + +/* Apply "fn" to each of the elements of "multi" with as second argument "v". + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),fn_val)( + __isl_take MULTI(BASE) *multi, + __isl_give EL *(*fn)(__isl_take EL *el, __isl_take isl_val *v), + __isl_take isl_val *v) +{ + isl_size n; + int i; + + n = FN(MULTI(BASE),size)(multi); + if (n < 0 || !v) + goto error; + + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = fn(el, isl_val_copy(v)); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); + } + + isl_val_free(v); + return multi; +error: + isl_val_free(v); + FN(MULTI(BASE),free)(multi); + return NULL; +} + +#undef TYPE +#define TYPE MULTI(BASE) +#include "isl_type_check_match_range_multi_val.c" + +/* Elementwise apply "fn" to "multi" and "mv". + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),fn_multi_val)( + __isl_take MULTI(BASE) *multi, + __isl_give EL *(*fn)(__isl_take EL *el, __isl_take isl_val *v), + __isl_take isl_multi_val *mv) +{ + isl_size n; + int i; + + n = FN(MULTI(BASE),size)(multi); + if (n < 0 || FN(MULTI(BASE),check_match_range_multi_val)(multi, mv) < 0) + goto error; + + for (i = 0; i < n; ++i) { + isl_val *v; + EL *el; + + v = isl_multi_val_get_val(mv, i); + el = FN(MULTI(BASE),take_at)(multi, i); + el = fn(el, v); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); + } + + isl_multi_val_free(mv); + return multi; +error: + isl_multi_val_free(mv); + return FN(MULTI(BASE),free)(multi); +} diff --git a/polly/lib/External/isl/isl_multi_dim_id_templ.c b/polly/lib/External/isl/isl_multi_dim_id_templ.c index 80dd7db..5103edf 100644 --- a/polly/lib/External/isl/isl_multi_dim_id_templ.c +++ b/polly/lib/External/isl/isl_multi_dim_id_templ.c @@ -47,26 +47,12 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)( __isl_take MULTI(BASE) *multi, enum isl_dim_type type, unsigned pos, const char *s) { - int i; - - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; - - multi->space = isl_space_set_dim_name(multi->space, type, pos, s); - if (!multi->space) - return FN(MULTI(BASE),free)(multi); + isl_space *space; - if (type == isl_dim_out) - return multi; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,set_dim_name)(multi->u.p[i], - type, pos, s); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); - } + space = FN(MULTI(BASE),get_space)(multi); + space = isl_space_set_dim_name(space, type, pos, s); - return multi; + return FN(MULTI(BASE),reset_space)(multi, space); } /* Set the id of the given dimension of "multi" to "id". @@ -77,16 +63,8 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)( { isl_space *space; - multi = FN(MULTI(BASE),cow)(multi); - if (!multi || !id) - goto error; - space = FN(MULTI(BASE),get_space)(multi); space = isl_space_set_dim_id(space, type, pos, id); return FN(MULTI(BASE),reset_space)(multi, space); -error: - isl_id_free(id); - FN(MULTI(BASE),free)(multi); - return NULL; } diff --git a/polly/lib/External/isl/isl_multi_dims.c b/polly/lib/External/isl/isl_multi_dims.c index a2775ea..fb5cb11 100644 --- a/polly/lib/External/isl/isl_multi_dims.c +++ b/polly/lib/External/isl/isl_multi_dims.c @@ -45,10 +45,13 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)( __isl_take MULTI(BASE) *multi, enum isl_dim_type type, unsigned first, unsigned n) { + isl_space *space; + isl_size size; int i; - if (!multi) - return NULL; + size = FN(MULTI(BASE),size)(multi); + if (size < 0) + return FN(MULTI(BASE),free)(multi); if (type == isl_dim_out) isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, "cannot insert output/set dimensions", @@ -56,24 +59,20 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)( if (n == 0 && !isl_space_is_named_or_nested(multi->space, type)) return multi; - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; + space = FN(MULTI(BASE),take_space)(multi); + space = isl_space_insert_dims(space, type, first, n); + multi = FN(MULTI(BASE),restore_space)(multi, space); - multi->space = isl_space_insert_dims(multi->space, type, first, n); - if (!multi->space) - return FN(MULTI(BASE),free)(multi); if (FN(MULTI(BASE),has_explicit_domain)(multi)) multi = FN(MULTI(BASE),insert_explicit_domain_dims)(multi, type, first, n); - if (!multi) - return NULL; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,insert_dims)(multi->u.p[i], - type, first, n); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); + for (i = 0; i < size; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = FN(EL,insert_dims)(el, type, first, n); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } return multi; diff --git a/polly/lib/External/isl/isl_multi_floor.c b/polly/lib/External/isl/isl_multi_floor.c index b9a8898..0d8420f 100644 --- a/polly/lib/External/isl/isl_multi_floor.c +++ b/polly/lib/External/isl/isl_multi_floor.c @@ -13,17 +13,5 @@ */ __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->u.p[i] = FN(EL,floor)(multi->u.p[i]); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); - } - - return multi; + return FN(MULTI(BASE),un_op)(multi, &FN(EL,floor)); } diff --git a/polly/lib/External/isl/isl_multi_from_tuple_templ.c b/polly/lib/External/isl/isl_multi_from_tuple_templ.c new file mode 100644 index 0000000..46d35cc --- /dev/null +++ b/polly/lib/External/isl/isl_multi_from_tuple_templ.c @@ -0,0 +1,46 @@ +/* + * Copyright 2011 Sven Verdoolaege + * Copyright 2012 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 + +/* Extract a multi expression with domain space "dom_space" + * from a tuple "tuple" that was read by read_tuple. + * + * Check that none of the expressions depend on any other output/set dimensions. + */ +static MULTI(BASE) *FN(MULTI(BASE),from_tuple)( + __isl_take isl_space *dom_space, __isl_take isl_multi_pw_aff *tuple) +{ + int i; + isl_size dim, n; + isl_space *space; + MULTI(BASE) *multi; + + n = isl_multi_pw_aff_dim(tuple, isl_dim_out); + dim = isl_space_dim(dom_space, isl_dim_all); + if (n < 0 || dim < 0) + dom_space = isl_space_free(dom_space); + space = isl_space_range(isl_multi_pw_aff_get_space(tuple)); + space = isl_space_align_params(space, isl_space_copy(dom_space)); + if (!isl_space_is_params(dom_space)) + space = isl_space_map_from_domain_and_range( + isl_space_copy(dom_space), space); + isl_space_free(dom_space); + multi = FN(MULTI(BASE),alloc)(space); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + pa = isl_multi_pw_aff_get_pw_aff(tuple, i); + multi = FN(MULTI(BASE),set_tuple_entry)(multi, pa, i, dim, n); + } + + isl_multi_pw_aff_free(tuple); + return multi; +} diff --git a/polly/lib/External/isl/isl_multi_move_dims_templ.c b/polly/lib/External/isl/isl_multi_move_dims_templ.c index 9c88085..ba9830e 100644 --- a/polly/lib/External/isl/isl_multi_move_dims_templ.c +++ b/polly/lib/External/isl/isl_multi_move_dims_templ.c @@ -20,10 +20,13 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi, enum isl_dim_type dst_type, unsigned dst_pos, enum isl_dim_type src_type, unsigned src_pos, unsigned n) { + isl_space *space; + isl_size size; int i; - if (!multi) - return NULL; + size = FN(MULTI(BASE),size)(multi); + if (size < 0) + return FN(MULTI(BASE),free)(multi); if (n == 0 && !isl_space_is_named_or_nested(multi->space, src_type) && @@ -45,26 +48,22 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi, "moving dims within the same type not supported", return FN(MULTI(BASE),free)(multi)); - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; - - multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos, + space = FN(MULTI(BASE),take_space)(multi); + space = isl_space_move_dims(space, dst_type, dst_pos, src_type, src_pos, n); - if (!multi->space) - return FN(MULTI(BASE),free)(multi); + multi = FN(MULTI(BASE),restore_space)(multi, space); + if (FN(MULTI(BASE),has_explicit_domain)(multi)) multi = FN(MULTI(BASE),move_explicit_domain_dims)(multi, dst_type, dst_pos, src_type, src_pos, n); - if (!multi) - return NULL; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,move_dims)(multi->u.p[i], - dst_type, dst_pos, + for (i = 0; i < size; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = FN(EL,move_dims)(el, dst_type, dst_pos, src_type, src_pos, n); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } return multi; diff --git a/polly/lib/External/isl/isl_multi_pw_aff_pullback_templ.c b/polly/lib/External/isl/isl_multi_pw_aff_pullback_templ.c new file mode 100644 index 0000000..fc5aed2 --- /dev/null +++ b/polly/lib/External/isl/isl_multi_pw_aff_pullback_templ.c @@ -0,0 +1,73 @@ +/* + * 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 + */ + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,BASE) +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +#undef SUFFIX +#define SUFFIX BASE +#undef ARG1 +#define ARG1 isl_multi_pw_aff +#undef ARG2 +#define ARG2 TYPE + +static +#include "isl_align_params_templ.c" + +/* Compute the pullback of "mpa" by the function represented by "fn". + * In other words, plug in "fn" in "mpa". + * + * If "mpa" has an explicit domain, then it is this domain + * that needs to undergo a pullback, i.e., a preimage. + */ +__isl_give isl_multi_pw_aff *FN(isl_multi_pw_aff_pullback,BASE)( + __isl_take isl_multi_pw_aff *mpa, __isl_take TYPE *fn) +{ + int i; + isl_size n; + isl_space *space = NULL; + + FN(isl_multi_pw_aff_align_params,BASE)(&mpa, &fn); + mpa = isl_multi_pw_aff_cow(mpa); + n = isl_multi_pw_aff_size(mpa); + if (n < 0 || !fn) + goto error; + + space = isl_space_join(FN(TYPE,get_space)(fn), + isl_multi_pw_aff_get_space(mpa)); + + for (i = 0; i < n; ++i) { + isl_pw_aff *pa; + + pa = isl_multi_pw_aff_take_at(mpa, i); + pa = FN(isl_pw_aff_pullback,BASE)(pa, FN(TYPE,copy)(fn)); + mpa = isl_multi_pw_aff_restore_at(mpa, i, pa); + if (!mpa) + goto error; + } + if (isl_multi_pw_aff_has_explicit_domain(mpa)) { + mpa->u.dom = FN(isl_set_preimage,BASE)(mpa->u.dom, + FN(TYPE,copy)(fn)); + if (!mpa->u.dom) + goto error; + } + + FN(TYPE,free)(fn); + isl_multi_pw_aff_restore_space(mpa, space); + return mpa; +error: + isl_space_free(space); + isl_multi_pw_aff_free(mpa); + FN(TYPE,free)(fn); + return NULL; +} diff --git a/polly/lib/External/isl/isl_multi_read_no_explicit_domain_templ.c b/polly/lib/External/isl/isl_multi_read_no_explicit_domain_templ.c index b8a6ec5..6baf562 100644 --- a/polly/lib/External/isl/isl_multi_read_no_explicit_domain_templ.c +++ b/polly/lib/External/isl/isl_multi_read_no_explicit_domain_templ.c @@ -79,16 +79,6 @@ error: return NULL; } -/* Read a multi expression from "str". - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),read_from_str)(isl_ctx *ctx, - const char *str) -{ - MULTI(BASE) *multi; - isl_stream *s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - multi = FN(isl_stream_read_multi,BASE)(s); - isl_stream_free(s); - return multi; -} +#undef TYPE_BASE +#define TYPE_BASE CAT(multi_,BASE) +#include "isl_read_from_str_templ.c" diff --git a/polly/lib/External/isl/isl_multi_templ.c b/polly/lib/External/isl/isl_multi_templ.c index 3777024..6e0a6ed 100644 --- a/polly/lib/External/isl/isl_multi_templ.c +++ b/polly/lib/External/isl/isl_multi_templ.c @@ -138,6 +138,56 @@ __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi) return NULL; } +/* Return the space of "multi". + * The caller is not allowed to modify "multi" between this call + * and the call to *_restore_space because the number + * of references needs to stay the same. + * The only exception is that isl_multi_*_free can be called instead. + * No copy is taken of multi->space if "multi" has only one reference + * such that it can be modified inplace if both have only a single reference. + */ +__isl_give isl_space *FN(MULTI(BASE),take_space)(__isl_keep MULTI(BASE) *multi) +{ + isl_space *space; + + if (!multi) + return NULL; + if (multi->ref != 1) + return FN(MULTI(BASE),get_space)(multi); + space = multi->space; + multi->space = NULL; + return space; +} + +/* Set the space of "multi" to "space", where the space of "multi" + * may be missing due to a preceding call to isl_multi_*_take_space. + * However, in this case, "multi" only has a single reference and + * then the call to isl_multi_*_cow has no effect. + */ +__isl_give MULTI(BASE) *FN(MULTI(BASE),restore_space)( + __isl_take MULTI(BASE) *multi, __isl_take isl_space *space) +{ + if (!multi || !space) + goto error; + + if (multi->space == space) { + isl_space_free(space); + return multi; + } + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + goto error; + isl_space_free(multi->space); + multi->space = space; + + return multi; +error: + FN(MULTI(BASE),free)(multi); + isl_space_free(space); + return NULL; +} + isl_size FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi, enum isl_dim_type type) { @@ -156,16 +206,21 @@ isl_size FN(MULTI(BASE),size)(__isl_keep MULTI(BASE) *multi) static #include "check_type_range_templ.c" -/* Return a copy of the base expression at position "pos" in "multi". +/* Return the base expression at position "pos" in "multi". */ -__isl_give EL *FN(MULTI(BASE),get_at)(__isl_keep MULTI(BASE) *multi, int pos) +static __isl_give EL *FN(MULTI(BASE),peek_at)(__isl_keep MULTI(BASE) *multi, + int pos) { - isl_ctx *ctx; - if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0) return NULL; - ctx = FN(MULTI(BASE),get_ctx)(multi); - return FN(EL,copy)(multi->u.p[pos]); + return multi->u.p[pos]; +} + +/* Return a copy of the base expression at position "pos" in "multi". + */ +__isl_give EL *FN(MULTI(BASE),get_at)(__isl_keep MULTI(BASE) *multi, int pos) +{ + return FN(EL,copy)(FN(MULTI(BASE),peek_at)(multi, pos)); } /* This is an alternative name for the function above. @@ -176,17 +231,48 @@ __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi, return FN(MULTI(BASE),get_at)(multi, pos); } +/* Return the base expression at position "pos" in "multi". + * This may be either a copy or the base expression itself + * if there is only one reference to "multi". + * This allows the base expression to be modified inplace + * if both the multi expression and this base expression + * have only a single reference. + * The caller is not allowed to modify "multi" between this call and + * the subsequent call to isl_multi_*_restore_at_*. + * The only exception is that isl_multi_*_free can be called instead. + */ +static __isl_give EL *FN(MULTI(BASE),take_at)(__isl_keep MULTI(BASE) *multi, + int pos) +{ + EL *el; + + if (!multi) + return NULL; + if (multi->ref != 1) + return FN(MULTI(BASE),get_at)(multi, pos); + if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0) + return NULL; + el = multi->u.p[pos]; + multi->u.p[pos] = NULL; + return el; +} + /* Set the element at position "pos" of "multi" to "el", * where the position may be empty if "multi" has only a single reference. */ -static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore)( +static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_at)( __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el) { - multi = FN(MULTI(BASE),cow)(multi); - if (!multi || !el) + if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0 || !el) goto error; - if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0) + if (multi->u.p[pos] == el) { + FN(EL,free)(el); + return multi; + } + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) goto error; FN(EL,free)(multi->u.p[pos]); @@ -212,7 +298,7 @@ static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_check_space)( space = FN(MULTI(BASE),peek_space)(multi); if (FN(EL,check_match_domain_space)(el, space) < 0) multi = FN(MULTI(BASE),free)(multi); - return FN(MULTI(BASE),restore)(multi, pos, el); + return FN(MULTI(BASE),restore_at)(multi, pos, el); } /* Replace the base expression at position "pos" in "multi" with "el". @@ -293,27 +379,26 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)( __isl_take MULTI(BASE) *multi, __isl_take isl_space *space, __isl_take isl_space *domain) { + isl_size n; int i; - multi = FN(MULTI(BASE),cow)(multi); - if (!multi || !space || !domain) + n = FN(MULTI(BASE),size)(multi); + if (n < 0 || !space || !domain) goto error; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,reset_domain_space)(multi->u.p[i], - isl_space_copy(domain)); - if (!multi->u.p[i]) - goto error; + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = FN(EL,reset_domain_space)(el, isl_space_copy(domain)); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } - if (FN(MULTI(BASE),has_explicit_domain)(multi)) { + if (FN(MULTI(BASE),has_explicit_domain)(multi)) multi = FN(MULTI(BASE),reset_explicit_domain_space)(multi, isl_space_copy(domain)); - if (!multi) - goto error; - } isl_space_free(domain); - isl_space_free(multi->space); - multi->space = space; + + multi = FN(MULTI(BASE),restore_space)(multi, space); return multi; error: @@ -326,10 +411,11 @@ error: __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)( __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain) { - isl_space *space; + isl_space *space, *multi_space; + multi_space = FN(MULTI(BASE),get_space)(multi); space = isl_space_extend_domain_with_range(isl_space_copy(domain), - isl_space_copy(multi->space)); + multi_space); return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain); } @@ -360,17 +446,19 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)( __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp) { int i; + isl_size n; isl_space *space; - multi = FN(MULTI(BASE),cow)(multi); - if (!multi || !exp) + n = FN(MULTI(BASE),size)(multi); + if (n < 0 || !exp) goto error; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,realign_domain)(multi->u.p[i], - isl_reordering_copy(exp)); - if (!multi->u.p[i]) - goto error; + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = FN(EL,realign_domain)(el, isl_reordering_copy(exp)); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } space = isl_reordering_get_space(exp); @@ -394,6 +482,7 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)( { isl_ctx *ctx; isl_bool equal_params; + isl_space *domain_space; isl_reordering *exp; if (!multi || !model) @@ -421,9 +510,9 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)( if (!multi) goto error; } - exp = isl_parameter_alignment_reordering(multi->space, model); - exp = isl_reordering_extend_space(exp, - FN(MULTI(BASE),get_domain_space)(multi)); + domain_space = FN(MULTI(BASE),get_domain_space)(multi); + exp = isl_parameter_alignment_reordering(domain_space, model); + isl_space_free(domain_space); multi = FN(MULTI(BASE),realign_domain)(multi, exp); isl_space_free(model); @@ -488,42 +577,60 @@ __isl_give MULTI(BASE) *FN(isl_space_multi,BASE)(__isl_take isl_space *space, return FN(FN(MULTI(BASE),from),LIST(BASE))(space, list); } +/* Drop the "n" output dimensions of "multi" starting at "first", + * where the space is assumed to have been adjusted already. + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_output_dims)( + __isl_take MULTI(BASE) *multi, unsigned first, unsigned n) +{ + int i; + + multi = FN(MULTI(BASE),cow)(multi); + if (!multi) + return NULL; + + for (i = 0; i < n; ++i) + FN(EL,free)(multi->u.p[first + i]); + for (i = first; i + n < multi->n; ++i) + multi->u.p[i] = multi->u.p[i + n]; + multi->n -= n; + if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi)) + multi = FN(MULTI(BASE),init_explicit_domain)(multi); + + return multi; +} + __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)( __isl_take MULTI(BASE) *multi, enum isl_dim_type type, unsigned first, unsigned n) { + isl_space *space; + isl_size size; int i; - multi = FN(MULTI(BASE),cow)(multi); if (FN(MULTI(BASE),check_range)(multi, type, first, n) < 0) return FN(MULTI(BASE),free)(multi); - multi->space = isl_space_drop_dims(multi->space, type, first, n); - if (!multi->space) - return FN(MULTI(BASE),free)(multi); - - if (type == isl_dim_out) { - for (i = 0; i < n; ++i) - FN(EL,free)(multi->u.p[first + i]); - for (i = first; i + n < multi->n; ++i) - multi->u.p[i] = multi->u.p[i + n]; - multi->n -= n; - if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi)) - multi = FN(MULTI(BASE),init_explicit_domain)(multi); + space = FN(MULTI(BASE),take_space)(multi); + space = isl_space_drop_dims(space, type, first, n); + multi = FN(MULTI(BASE),restore_space)(multi, space); - return multi; - } + if (type == isl_dim_out) + return FN(MULTI(BASE),drop_output_dims)(multi, first, n); if (FN(MULTI(BASE),has_explicit_domain)(multi)) multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi, type, first, n); - if (!multi) - return NULL; - for (i = 0; i < multi->n; ++i) { - multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n); - if (!multi->u.p[i]) - return FN(MULTI(BASE),free)(multi); + size = FN(MULTI(BASE),size)(multi); + if (size < 0) + return FN(MULTI(BASE),free)(multi); + for (i = 0; i < size; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = FN(EL,drop_dims)(el, type, first, n); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); } return multi; @@ -678,19 +785,11 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)( __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)( __isl_take MULTI(BASE) *multi) { - if (!multi) - return NULL; - - if (!multi->space->nested[1]) - return multi; - - multi = FN(MULTI(BASE),cow)(multi); - if (!multi) - return NULL; + isl_space *space; - multi->space = isl_space_flatten_range(multi->space); - if (!multi->space) - return FN(MULTI(BASE),free)(multi); + space = FN(MULTI(BASE),take_space)(multi); + space = isl_space_flatten_range(space); + multi = FN(MULTI(BASE),restore_space)(multi, space); return multi; } @@ -773,18 +872,21 @@ static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)( __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2, __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *)) { + isl_size n; int i; FN(MULTI(BASE),align_params_bin)(&multi1, &multi2); - multi1 = FN(MULTI(BASE),cow)(multi1); - if (FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0) + n = FN(MULTI(BASE),size)(multi1); + if (n < 0 || FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0) goto error; - for (i = 0; i < multi1->n; ++i) { - multi1->u.p[i] = fn(multi1->u.p[i], - FN(EL,copy)(multi2->u.p[i])); - if (!multi1->u.p[i]) - goto error; + for (i = 0; i < n; ++i) { + EL *el1, *el2; + + el2 = FN(MULTI(BASE),get_at)(multi2, i); + el1 = FN(MULTI(BASE),take_at)(multi1, i); + el1 = fn(el1, el2); + multi1 = FN(MULTI(BASE),restore_at)(multi1, i, el1); } if (FN(MULTI(BASE),has_explicit_domain)(multi2)) @@ -851,27 +953,9 @@ static isl_bool FN(MULTI(BASE),every)(__isl_keep MULTI(BASE) *multi, return isl_bool_true; } -/* Convert a multiple expression defined over a parameter domain - * into one that is defined over a zero-dimensional set. - */ -__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)( - __isl_take MULTI(BASE) *multi) -{ - isl_space *space; - - if (!multi) - return NULL; - if (!isl_space_is_set(multi->space)) - isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid, - "not living in a set space", - return FN(MULTI(BASE),free)(multi)); - - space = FN(MULTI(BASE),get_space)(multi); - space = isl_space_from_range(space); - multi = FN(MULTI(BASE),reset_space)(multi, space); - - return multi; -} +#undef TYPE +#define TYPE MULTI(BASE) +#include "isl_from_range_templ.c" /* Are "multi1" and "multi2" obviously equal? */ diff --git a/polly/lib/External/isl/isl_multi_un_op_templ.c b/polly/lib/External/isl/isl_multi_un_op_templ.c new file mode 100644 index 0000000..bbf105b --- /dev/null +++ b/polly/lib/External/isl/isl_multi_un_op_templ.c @@ -0,0 +1,33 @@ +/* + * 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 + +/* Apply "fn" to each of the base expressions of "multi". + */ +static __isl_give MULTI(BASE) *FN(MULTI(BASE),un_op)( + __isl_take MULTI(BASE) *multi, __isl_give EL *(*fn)(__isl_take EL *el)) +{ + int i; + isl_size n; + + n = FN(MULTI(BASE),size)(multi); + if (n < 0) + return FN(MULTI(BASE),free)(multi); + + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(MULTI(BASE),take_at)(multi, i); + el = fn(el); + multi = FN(MULTI(BASE),restore_at)(multi, i, el); + } + + return multi; +} diff --git a/polly/lib/External/isl/isl_output.c b/polly/lib/External/isl/isl_output.c index 9839a52..df49364 100644 --- a/polly/lib/External/isl/isl_output.c +++ b/polly/lib/External/isl/isl_output.c @@ -1456,8 +1456,8 @@ static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p, return p; } -static __isl_give isl_printer *isl_map_print_isl_body(__isl_keep isl_map *map, - __isl_take isl_printer *p) +static __isl_give isl_printer *print_body_map(__isl_take isl_printer *p, + __isl_keep isl_map *map) { struct isl_print_space_data data = { 0 }; struct isl_aff_split *split = NULL; @@ -1486,7 +1486,7 @@ static __isl_give isl_printer *isl_map_print_isl(__isl_keep isl_map *map, p = print_param_tuple(p, map->dim, &data); p = isl_printer_print_str(p, s_open_set[0]); - p = isl_map_print_isl_body(map, p); + p = print_body_map(p, map); p = isl_printer_print_str(p, s_close_set[0]); return p; } @@ -1617,37 +1617,9 @@ struct isl_union_print_data { int first; }; -static isl_stat print_map_body(__isl_take isl_map *map, 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 = isl_map_print_isl_body(map, data->p); - isl_map_free(map); - - return isl_stat_ok; -} - -/* Print the body of "umap" (everything except the parameter declarations) - * to "p" in isl format. - */ -static __isl_give isl_printer *isl_printer_print_union_map_isl_body( - __isl_take isl_printer *p, __isl_keep isl_union_map *umap) -{ - struct isl_union_print_data data; - - p = isl_printer_print_str(p, s_open_set[0]); - data.p = p; - data.first = 1; - isl_union_map_foreach_map(umap, &print_map_body, &data); - p = data.p; - p = isl_printer_print_str(p, s_close_set[0]); - return p; -} +#undef BASE +#define BASE map +#include "isl_union_print_templ.c" /* Print the body of "uset" (everything except the parameter declarations) * to "p" in isl format. @@ -1655,24 +1627,7 @@ static __isl_give isl_printer *isl_printer_print_union_map_isl_body( static __isl_give isl_printer *isl_printer_print_union_set_isl_body( __isl_take isl_printer *p, __isl_keep isl_union_set *uset) { - return isl_printer_print_union_map_isl_body(p, uset_to_umap(uset)); -} - -/* Print the isl_union_map "umap" to "p" in isl format. - */ -static __isl_give isl_printer *isl_union_map_print_isl( - __isl_keep isl_union_map *umap, __isl_take isl_printer *p) -{ - struct isl_print_space_data space_data = { 0 }; - isl_space *space; - - space = isl_union_map_get_space(umap); - p = print_param_tuple(p, space, &space_data); - isl_space_free(space); - - p = isl_printer_print_union_map_isl_body(p, umap); - - return p; + return print_body_union_map(p, uset_to_umap(uset)); } static isl_stat print_latex_map_body(__isl_take isl_map *map, void *user) @@ -1706,7 +1661,7 @@ __isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p, goto error; if (p->output_format == ISL_FORMAT_ISL) - return isl_union_map_print_isl(umap, p); + return print_union_map_isl(p, umap); if (p->output_format == ISL_FORMAT_LATEX) return isl_union_map_print_latex(umap, p); @@ -1724,7 +1679,7 @@ __isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p, goto error; if (p->output_format == ISL_FORMAT_ISL) - return isl_union_map_print_isl(uset_to_umap(uset), p); + return print_union_map_isl(p, uset_to_umap(uset)); if (p->output_format == ISL_FORMAT_LATEX) return isl_union_map_print_latex(uset_to_umap(uset), p); @@ -2028,7 +1983,7 @@ void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold, isl_printer_free(p); } -static __isl_give isl_printer *isl_pwqp_print_isl_body( +static __isl_give isl_printer *print_body_pw_qpolynomial( __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) { struct isl_print_space_data data = { 0 }; @@ -2069,7 +2024,7 @@ static __isl_give isl_printer *print_pw_qpolynomial_isl( } p = isl_printer_print_str(p, "0"); } - p = isl_pwqp_print_isl_body(p, pwqp); + p = print_body_pw_qpolynomial(p, pwqp); p = isl_printer_print_str(p, " }"); return p; error: @@ -2092,7 +2047,7 @@ void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out, isl_printer_free(p); } -static __isl_give isl_printer *isl_pwf_print_isl_body( +static __isl_give isl_printer *print_body_pw_qpolynomial_fold( __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) { struct isl_print_space_data data = { 0 }; @@ -2130,7 +2085,7 @@ static __isl_give isl_printer *print_pw_qpolynomial_fold_isl( } p = isl_printer_print_str(p, "0"); } - p = isl_pwf_print_isl_body(p, pwf); + p = print_body_pw_qpolynomial_fold(p, pwf); p = isl_printer_print_str(p, " }"); return p; } @@ -2287,40 +2242,9 @@ error: return NULL; } -static isl_stat print_pwqp_body(__isl_take isl_pw_qpolynomial *pwqp, 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 = isl_pwqp_print_isl_body(data->p, pwqp); - isl_pw_qpolynomial_free(pwqp); - - return isl_stat_ok; -} - -static __isl_give isl_printer *print_union_pw_qpolynomial_isl( - __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp) -{ - struct isl_union_print_data data; - struct isl_print_space_data space_data = { 0 }; - isl_space *space; - - space = isl_union_pw_qpolynomial_get_space(upwqp); - p = print_param_tuple(p, space, &space_data); - isl_space_free(space); - p = isl_printer_print_str(p, "{ "); - data.p = p; - data.first = 1; - isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &print_pwqp_body, - &data); - p = data.p; - p = isl_printer_print_str(p, " }"); - return p; -} +#undef BASE +#define BASE pw_qpolynomial +#include "isl_union_print_templ.c" __isl_give isl_printer *isl_printer_print_union_pw_qpolynomial( __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp) @@ -2447,42 +2371,9 @@ void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf, isl_printer_free(p); } -static isl_stat print_pwf_body(__isl_take isl_pw_qpolynomial_fold *pwf, - 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 = isl_pwf_print_isl_body(data->p, pwf); - isl_pw_qpolynomial_fold_free(pwf); - - return isl_stat_ok; -} - -static __isl_give isl_printer *print_union_pw_qpolynomial_fold_isl( - __isl_take isl_printer *p, - __isl_keep isl_union_pw_qpolynomial_fold *upwf) -{ - struct isl_union_print_data data; - struct isl_print_space_data space_data = { 0 }; - isl_space *space; - - space = isl_union_pw_qpolynomial_fold_get_space(upwf); - p = print_param_tuple(p, space, &space_data); - isl_space_free(space); - p = isl_printer_print_str(p, "{ "); - data.p = p; - data.first = 1; - isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(upwf, - &print_pwf_body, &data); - p = data.p; - p = isl_printer_print_str(p, " }"); - return p; -} +#undef BASE +#define BASE pw_qpolynomial_fold +#include "isl_union_print_templ.c" __isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold( __isl_take isl_printer *p, @@ -2806,7 +2697,7 @@ static __isl_give isl_printer *print_aff_body(__isl_take isl_printer *p, return p; } -static __isl_give isl_printer *print_aff(__isl_take isl_printer *p, +static __isl_give isl_printer *print_body_aff(__isl_take isl_printer *p, __isl_keep isl_aff *aff) { struct isl_print_space_data data = { 0 }; @@ -2834,7 +2725,7 @@ static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p, p = print_param_tuple(p, aff->ls->dim, &data); p = isl_printer_print_str(p, "{ "); - p = print_aff(p, aff); + p = print_body_aff(p, aff); p = isl_printer_print_str(p, " }"); return p; error: @@ -2842,48 +2733,9 @@ 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) { - isl_space *space; - - if (i) - p = isl_printer_print_str(p, "; "); - p = print_aff(p, pa->p[i].aff); - space = isl_aff_get_domain_space(pa->p[i].aff); - p = print_disjuncts(set_to_map(pa->p[i].set), space, p, 0); - isl_space_free(space); - } - - 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 }; - - if (!pwaff) - goto error; - - p = print_param_tuple(p, pwaff->dim, &data); - p = isl_printer_print_str(p, "{ "); - p = print_pw_aff_body(p, pwaff); - p = isl_printer_print_str(p, " }"); - return p; -error: - isl_printer_free(p); - return NULL; -} +#undef BASE +#define BASE aff +#include "isl_pw_print_templ.c" static __isl_give isl_printer *print_ls_name_c(__isl_take isl_printer *p, __isl_keep isl_local_space *ls, enum isl_dim_type type, unsigned pos) @@ -3048,64 +2900,9 @@ 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 isl_stat 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 ? isl_stat_ok : isl_stat_error; -} - -/* 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(data.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); - p = print_param_tuple(p, space, &data); - isl_space_free(space); - p = print_union_pw_aff_body(p, upa); - return p; -} +#undef BASE +#define BASE pw_aff +#include "isl_union_print_templ.c" /* Print the isl_union_pw_aff "upa" to "p". * @@ -3153,7 +2950,7 @@ static __isl_give isl_printer *print_dim_ma(__isl_take isl_printer *p, return p; } -static __isl_give isl_printer *print_multi_aff(__isl_take isl_printer *p, +static __isl_give isl_printer *print_body_multi_aff(__isl_take isl_printer *p, __isl_keep isl_multi_aff *maff) { struct isl_print_space_data data = { 0 }; @@ -3173,7 +2970,7 @@ static __isl_give isl_printer *print_multi_aff_isl(__isl_take isl_printer *p, p = print_param_tuple(p, maff->space, &data); p = isl_printer_print_str(p, "{ "); - p = print_multi_aff(p, maff); + p = print_body_multi_aff(p, maff); p = isl_printer_print_str(p, " }"); return p; error: @@ -3196,47 +2993,9 @@ error: return NULL; } -static __isl_give isl_printer *print_pw_multi_aff_body( - __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) -{ - int i; - - if (!pma) - goto error; - - for (i = 0; i < pma->n; ++i) { - isl_space *space; - - if (i) - p = isl_printer_print_str(p, "; "); - p = print_multi_aff(p, pma->p[i].maff); - space = isl_multi_aff_get_domain_space(pma->p[i].maff); - p = print_disjuncts(set_to_map(pma->p[i].set), space, p, 0); - isl_space_free(space); - } - return p; -error: - isl_printer_free(p); - return NULL; -} - -static __isl_give isl_printer *print_pw_multi_aff_isl(__isl_take isl_printer *p, - __isl_keep isl_pw_multi_aff *pma) -{ - struct isl_print_space_data data = { 0 }; - - if (!pma) - goto error; - - p = print_param_tuple(p, pma->dim, &data); - p = isl_printer_print_str(p, "{ "); - p = print_pw_multi_aff_body(p, pma); - p = isl_printer_print_str(p, " }"); - return p; -error: - isl_printer_free(p); - return NULL; -} +#undef BASE +#define BASE multi_aff +#include "isl_pw_print_templ.c" /* Print the unnamed, single-dimensional piecewise multi affine expression "pma" * to "p". @@ -3311,41 +3070,9 @@ error: return NULL; } -static isl_stat print_pw_multi_aff_body_wrap(__isl_take isl_pw_multi_aff *pma, - 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_multi_aff_body(data->p, pma); - isl_pw_multi_aff_free(pma); - - return isl_stat_ok; -} - -static __isl_give isl_printer *print_union_pw_multi_aff_isl( - __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma) -{ - struct isl_union_print_data data; - struct isl_print_space_data space_data = { 0 }; - isl_space *space; - - space = isl_union_pw_multi_aff_get_space(upma); - p = print_param_tuple(p, space, &space_data); - isl_space_free(space); - p = isl_printer_print_str(p, s_open_set[0]); - data.p = p; - data.first = 1; - isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, - &print_pw_multi_aff_body_wrap, &data); - p = data.p; - p = isl_printer_print_str(p, s_close_set[0]); - return p; -} +#undef BASE +#define BASE pw_multi_aff +#include "isl_union_print_templ.c" __isl_give isl_printer *isl_printer_print_union_pw_multi_aff( __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma) @@ -3580,7 +3307,7 @@ static __isl_give isl_printer *print_union_pw_aff_dim(__isl_take isl_printer *p, 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); + p = print_body_union_pw_aff(p, upa); isl_union_pw_aff_free(upa); return p; diff --git a/polly/lib/External/isl/isl_point.c b/polly/lib/External/isl/isl_point.c index f7da706..f315b3d 100644 --- a/polly/lib/External/isl/isl_point.c +++ b/polly/lib/External/isl/isl_point.c @@ -2,7 +2,7 @@ * Copyright 2010 INRIA Saclay * Copyright 2013 Ecole Normale Superieure * Copyright 2015 Sven Verdoolaege - * Copyright 2019 Cerebras Systems + * Copyright 2019,2022 Cerebras Systems * * Use of this software is governed by the MIT license * @@ -11,6 +11,7 @@ * 91893 Orsay, France * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA + * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA */ #include @@ -57,6 +58,11 @@ static static #include "isl_type_check_equal_space_templ.c" +#undef TYPE +#define TYPE isl_point + +#include "isl_check_named_params_templ.c" + __isl_give isl_point *isl_point_alloc(__isl_take isl_space *space, __isl_take isl_vec *vec) { @@ -304,6 +310,60 @@ static isl_size isl_point_var_offset(__isl_keep isl_point *pnt, return pnt ? isl_space_offset(pnt->dim, type) : isl_size_error; } +/* Reorder the coordinates of "pnt" based on the given reordering. + */ +static __isl_give isl_point *isl_point_reorder(__isl_take isl_point *pnt, + __isl_take isl_reordering *r) +{ + isl_vec *vec; + + isl_space_free(isl_point_take_space(pnt)); + pnt = isl_point_restore_space(pnt, isl_reordering_get_space(r)); + + vec = isl_point_take_vec(pnt); + vec = isl_vec_reorder(vec, 1, isl_reordering_copy(r)); + pnt = isl_point_restore_vec(pnt, vec); + + return pnt; +} + +/* Align the parameters of "pnt" along those of "model". + * + * Note that "model" is not allowed to have any parameters + * that do not already appear in "pnt" since "pnt" does not specify + * any value for such parameters. + */ +__isl_give isl_point *isl_point_align_params(__isl_take isl_point *pnt, + __isl_take isl_space *model) +{ + isl_space *space; + isl_bool equal_params; + + space = isl_point_peek_space(pnt); + equal_params = isl_space_has_equal_params(space, model); + if (equal_params < 0) + goto error; + if (!equal_params) { + isl_reordering *r; + + r = isl_parameter_alignment_reordering(space, model); + if (!r) + goto error; + if (r->src_len != r->dst_len) + isl_die(isl_point_get_ctx(pnt), isl_error_invalid, + "no value specified for some parameters", + r = isl_reordering_free(r)); + pnt = isl_point_reorder(pnt, r); + } + + isl_space_free(model); + return pnt; +error: + isl_space_free(model); + isl_point_free(pnt); + return NULL; +} + #undef TYPE #define TYPE isl_point static diff --git a/polly/lib/External/isl/isl_point_private.h b/polly/lib/External/isl/isl_point_private.h index a1e8449..f8f9d83 100644 --- a/polly/lib/External/isl/isl_point_private.h +++ b/polly/lib/External/isl/isl_point_private.h @@ -24,4 +24,8 @@ __isl_give isl_vec *isl_point_take_vec(__isl_keep isl_point *pnt); __isl_give isl_point *isl_point_restore_vec(__isl_take isl_point *pnt, __isl_take isl_vec *vec); +isl_stat isl_point_check_named_params(__isl_keep isl_point *pnt); +__isl_give isl_point *isl_point_align_params(__isl_take isl_point *pnt, + __isl_take isl_space *model); + #endif diff --git a/polly/lib/External/isl/isl_polynomial.c b/polly/lib/External/isl/isl_polynomial.c index 0aac613..7b4eae0 100644 --- a/polly/lib/External/isl/isl_polynomial.c +++ b/polly/lib/External/isl/isl_polynomial.c @@ -3108,13 +3108,18 @@ static __isl_give isl_qpolynomial *isl_qpolynomial_zero_in_space( #define DEFAULT_IS_ZERO 1 #include +#include +#include #include +#include +#include #include #include #include #include #include #include +#include #include #undef BASE @@ -3123,6 +3128,7 @@ static __isl_give isl_qpolynomial *isl_qpolynomial_zero_in_space( #include #include #include +#include int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp) { @@ -4486,20 +4492,17 @@ error: __isl_give isl_qpolynomial *isl_qpolynomial_align_params( __isl_take isl_qpolynomial *qp, __isl_take isl_space *model) { + isl_space *domain_space; isl_bool equal_params; - if (!qp || !model) - goto error; - - equal_params = isl_space_has_equal_params(qp->dim, model); + domain_space = isl_qpolynomial_peek_domain_space(qp); + equal_params = isl_space_has_equal_params(domain_space, model); if (equal_params < 0) goto error; if (!equal_params) { isl_reordering *exp; - exp = isl_parameter_alignment_reordering(qp->dim, model); - exp = isl_reordering_extend_space(exp, - isl_qpolynomial_get_domain_space(qp)); + exp = isl_parameter_alignment_reordering(domain_space, model); qp = isl_qpolynomial_realign_domain(qp, exp); } diff --git a/polly/lib/External/isl/isl_polynomial_private.h b/polly/lib/External/isl/isl_polynomial_private.h index acab078..4e8cb82 100644 --- a/polly/lib/External/isl/isl_polynomial_private.h +++ b/polly/lib/External/isl/isl_polynomial_private.h @@ -186,6 +186,9 @@ __isl_give isl_qpolynomial *isl_qpolynomial_from_affine( __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_cow( __isl_take isl_pw_qpolynomial *pwqp); +__isl_keep isl_qpolynomial *isl_pw_qpolynomial_peek_base_at( + __isl_keep isl_pw_qpolynomial *pwqp, int pos); + __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_piece( __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *set, __isl_take isl_qpolynomial *qp); @@ -211,6 +214,9 @@ __isl_keep isl_qpolynomial_list *isl_qpolynomial_fold_peek_list( __isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_cow( __isl_take isl_pw_qpolynomial_fold *pwf); +__isl_keep isl_qpolynomial_fold *isl_pw_qpolynomial_fold_peek_base_at( + __isl_keep isl_pw_qpolynomial_fold *pwf, int pos); + __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain( __isl_keep isl_set *set, __isl_take isl_qpolynomial_fold *fold1, @@ -255,10 +261,6 @@ __isl_give isl_qpolynomial *isl_qpolynomial_realign_domain( __isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r); __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain( __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r); -__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_realign_domain( - __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_reordering *r); -__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_realign_domain( - __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_reordering *r); __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_space( __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *space); @@ -280,20 +282,11 @@ __isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int( __isl_take isl_qpolynomial *qp, isl_int v); __isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int( __isl_take isl_qpolynomial *qp, isl_int v); -__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul_isl_int( - __isl_take isl_pw_qpolynomial *pwqp, isl_int v); __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale( __isl_take isl_qpolynomial_fold *fold, isl_int v); __isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int( __isl_take isl_qpolynomial_fold *fold, isl_int v); -__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_mul_isl_int( - __isl_take isl_pw_qpolynomial_fold *pwf, isl_int v); -__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul_isl_int( - __isl_take isl_union_pw_qpolynomial *upwqp, isl_int v); -__isl_give isl_union_pw_qpolynomial_fold * -isl_union_pw_qpolynomial_fold_mul_isl_int( - __isl_take isl_union_pw_qpolynomial_fold *upwf, isl_int v); ISL_DECLARE_LIST_FN_PRIVATE(qpolynomial) diff --git a/polly/lib/External/isl/isl_power_templ.c b/polly/lib/External/isl/isl_power_templ.c index 65253bd..26f0fe5 100644 --- a/polly/lib/External/isl/isl_power_templ.c +++ b/polly/lib/External/isl/isl_power_templ.c @@ -3,6 +3,27 @@ #define xFN(TYPE,NAME) TYPE ## _ ## NAME #define FN(TYPE,NAME) xFN(TYPE,NAME) +/* Helper function for isl_*_fixed_power that applies (a copy of) "map2" + * to the range of "map1" and returns the result. + * + * The result is coalesced in an attempt to reduce the number of disjuncts + * that result from repeated applications. + * Similarly, look for implicit equality constraints in an attempt + * to reduce the number of local variables that get introduced + * during the repeated applications. + */ +static __isl_give TYPE *FN(TYPE,fixed_power_apply)(__isl_take TYPE *map1, + __isl_keep TYPE *map2) +{ + TYPE *res; + + res = FN(TYPE,apply_range)(map1, FN(TYPE,copy)(map2)); + res = FN(TYPE,detect_equalities)(res); + res = FN(TYPE,coalesce)(res); + + return res; +} + /* Compute the given non-zero power of "map" and return the result. * If the exponent "exp" is negative, then the -exp th power of the inverse * relation is computed. @@ -34,11 +55,8 @@ __isl_give TYPE *FN(TYPE,fixed_power)(__isl_take TYPE *map, isl_int exp) if (!isl_int_is_zero(r)) { if (!res) res = FN(TYPE,copy)(map); - else { - res = FN(TYPE,apply_range)(res, - FN(TYPE,copy)(map)); - res = FN(TYPE,coalesce)(res); - } + else + res = FN(TYPE,fixed_power_apply)(res, map); if (!res) break; } @@ -47,8 +65,7 @@ __isl_give TYPE *FN(TYPE,fixed_power)(__isl_take TYPE *map, isl_int exp) if (isl_int_is_zero(exp)) break; - map = FN(TYPE,apply_range)(map, FN(TYPE,copy)(map)); - map = FN(TYPE,coalesce)(map); + map = FN(TYPE,fixed_power_apply)(map, map); } isl_int_clear(r); diff --git a/polly/lib/External/isl/isl_project_out_param_templ.c b/polly/lib/External/isl/isl_project_out_param_templ.c new file mode 100644 index 0000000..f277b7c --- /dev/null +++ b/polly/lib/External/isl/isl_project_out_param_templ.c @@ -0,0 +1,59 @@ +/* + * Copyright 2019 Cerebras Systems + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, + * Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA + */ + +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* If "obj" involves a parameter with identifier "id", + * then turn it into an existentially quantified variable. + */ +__isl_give TYPE *FN(TYPE,project_out_param_id)(__isl_take TYPE *obj, + __isl_take isl_id *id) +{ + int pos; + + if (!obj || !id) + goto error; + pos = FN(TYPE,find_dim_by_id)(obj, isl_dim_param, id); + isl_id_free(id); + if (pos < 0) + return obj; + return FN(TYPE,project_out)(obj, isl_dim_param, pos, 1); +error: + FN(TYPE,free)(obj); + isl_id_free(id); + return NULL; +} + +/* If "obj" involves any of the parameters with identifiers in "list", + * then turn them into existentially quantified variables. + */ +__isl_give TYPE *FN(TYPE,project_out_param_id_list)(__isl_take TYPE *obj, + __isl_take isl_id_list *list) +{ + int i; + isl_size n; + + n = isl_id_list_size(list); + if (n < 0) + goto error; + for (i = 0; i < n; ++i) { + isl_id *id; + + id = isl_id_list_get_at(list, i); + obj = FN(TYPE,project_out_param_id)(obj, id); + } + + isl_id_list_free(list); + return obj; +error: + isl_id_list_free(list); + FN(TYPE,free)(obj); + return NULL; +} diff --git a/polly/lib/External/isl/isl_pw_add_disjoint_templ.c b/polly/lib/External/isl/isl_pw_add_disjoint_templ.c new file mode 100644 index 0000000..160b9b5 --- /dev/null +++ b/polly/lib/External/isl/isl_pw_add_disjoint_templ.c @@ -0,0 +1,93 @@ +/* + * Copyright 2010 INRIA Saclay + * Copyright 2011 Sven Verdoolaege + * + * 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 + */ + +#include + +/* Make sure "pw" has room for at least "n" more pieces. + * + * If there is only one reference to pw, we extend it in place. + * Otherwise, we create a new PW and copy the pieces. + */ +static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n) +{ + int i; + isl_ctx *ctx; + PW *res; + + if (!pw) + return NULL; + if (pw->n + n <= pw->size) + return pw; + ctx = FN(PW,get_ctx)(pw); + n += pw->n; + if (pw->ref == 1) { + res = isl_realloc(ctx, pw, struct PW, + sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece))); + if (!res) + return FN(PW,free)(pw); + res->size = n; + return res; + } + res = FN(PW,alloc_size)(isl_space_copy(pw->dim) OPT_TYPE_ARG(pw->), n); + if (!res) + return FN(PW,free)(pw); + for (i = 0; i < pw->n; ++i) + res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set), + FN(EL,copy)(pw->p[i].FIELD)); + FN(PW,free)(pw); + return res; +} + +__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2) +{ + int i; + isl_ctx *ctx; + + if (FN(PW,align_params_bin)(&pw1, &pw2) < 0) + goto error; + + if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n) + return FN(PW,add_disjoint)(pw2, pw1); + + ctx = isl_space_get_ctx(pw1->dim); + if (!OPT_EQUAL_TYPES(pw1->, pw2->)) + isl_die(ctx, isl_error_invalid, + "fold types don't match", goto error); + if (FN(PW,check_equal_space)(pw1, pw2) < 0) + goto error; + + if (FN(PW,IS_ZERO)(pw1)) { + FN(PW,free)(pw1); + return pw2; + } + + if (FN(PW,IS_ZERO)(pw2)) { + FN(PW,free)(pw2); + return pw1; + } + + pw1 = FN(PW,grow)(pw1, pw2->n); + if (!pw1) + goto error; + + for (i = 0; i < pw2->n; ++i) + pw1 = FN(PW,add_piece)(pw1, + isl_set_copy(pw2->p[i].set), + FN(EL,copy)(pw2->p[i].FIELD)); + + FN(PW,free)(pw2); + + return pw1; +error: + FN(PW,free)(pw1); + FN(PW,free)(pw2); + return NULL; +} diff --git a/polly/lib/External/isl/isl_pw_eval.c b/polly/lib/External/isl/isl_pw_eval.c index f59b787..40396b6 100644 --- a/polly/lib/External/isl/isl_pw_eval.c +++ b/polly/lib/External/isl/isl_pw_eval.c @@ -16,6 +16,16 @@ #include +#undef SUFFIX +#define SUFFIX point +#undef ARG1 +#define ARG1 PW +#undef ARG2 +#define ARG2 isl_point + +static +#include "isl_align_params_templ.c" + /* Evaluate "pw" in the void point "pnt". * In particular, return the value NaN. */ @@ -34,6 +44,9 @@ static __isl_give isl_val *FN(PW,eval_void)(__isl_take PW *pw, * If the point is void, then return NaN. * If the point lies outside the domain of "pw", then return 0 or NaN * depending on whether 0 is the default value for this type of function. + * + * Align the parameters if needed, but "pnt" should specify a value + * for all parameters in "pw". */ __isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt) { @@ -45,6 +58,8 @@ __isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt) isl_space *pnt_space, *pw_space; isl_val *v; + FN(PW,align_params_point)(&pw, &pnt); + pnt_space = isl_point_peek_space(pnt); pw_space = FN(PW,peek_space)(pw); ok = isl_space_is_domain_internal(pnt_space, pw_space); diff --git a/polly/lib/External/isl/isl_pw_fix_templ.c b/polly/lib/External/isl/isl_pw_fix_templ.c new file mode 100644 index 0000000..36a50bc --- /dev/null +++ b/polly/lib/External/isl/isl_pw_fix_templ.c @@ -0,0 +1,71 @@ +#include + +/* Fix the value of the given parameter or domain dimension of "pw" + * to be equal to "value". + */ +__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type, + unsigned pos, int value) +{ + int i; + isl_size n; + + n = FN(PW,n_piece)(pw); + if (n < 0) + return FN(PW,free)(pw); + + if (type == isl_dim_out) + isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, + "cannot fix output dimension", return FN(PW,free)(pw)); + + if (type == isl_dim_in) + type = isl_dim_set; + + for (i = n - 1; i >= 0; --i) { + isl_set *domain; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_fix_si(domain, type, pos, value); + pw = FN(PW,restore_domain_at)(pw, i, domain); + pw = FN(PW,exploit_equalities_and_remove_if_empty)(pw, i); + } + + return pw; +} + +/* Fix the value of the variable at position "pos" of type "type" of "pw" + * to be equal to "v". + */ +__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) +{ + int i; + isl_size n; + + if (!v) + return FN(PW,free)(pw); + if (!isl_val_is_int(v)) + isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, + "expecting integer value", goto error); + + n = FN(PW,n_piece)(pw); + if (n < 0) + goto error; + + if (type == isl_dim_in) + type = isl_dim_set; + + for (i = 0; i < n; ++i) { + isl_set *domain; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_fix(domain, type, pos, v->n); + pw = FN(PW,restore_domain_at)(pw, i, domain); + pw = FN(PW,exploit_equalities_and_remove_if_empty)(pw, i); + } + + isl_val_free(v); + return pw; +error: + isl_val_free(v); + return FN(PW,free)(pw); +} diff --git a/polly/lib/External/isl/isl_pw_from_range_templ.c b/polly/lib/External/isl/isl_pw_from_range_templ.c new file mode 100644 index 0000000..c9394bd --- /dev/null +++ b/polly/lib/External/isl/isl_pw_from_range_templ.c @@ -0,0 +1,14 @@ +/* + * 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 + +#undef TYPE +#define TYPE PW +#include "isl_from_range_templ.c" diff --git a/polly/lib/External/isl/isl_pw_insert_dims_templ.c b/polly/lib/External/isl/isl_pw_insert_dims_templ.c index c451dca..df5bfb4 100644 --- a/polly/lib/External/isl/isl_pw_insert_dims_templ.c +++ b/polly/lib/External/isl/isl_pw_insert_dims_templ.c @@ -12,38 +12,35 @@ __isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type, unsigned first, unsigned n) { int i; + isl_size n_piece; enum isl_dim_type set_type; + isl_space *space; - if (!pw) - return NULL; + n_piece = FN(PW,n_piece)(pw); + if (n_piece < 0) + return FN(PW,free)(pw); if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type)) return pw; set_type = type == isl_dim_in ? isl_dim_set : type; - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - - pw->dim = isl_space_insert_dims(pw->dim, type, first, n); - if (!pw->dim) - goto error; - - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_insert_dims(pw->p[i].set, - set_type, first, n); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD, - type, first, n); - if (!pw->p[i].FIELD) - goto error; + space = FN(PW,take_space)(pw); + space = isl_space_insert_dims(space, type, first, n); + pw = FN(PW,restore_space)(pw, space); + + for (i = 0; i < n_piece; ++i) { + isl_set *domain; + EL *el; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_insert_dims(domain, set_type, first, n); + pw = FN(PW,restore_domain_at)(pw, i, domain); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,insert_dims)(el, type, first, n); + pw = FN(PW,restore_base_at)(pw, i, el); } return pw; -error: - FN(PW,free)(pw); - return NULL; } __isl_give PW *FN(PW,add_dims)(__isl_take PW *pw, enum isl_dim_type type, diff --git a/polly/lib/External/isl/isl_pw_morph_templ.c b/polly/lib/External/isl/isl_pw_morph_templ.c index a90fea1..3c08698 100644 --- a/polly/lib/External/isl/isl_pw_morph_templ.c +++ b/polly/lib/External/isl/isl_pw_morph_templ.c @@ -12,31 +12,33 @@ __isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw, __isl_take isl_morph *morph) { int i; + isl_size n; isl_ctx *ctx; + isl_space *space; - if (!pw || !morph) + n = FN(PW,n_piece)(pw); + if (n < 0 || !morph) goto error; ctx = isl_space_get_ctx(pw->dim); isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim), goto error); - pw = FN(PW,cow)(pw); - if (!pw) - goto error; - pw->dim = isl_space_extend_domain_with_range( - isl_space_copy(morph->ran->dim), pw->dim); - if (!pw->dim) - goto error; + space = FN(PW,take_space)(pw); + space = isl_space_extend_domain_with_range( + isl_space_copy(morph->ran->dim), space); + pw = FN(PW,restore_space)(pw, space); + + for (i = 0; i < n; ++i) { + isl_set *domain; + EL *el; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD, - isl_morph_copy(morph)); - if (!pw->p[i].FIELD) - goto error; + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_morph_set(isl_morph_copy(morph), domain); + pw = FN(PW,restore_domain_at)(pw, i, domain); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,morph_domain)(el, isl_morph_copy(morph)); + pw = FN(PW,restore_base_at)(pw, i, el); } isl_morph_free(morph); diff --git a/polly/lib/External/isl/isl_pw_move_dims_templ.c b/polly/lib/External/isl/isl_pw_move_dims_templ.c index 31788d7..a68a947 100644 --- a/polly/lib/External/isl/isl_pw_move_dims_templ.c +++ b/polly/lib/External/isl/isl_pw_move_dims_templ.c @@ -13,20 +13,25 @@ __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw, enum isl_dim_type src_type, unsigned src_pos, unsigned n) { int i; + isl_size n_piece; + isl_space *space; - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; + space = FN(PW,take_space)(pw); + space = isl_space_move_dims(space, dst_type, dst_pos, + src_type, src_pos, n); + pw = FN(PW,restore_space)(pw, space); - pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n); - if (!pw->dim) - goto error; + n_piece = FN(PW,n_piece)(pw); + if (n_piece < 0) + return FN(PW,free)(pw); - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD, + for (i = 0; i < n_piece; ++i) { + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,move_dims)(el, dst_type, dst_pos, src_type, src_pos, n); - if (!pw->p[i].FIELD) - goto error; + pw = FN(PW,restore_base_at)(pw, i, el); } if (dst_type == isl_dim_in) @@ -34,16 +39,14 @@ __isl_give PW *FN(PW,move_dims)(__isl_take PW *pw, if (src_type == isl_dim_in) src_type = isl_dim_set; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_move_dims(pw->p[i].set, - dst_type, dst_pos, + for (i = 0; i < n_piece; ++i) { + isl_set *domain; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_move_dims(domain, dst_type, dst_pos, src_type, src_pos, n); - if (!pw->p[i].set) - goto error; + pw = FN(PW,restore_domain_at)(pw, i, domain); } return pw; -error: - FN(PW,free)(pw); - return NULL; } diff --git a/polly/lib/External/isl/isl_pw_neg_templ.c b/polly/lib/External/isl/isl_pw_neg_templ.c index 65970cf..d3da913 100644 --- a/polly/lib/External/isl/isl_pw_neg_templ.c +++ b/polly/lib/External/isl/isl_pw_neg_templ.c @@ -12,23 +12,5 @@ __isl_give PW *FN(PW,neg)(__isl_take PW *pw) { - int i; - - if (!pw) - return NULL; - - if (FN(PW,IS_ZERO)(pw)) - return pw; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD); - if (!pw->p[i].FIELD) - return FN(PW,free)(pw); - } - - return pw; + return FN(PW,un_op)(pw, &FN(EL,neg)); } diff --git a/polly/lib/External/isl/isl_pw_print_templ.c b/polly/lib/External/isl/isl_pw_print_templ.c new file mode 100644 index 0000000..77f62c6 --- /dev/null +++ b/polly/lib/External/isl/isl_pw_print_templ.c @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#undef EL +#define EL CAT(isl_,BASE) +#undef PW +#define PW CAT(isl_pw_,BASE) + +/* Print the body of a piecewise expression, i.e., a semicolon delimited + * sequence of expressions, each followed by constraints. + */ +static __isl_give isl_printer *FN(print_body_pw,BASE)( + __isl_take isl_printer *p, __isl_keep PW *pw) +{ + int i; + + if (!pw) + return isl_printer_free(p); + + for (i = 0; i < pw->n; ++i) { + EL *el; + isl_space *space; + + if (i) + p = isl_printer_print_str(p, "; "); + el = FN(PW,peek_base_at)(pw, i); + p = FN(print_body,BASE)(p, el); + space = FN(EL,get_domain_space)(el); + p = print_disjuncts(set_to_map(pw->p[i].set), space, p, 0); + isl_space_free(space); + } + return p; +} + +/* Print a piecewise expression in isl format. + */ +static __isl_give isl_printer *FN(FN(print_pw,BASE),isl)( + __isl_take isl_printer *p, __isl_keep PW *pw) +{ + struct isl_print_space_data data = { 0 }; + + if (!pw) + return isl_printer_free(p); + + p = print_param_tuple(p, pw->dim, &data); + p = isl_printer_print_str(p, "{ "); + p = FN(print_body_pw,BASE)(p, pw); + p = isl_printer_print_str(p, " }"); + return p; +} diff --git a/polly/lib/External/isl/isl_pw_pullback_templ.c b/polly/lib/External/isl/isl_pw_pullback_templ.c index 6f1bda9..5486061 100644 --- a/polly/lib/External/isl/isl_pw_pullback_templ.c +++ b/polly/lib/External/isl/isl_pw_pullback_templ.c @@ -36,26 +36,29 @@ __isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw, __isl_take isl_multi_aff *ma) { int i; + isl_size n; isl_space *space = NULL; FN(PW,align_params_multi_aff)(&pw, &ma); ma = isl_multi_aff_align_divs(ma); - pw = FN(PW,cow)(pw); - if (!pw || !ma) + n = FN(PW,n_piece)(pw); + if (n < 0 || !ma) goto error; space = isl_space_join(isl_multi_aff_get_space(ma), FN(PW,get_space)(pw)); - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set, - isl_multi_aff_copy(ma)); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD, + for (i = 0; i < n; ++i) { + isl_set *domain; + EL *el; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_preimage_multi_aff(domain, isl_multi_aff_copy(ma)); - if (!pw->p[i].FIELD) - goto error; + pw = FN(PW,restore_domain_at)(pw, i, domain); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,pullback_multi_aff)(el, isl_multi_aff_copy(ma)); + pw = FN(PW,restore_base_at)(pw, i, el); } pw = FN(PW,reset_space)(pw, space); diff --git a/polly/lib/External/isl/isl_pw_scale_templ.c b/polly/lib/External/isl/isl_pw_scale_templ.c new file mode 100644 index 0000000..81c8495 --- /dev/null +++ b/polly/lib/External/isl/isl_pw_scale_templ.c @@ -0,0 +1,42 @@ +/* + * Copyright 2010 INRIA Saclay + * + * 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 + */ + +#include + +__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v) +{ + int i; + isl_size n; + + if (isl_int_is_one(v)) + return pw; + if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) { + PW *zero; + isl_space *space = FN(PW,get_space)(pw); + zero = FN(PW,ZERO)(space OPT_TYPE_ARG(pw->)); + FN(PW,free)(pw); + return zero; + } + if (isl_int_is_neg(v)) + pw = FN(PW,negate_type)(pw); + + n = FN(PW,n_piece)(pw); + if (n < 0) + return FN(PW,free)(pw); + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,scale)(el, v); + pw = FN(PW,restore_base_at)(pw, i, el); + } + + return pw; +} diff --git a/polly/lib/External/isl/isl_pw_split_dims_templ.c b/polly/lib/External/isl/isl_pw_split_dims_templ.c new file mode 100644 index 0000000..68e9165 --- /dev/null +++ b/polly/lib/External/isl/isl_pw_split_dims_templ.c @@ -0,0 +1,37 @@ +/* + * Copyright 2010 INRIA Saclay + * + * 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 + */ + +#include + +__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) +{ + int i; + isl_size n_piece; + + n_piece = FN(PW,n_piece)(pw); + if (n_piece < 0) + return FN(PW,free)(pw); + if (n == 0) + return pw; + + if (type == isl_dim_in) + type = isl_dim_set; + + for (i = 0; i < n; ++i) { + isl_set *domain; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_split_dims(domain, type, first, n); + pw = FN(PW,restore_domain_at)(pw, i, domain); + } + + return pw; +} diff --git a/polly/lib/External/isl/isl_pw_templ.c b/polly/lib/External/isl/isl_pw_templ.c index 3fa6faf..30ddb92 100644 --- a/polly/lib/External/isl/isl_pw_templ.c +++ b/polly/lib/External/isl/isl_pw_templ.c @@ -57,7 +57,7 @@ __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *space OPT_TYPE_PARAM) * Do this independently of the values of "set" and "el", * such that this function can be used by isl_pw_*_dup. */ -__isl_give PW *FN(PW,add_dup_piece)(__isl_take PW *pw, +static __isl_give PW *FN(PW,add_dup_piece)(__isl_take PW *pw, __isl_take isl_set *set, __isl_take EL *el) { isl_ctx *ctx; @@ -222,6 +222,255 @@ __isl_null PW *FN(PW,free)(__isl_take PW *pw) return NULL; } +/* Return the space of "pw". + */ +__isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw) +{ + return pw ? pw->dim : NULL; +} + +__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw) +{ + return isl_space_copy(FN(PW,peek_space)(pw)); +} + +/* Return the space of "pw". + * This may be either a copy or the space itself + * if there is only one reference to "pw". + * This allows the space to be modified inplace + * if both the piecewise expression and its space have only a single reference. + * The caller is not allowed to modify "pw" between this call and + * a subsequent call to isl_pw_*_restore_*. + * The only exception is that isl_pw_*_free can be called instead. + */ +static __isl_give isl_space *FN(PW,take_space)(__isl_keep PW *pw) +{ + isl_space *space; + + if (!pw) + return NULL; + if (pw->ref != 1) + return FN(PW,get_space)(pw); + space = pw->dim; + pw->dim = NULL; + return space; +} + +/* Set the space of "pw" to "space", where the space of "pw" may be missing + * due to a preceding call to isl_pw_*_take_space. + * However, in this case, "pw" only has a single reference and + * then the call to isl_pw_*_cow has no effect. + */ +static __isl_give PW *FN(PW,restore_space)(__isl_take PW *pw, + __isl_take isl_space *space) +{ + if (!pw || !space) + goto error; + + if (pw->dim == space) { + isl_space_free(space); + return pw; + } + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + isl_space_free(pw->dim); + pw->dim = space; + + return pw; +error: + FN(PW,free)(pw); + isl_space_free(space); + return NULL; +} + +/* Check that "pos" is a valid position for a cell in "pw". + */ +static isl_stat FN(PW,check_pos)(__isl_keep PW *pw, int pos) +{ + if (!pw) + return isl_stat_error; + if (pos < 0 || pos >= pw->n) + isl_die(FN(PW,get_ctx)(pw), isl_error_internal, + "position out of bounds", return isl_stat_error); + return isl_stat_ok; +} + +/* Return the cell at position "pos" in "pw". + */ +static __isl_keep isl_set *FN(PW,peek_domain_at)(__isl_keep PW *pw, int pos) +{ + if (FN(PW,check_pos)(pw, pos) < 0) + return NULL; + return pw->p[pos].set; +} + +/* Return a copy of the cell at position "pos" in "pw". + */ +static __isl_give isl_set *FN(PW,get_domain_at)(__isl_keep PW *pw, int pos) +{ + return isl_set_copy(FN(PW,peek_domain_at)(pw, pos)); +} + +/* Return the cell at position "pos" in "pw". + * This may be either a copy or the cell itself + * if there is only one reference to "pw". + * This allows the cell to be modified inplace + * if both the piecewise expression and this cell + * have only a single reference. + * The caller is not allowed to modify "pw" between this call and + * the subsequent call to isl_pw_*_restore_domain_at. + * The only exception is that isl_pw_*_free can be called instead. + */ +static __isl_give isl_set *FN(PW,take_domain_at)(__isl_keep PW *pw, int pos) +{ + isl_set *domain; + + if (!pw) + return NULL; + if (pw->ref != 1) + return FN(PW,get_domain_at)(pw, pos); + if (FN(PW,check_pos)(pw, pos) < 0) + return NULL; + domain = pw->p[pos].set; + pw->p[pos].set = NULL; + return domain; +} + +/* Set the cell at position "pos" in "pw" to "el", + * where this cell may be missing + * due to a preceding call to isl_pw_*_take_domain_at. + * However, in this case, "pw" only has a single reference and + * then the call to isl_pw_*_cow has no effect. + */ +static __isl_give PW *FN(PW,restore_domain_at)(__isl_take PW *pw, int pos, + __isl_take isl_set *domain) +{ + if (FN(PW,check_pos)(pw, pos) < 0 || !domain) + goto error; + + if (pw->p[pos].set == domain) { + isl_set_free(domain); + return pw; + } + + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + isl_set_free(pw->p[pos].set); + pw->p[pos].set = domain; + + return pw; +error: + FN(PW,free)(pw); + isl_set_free(domain); + return NULL; +} + +/* Return the base expression associated to + * the cell at position "pos" in "pw". + */ +__isl_keep EL *FN(PW,peek_base_at)(__isl_keep PW *pw, int pos) +{ + if (FN(PW,check_pos)(pw, pos) < 0) + return NULL; + return pw->p[pos].FIELD; +} + +/* Return a copy of the base expression associated to + * the cell at position "pos" in "pw". + */ +static __isl_give EL *FN(PW,get_base_at)(__isl_keep PW *pw, int pos) +{ + return FN(EL,copy)(FN(PW,peek_base_at)(pw, pos)); +} + +/* Return the base expression associated to + * the cell at position "pos" in "pw". + * This may be either a copy or the base expression itself + * if there is only one reference to "pw". + * This allows the base expression to be modified inplace + * if both the piecewise expression and this base expression + * have only a single reference. + * The caller is not allowed to modify "pw" between this call and + * a subsequent call to isl_pw_*_restore_*. + * The only exception is that isl_pw_*_free can be called instead. + */ +static __isl_give EL *FN(PW,take_base_at)(__isl_keep PW *pw, int pos) +{ + EL *el; + + if (!pw) + return NULL; + if (pw->ref != 1) + return FN(PW,get_base_at)(pw, pos); + if (FN(PW,check_pos)(pw, pos) < 0) + return NULL; + el = pw->p[pos].FIELD; + pw->p[pos].FIELD = NULL; + return el; +} + +/* Set the base expression associated to + * the cell at position "pos" in "pw" to "el", + * where this base expression may be missing + * due to a preceding call to isl_pw_*_take_base_at. + * However, in this case, "pw" only has a single reference and + * then the call to isl_pw_*_cow has no effect. + * If "inplace" is set, then replacing the base expression by "el" + * is known not to change the meaning of "pw". It can therefore be replaced + * in all references to "pw". + */ +static __isl_give PW *FN(PW,restore_base_at_)(__isl_take PW *pw, int pos, + __isl_take EL *el, int inplace) +{ + if (FN(PW,check_pos)(pw, pos) < 0 || !el) + goto error; + + if (pw->p[pos].FIELD == el) { + FN(EL,free)(el); + return pw; + } + + if (!inplace) + pw = FN(PW,cow)(pw); + if (!pw) + goto error; + FN(EL,free)(pw->p[pos].FIELD); + pw->p[pos].FIELD = el; + + return pw; +error: + FN(PW,free)(pw); + FN(EL,free)(el); + return NULL; +} + +/* Set the base expression associated to + * the cell at position "pos" in "pw" to "el", + * where this base expression may be missing + * due to a preceding call to isl_pw_*_take_base_at. + */ +static __isl_give PW *FN(PW,restore_base_at)(__isl_take PW *pw, int pos, + __isl_take EL *el) +{ + return FN(PW,restore_base_at_)(pw, pos, el, 0); +} + +/* Set the base expression associated to + * the cell at position "pos" in "pw" to "el", + * where this base expression may be missing + * due to a preceding call to isl_pw_*_take_base_at. + * Furthermore, replacing the base expression by "el" + * is known not to change the meaning of "pw". + */ +static __isl_give PW *FN(PW,restore_base_at_inplace)(__isl_take PW *pw, int pos, + __isl_take EL *el) +{ + return FN(PW,restore_base_at_)(pw, pos, el, 1); +} + /* Create a piecewise expression with the given base expression on a universe * domain. */ @@ -327,24 +576,27 @@ isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw) return isl_bool_ok(pw->n == 0); } -__isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw, +static __isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw, __isl_take isl_reordering *exp) { int i; + isl_size n; - pw = FN(PW,cow)(pw); - if (!pw || !exp) + n = FN(PW,n_piece)(pw); + if (n < 0 || !exp) goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_realign(pw->p[i].set, - isl_reordering_copy(exp)); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD, - isl_reordering_copy(exp)); - if (!pw->p[i].FIELD) - goto error; + for (i = 0; i < n; ++i) { + isl_set *domain; + EL *el; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_realign(domain, isl_reordering_copy(exp)); + pw = FN(PW,restore_domain_at)(pw, i, domain); + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,realign_domain)(el, isl_reordering_copy(exp)); + pw = FN(PW,restore_base_at)(pw, i, el); } pw = FN(PW,reset_domain_space)(pw, isl_reordering_get_space(exp)); @@ -382,11 +634,12 @@ __isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *mode if (equal_params < 0) goto error; if (!equal_params) { + isl_space *space; isl_reordering *exp; - exp = isl_parameter_alignment_reordering(pw->dim, model); - exp = isl_reordering_extend_space(exp, - FN(PW,get_domain_space)(pw)); + space = FN(PW,get_domain_space)(pw); + exp = isl_parameter_alignment_reordering(space, model); + isl_space_free(space); pw = FN(PW,realign_domain)(pw, exp); } @@ -495,105 +748,41 @@ error: return NULL; } -/* Make sure "pw" has room for at least "n" more pieces. +#if !DEFAULT_IS_ZERO + +/* Compute the sum of "pw1" and "pw2 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. * - * If there is only one reference to pw, we extend it in place. - * Otherwise, we create a new PW and copy the pieces. + * This function is only defined for object types that do not have + * a default zero value. For other object types, this function + * is simply called "add". */ -static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n) +__isl_give PW *FN(PW,union_add)(__isl_take PW *pw1, __isl_take PW *pw2) { - int i; - isl_ctx *ctx; - PW *res; - - if (!pw) - return NULL; - if (pw->n + n <= pw->size) - return pw; - ctx = FN(PW,get_ctx)(pw); - n += pw->n; - if (pw->ref == 1) { - res = isl_realloc(ctx, pw, struct PW, - sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece))); - if (!res) - return FN(PW,free)(pw); - res->size = n; - return res; - } - res = FN(PW,alloc_size)(isl_space_copy(pw->dim) OPT_TYPE_ARG(pw->), n); - if (!res) - return FN(PW,free)(pw); - for (i = 0; i < pw->n; ++i) - res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set), - FN(EL,copy)(pw->p[i].FIELD)); - FN(PW,free)(pw); - return res; + return FN(PW,union_add_)(pw1, pw2); } -__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2) +#endif + +/* This function is currently only used from isl_aff.c + */ +static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, + __isl_take PW *pw2, __isl_take isl_space *space, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) + __attribute__ ((unused)); + +/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains. + * The result of "fn" (and therefore also of this function) lives in "space". + */ +static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, + __isl_take PW *pw2, __isl_take isl_space *space, + __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) { - int i; - isl_ctx *ctx; + int i, j, n; + PW *res = NULL; - if (FN(PW,align_params_bin)(&pw1, &pw2) < 0) - goto error; - - if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n) - return FN(PW,add_disjoint)(pw2, pw1); - - ctx = isl_space_get_ctx(pw1->dim); - if (!OPT_EQUAL_TYPES(pw1->, pw2->)) - isl_die(ctx, isl_error_invalid, - "fold types don't match", goto error); - if (FN(PW,check_equal_space)(pw1, pw2) < 0) - goto error; - - if (FN(PW,IS_ZERO)(pw1)) { - FN(PW,free)(pw1); - return pw2; - } - - if (FN(PW,IS_ZERO)(pw2)) { - FN(PW,free)(pw2); - return pw1; - } - - pw1 = FN(PW,grow)(pw1, pw2->n); - if (!pw1) - goto error; - - for (i = 0; i < pw2->n; ++i) - pw1 = FN(PW,add_piece)(pw1, - isl_set_copy(pw2->p[i].set), - FN(EL,copy)(pw2->p[i].FIELD)); - - FN(PW,free)(pw2); - - return pw1; -error: - FN(PW,free)(pw1); - FN(PW,free)(pw2); - return NULL; -} - -/* This function is currently only used from isl_aff.c - */ -static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, - __isl_take PW *pw2, __isl_take isl_space *space, - __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) - __attribute__ ((unused)); - -/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains. - * The result of "fn" (and therefore also of this function) lives in "space". - */ -static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1, - __isl_take PW *pw2, __isl_take isl_space *space, - __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2)) -{ - int i, j, n; - PW *res = NULL; - - if (!pw1 || !pw2) + if (!pw1 || !pw2) goto error; n = pw1->n * pw2->n; @@ -692,14 +881,18 @@ __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw) * If the domain of piece "i" is empty, then remove it entirely, * replacing it with the final piece. */ -static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw, - int i) +static __isl_give PW *FN(PW,exploit_equalities_and_remove_if_empty)( + __isl_take PW *pw, int i) { + EL *el; + isl_set *domain; isl_basic_set *aff; - int empty = isl_set_plain_is_empty(pw->p[i].set); + int empty; + domain = FN(PW,peek_domain_at)(pw, i); + empty = isl_set_plain_is_empty(domain); if (empty < 0) - return -1; + return FN(PW,free)(pw); if (empty) { isl_set_free(pw->p[i].set); FN(EL,free)(pw->p[i].FIELD); @@ -707,68 +900,14 @@ static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw, pw->p[i] = pw->p[pw->n - 1]; pw->n--; - return 0; - } - - aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set)); - pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff); - if (!pw->p[i].FIELD) - return -1; - - return 0; -} - -/* Convert a piecewise expression defined over a parameter domain - * into one that is defined over a zero-dimensional set. - */ -__isl_give PW *FN(PW,from_range)(__isl_take PW *pw) -{ - isl_space *space; - - if (!pw) - return NULL; - if (!isl_space_is_set(pw->dim)) - isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, - "not living in a set space", return FN(PW,free)(pw)); - - space = FN(PW,get_space)(pw); - space = isl_space_from_range(space); - pw = FN(PW,reset_space)(pw, space); - - return pw; -} - -/* Fix the value of the given parameter or domain dimension of "pw" - * to be equal to "value". - */ -__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type, - unsigned pos, int value) -{ - int i; - - if (!pw) - return NULL; - - if (type == isl_dim_out) - isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, - "cannot fix output dimension", return FN(PW,free)(pw)); - - if (pw->n == 0) return pw; - - if (type == isl_dim_in) - type = isl_dim_set; - - pw = FN(PW,cow)(pw); - if (!pw) - return FN(PW,free)(pw); - - for (i = pw->n - 1; i >= 0; --i) { - pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value); - if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) - return FN(PW,free)(pw); } + aff = isl_set_affine_hull(FN(PW,get_domain_at)(pw, i)); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,substitute_equalities)(el, aff); + pw = FN(PW,restore_base_at_inplace)(pw, i, el); + return pw; } @@ -777,29 +916,26 @@ __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type, * isl_set_intersect, isl_set_intersect_params, isl_set_intersect_factor_domain, * isl_set_intersect_factor_range or isl_set_subtract. */ -static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw, +static __isl_give PW *FN(PW,restrict_domain)(__isl_take PW *pw, __isl_take isl_set *set, __isl_give isl_set *(*fn)(__isl_take isl_set *set1, __isl_take isl_set *set2)) { int i; + isl_size n; - if (!pw || !set) + FN(PW,align_params_set)(&pw, &set); + n = FN(PW,n_piece)(pw); + if (n < 0 || !set) goto error; - if (pw->n == 0) { - isl_set_free(set); - return pw; - } + for (i = n - 1; i >= 0; --i) { + isl_set *domain; - pw = FN(PW,cow)(pw); - if (!pw) - goto error; - - for (i = pw->n - 1; i >= 0; --i) { - pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set)); - if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) - goto error; + domain = FN(PW,take_domain_at)(pw, i); + domain = fn(domain, isl_set_copy(set)); + pw = FN(PW,restore_domain_at)(pw, i, domain); + pw = FN(PW,exploit_equalities_and_remove_if_empty)(pw, i); } isl_set_free(set); @@ -813,8 +949,7 @@ error: __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, __isl_take isl_set *context) { - FN(PW,align_params_set)(&pw, &context); - return FN(PW,restrict_domain_aligned)(pw, context, &isl_set_intersect); + return FN(PW,restrict_domain)(pw, context, &isl_set_intersect); } /* Intersect the domain of "pw" with the parameter domain "context". @@ -822,9 +957,7 @@ __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw, __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw, __isl_take isl_set *context) { - FN(PW,align_params_set)(&pw, &context); - return FN(PW,restrict_domain_aligned)(pw, context, - &isl_set_intersect_params); + return FN(PW,restrict_domain)(pw, context, &isl_set_intersect_params); } /* Given a piecewise expression "pw" with domain in a space [A -> B] and @@ -833,8 +966,7 @@ __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw, __isl_give PW *FN(PW,intersect_domain_wrapped_domain)(__isl_take PW *pw, __isl_take isl_set *set) { - FN(PW,align_params_set)(&pw, &set); - return FN(PW,restrict_domain_aligned)(pw, set, + return FN(PW,restrict_domain)(pw, set, &isl_set_intersect_factor_domain); } @@ -844,9 +976,7 @@ __isl_give PW *FN(PW,intersect_domain_wrapped_domain)(__isl_take PW *pw, __isl_give PW *FN(PW,intersect_domain_wrapped_range)(__isl_take PW *pw, __isl_take isl_set *set) { - FN(PW,align_params_set)(&pw, &set); - return FN(PW,restrict_domain_aligned)(pw, set, - &isl_set_intersect_factor_range); + return FN(PW,restrict_domain)(pw, set, &isl_set_intersect_factor_range); } /* Subtract "domain' from the domain of "pw". @@ -854,23 +984,86 @@ __isl_give PW *FN(PW,intersect_domain_wrapped_range)(__isl_take PW *pw, __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw, __isl_take isl_set *domain) { - FN(PW,align_params_set)(&pw, &domain); - return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract); + return FN(PW,restrict_domain)(pw, domain, &isl_set_subtract); +} + +/* Return -1 if the piece "p1" should be sorted before "p2" + * and 1 if it should be sorted after "p2". + * Return 0 if they do not need to be sorted in a specific order. + * + * The two pieces are compared on the basis of their function value expressions. + */ +static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg) +{ + struct FN(PW,piece) const *pc1 = p1; + struct FN(PW,piece) const *pc2 = p2; + + return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD); +} + +/* Sort the pieces of "pw" according to their function value + * expressions and then combine pairs of adjacent pieces with + * the same such expression. + * + * The sorting is performed in place because it does not + * change the meaning of "pw", but care needs to be + * taken not to change any possible other copies of "pw" + * in case anything goes wrong. + */ +static __isl_give PW *FN(PW,sort_unique)(__isl_take PW *pw) +{ + int i, j; + isl_set *set; + + if (!pw) + return NULL; + if (pw->n <= 1) + return pw; + if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]), + &FN(PW,sort_field_cmp), NULL) < 0) + return FN(PW,free)(pw); + for (i = pw->n - 1; i >= 1; --i) { + isl_bool equal; + EL *el, *el_prev; + isl_set *set_prev; + + el = FN(PW,peek_base_at)(pw, i); + el_prev = FN(PW,peek_base_at)(pw, i - 1); + equal = FN(EL,plain_is_equal)(el, el_prev); + if (equal < 0) + return FN(PW,free)(pw); + if (!equal) + continue; + set = FN(PW,get_domain_at)(pw, i); + set_prev = FN(PW,get_domain_at)(pw, i - 1); + set = isl_set_union(set_prev, set); + if (!set) + return FN(PW,free)(pw); + isl_set_free(pw->p[i].set); + FN(EL,free)(pw->p[i].FIELD); + isl_set_free(pw->p[i - 1].set); + pw->p[i - 1].set = set; + for (j = i + 1; j < pw->n; ++j) + pw->p[j - 1] = pw->p[j]; + pw->n--; + } + + return pw; } /* 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". - * Call "fn_el" to compute the gist of this element, replace + * Compute the gist of this element, replace * its domain by the universe and drop all other elements * as their domains are necessarily disjoint from "context". */ static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw, - __isl_take isl_set *context, - __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set)) + __isl_take isl_set *context) { int i; isl_space *space; + EL *el; for (i = 0; i < pw->n - 1; ++i) { isl_set_free(pw->p[i].set); @@ -881,36 +1074,39 @@ static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw, pw->n = 1; space = isl_set_get_space(context); - pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context); + el = FN(PW,take_base_at)(pw, 0); + el = FN(EL,gist)(el, context); + pw = FN(PW,restore_base_at)(pw, 0, el); context = isl_set_universe(space); - isl_set_free(pw->p[0].set); - pw->p[0].set = context; - - if (!pw->p[0].FIELD || !pw->p[0].set) - return FN(PW,free)(pw); + pw = FN(PW,restore_domain_at)(pw, 0, context); return pw; } /* Compute the gist of "pw" with respect to the domain constraints - * of "context". Call "fn_el" to compute the gist of the elements - * and "fn_dom" to compute the gist of the domains. + * of "context". + * Call "fn_dom" to compute the gist of the domains and + * "intersect_context" to intersect the domain with the context. * * If the piecewise expression is empty or the context is the universe, * then nothing can be simplified. + * If "pw" has a single domain and it is equal to "context", + * then simply replace the domain by the universe. + * Combine duplicate function value expressions first + * to increase the chance of "pw" having a single domain. */ -static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, +static __isl_give PW *FN(PW,gist_fn)(__isl_take PW *pw, __isl_take isl_set *context, - __isl_give EL *(*fn_el)(__isl_take EL *el, - __isl_take isl_set *set), __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set, - __isl_take isl_basic_set *bset)) + __isl_take isl_basic_set *bset), + __isl_give isl_set *intersect_context(__isl_take isl_set *set, + __isl_take isl_set *context)) { int i; int is_universe; - isl_bool aligned; isl_basic_set *hull = NULL; + pw = FN(PW,sort_unique)(pw); if (!pw || !context) goto error; @@ -927,13 +1123,7 @@ static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, return pw; } - aligned = isl_set_space_has_equal_params(context, pw->dim); - if (aligned < 0) - goto error; - if (!aligned) { - pw = FN(PW,align_params)(pw, isl_set_get_space(context)); - context = isl_set_align_params(context, FN(PW,get_space)(pw)); - } + FN(PW,align_params_set)(&pw, &context); pw = FN(PW,cow)(pw); if (!pw) @@ -946,7 +1136,7 @@ static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, if (equal < 0) goto error; if (equal) - return FN(PW,gist_last)(pw, context, fn_el); + return FN(PW,gist_last)(pw, context); } context = isl_set_compute_divs(context); @@ -954,6 +1144,7 @@ static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, for (i = pw->n - 1; i >= 0; --i) { isl_set *set_i; + EL *el; int empty; if (i == pw->n - 1) { @@ -963,15 +1154,19 @@ static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw, goto error; if (equal) { isl_basic_set_free(hull); - return FN(PW,gist_last)(pw, context, fn_el); + return FN(PW,gist_last)(pw, context); } } - set_i = isl_set_intersect(isl_set_copy(pw->p[i].set), - isl_set_copy(context)); + set_i = FN(PW,get_domain_at)(pw, i); + set_i = intersect_context(set_i, isl_set_copy(context)); empty = isl_set_plain_is_empty(set_i); - pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i); - pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull)); - if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set) + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,gist)(el, set_i); + pw = FN(PW,restore_base_at)(pw, i, el); + set_i = FN(PW,take_domain_at)(pw, i); + set_i = fn_dom(set_i, isl_basic_set_copy(hull)); + pw = FN(PW,restore_domain_at)(pw, i, set_i); + if (empty < 0 || !pw) goto error; if (empty) { isl_set_free(pw->p[i].set); @@ -995,71 +1190,15 @@ error: __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context) { - FN(PW,align_params_set)(&pw, &context); - return FN(PW,gist_aligned)(pw, context, &FN(EL,gist), - &isl_set_gist_basic_set); + return FN(PW,gist_fn)(pw, context, &isl_set_gist_basic_set, + &isl_set_intersect); } __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw, __isl_take isl_set *context) { - FN(PW,align_params_set)(&pw, &context); - return FN(PW,gist_aligned)(pw, context, &FN(EL,gist_params), - &isl_set_gist_params_basic_set); -} - -/* Return -1 if the piece "p1" should be sorted before "p2" - * and 1 if it should be sorted after "p2". - * Return 0 if they do not need to be sorted in a specific order. - * - * The two pieces are compared on the basis of their function value expressions. - */ -static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg) -{ - struct FN(PW,piece) const *pc1 = p1; - struct FN(PW,piece) const *pc2 = p2; - - return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD); -} - -/* Sort the pieces of "pw" according to their function value - * expressions and then combine pairs of adjacent pieces with - * the same such expression. - * - * The sorting is performed in place because it does not - * change the meaning of "pw", but care needs to be - * taken not to change any possible other copies of "pw" - * in case anything goes wrong. - */ -__isl_give PW *FN(PW,sort)(__isl_take PW *pw) -{ - int i, j; - isl_set *set; - - if (!pw) - return NULL; - if (pw->n <= 1) - return pw; - if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]), - &FN(PW,sort_field_cmp), NULL) < 0) - return FN(PW,free)(pw); - for (i = pw->n - 1; i >= 1; --i) { - if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD)) - continue; - set = isl_set_union(isl_set_copy(pw->p[i - 1].set), - isl_set_copy(pw->p[i].set)); - if (!set) - return FN(PW,free)(pw); - isl_set_free(pw->p[i].set); - FN(EL,free)(pw->p[i].FIELD); - isl_set_free(pw->p[i - 1].set); - pw->p[i - 1].set = set; - for (j = i + 1; j < pw->n; ++j) - pw->p[j - 1] = pw->p[j]; - pw->n--; - } - - return pw; + return FN(PW,gist_fn)(pw, context, &isl_set_gist_params_basic_set, + &isl_set_intersect_params); } /* Coalesce the domains of "pw". @@ -1072,448 +1211,187 @@ __isl_give PW *FN(PW,sort)(__isl_take PW *pw) __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw) { int i; - - pw = FN(PW,sort)(pw); - if (!pw) - return NULL; - - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_coalesce(pw->p[i].set); - if (!pw->p[i].set) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - -isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw) -{ - return pw ? isl_space_get_ctx(pw->dim) : NULL; -} - -isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type, - unsigned first, unsigned n) -{ - int i; - enum isl_dim_type set_type; - - if (!pw) - return isl_bool_error; - if (pw->n == 0 || n == 0) - return isl_bool_false; - - set_type = type == isl_dim_in ? isl_dim_set : type; - - for (i = 0; i < pw->n; ++i) { - isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD, - type, first, n); - if (involves < 0 || involves) - return involves; - involves = isl_set_involves_dims(pw->p[i].set, - set_type, first, n); - if (involves < 0 || involves) - return involves; - } - return isl_bool_false; -} - -__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw, - enum isl_dim_type type, unsigned pos, const char *s) -{ - int i; - enum isl_dim_type set_type; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - - set_type = type == isl_dim_in ? isl_dim_set : type; - - pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s); - if (!pw->dim) - goto error; - - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_set_dim_name(pw->p[i].set, - set_type, pos, s); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s); - if (!pw->p[i].FIELD) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - -__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw, - enum isl_dim_type type, unsigned first, unsigned n) -{ - int i; - enum isl_dim_type set_type; - - if (!pw) - return NULL; - if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) - return pw; - - set_type = type == isl_dim_in ? isl_dim_set : type; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - pw->dim = isl_space_drop_dims(pw->dim, type, first, n); - if (!pw->dim) - goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n); - if (!pw->p[i].FIELD) - goto error; - if (type == isl_dim_out) - continue; - pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n); - if (!pw->p[i].set) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - -/* This function is very similar to drop_dims. - * The only difference is that the cells may still involve - * the specified dimensions. They are removed using - * isl_set_project_out instead of isl_set_drop. - */ -__isl_give PW *FN(PW,project_out)(__isl_take PW *pw, - enum isl_dim_type type, unsigned first, unsigned n) -{ - int i; - enum isl_dim_type set_type; - - if (!pw) - return NULL; - if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) - return pw; - - set_type = type == isl_dim_in ? isl_dim_set : type; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - pw->dim = isl_space_drop_dims(pw->dim, type, first, n); - if (!pw->dim) - goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_project_out(pw->p[i].set, - set_type, first, n); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n); - if (!pw->p[i].FIELD) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - -/* Project the domain of pw onto its parameter space. - */ -__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw) -{ - isl_space *space; - isl_size n; - - n = FN(PW,dim)(pw, isl_dim_in); - if (n < 0) - return FN(PW,free)(pw); - pw = FN(PW,project_out)(pw, isl_dim_in, 0, n); - space = FN(PW,get_domain_space)(pw); - space = isl_space_params(space); - pw = FN(PW,reset_domain_space)(pw, space); - return pw; -} - -/* Drop all parameters not referenced by "pw". - */ -__isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw) -{ isl_size n; - int i; - - if (FN(PW,check_named_params)(pw) < 0) - return FN(PW,free)(pw); - n = FN(PW,dim)(pw, isl_dim_param); + pw = FN(PW,sort_unique)(pw); + n = FN(PW,n_piece)(pw); if (n < 0) return FN(PW,free)(pw); - for (i = n - 1; i >= 0; i--) { - isl_bool involves; - - involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1); - if (involves < 0) - return FN(PW,free)(pw); - if (!involves) - pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1); - } - - return pw; -} - -__isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw, - enum isl_dim_type type, unsigned pos, isl_int v) -{ - int i; - - if (!pw) - return NULL; - - if (type == isl_dim_in) - type = isl_dim_set; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v); - if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0) - return FN(PW,free)(pw); - } - - return pw; -} - -/* Fix the value of the variable at position "pos" of type "type" of "pw" - * to be equal to "v". - */ -__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw, - enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) -{ - if (!v) - return FN(PW,free)(pw); - if (!isl_val_is_int(v)) - isl_die(FN(PW,get_ctx)(pw), isl_error_invalid, - "expecting integer value", goto error); - - pw = FN(PW,fix_dim)(pw, type, pos, v->n); - isl_val_free(v); - - return pw; -error: - isl_val_free(v); - return FN(PW,free)(pw); -} - -isl_size FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type) -{ - return isl_space_dim(FN(PW,peek_space)(pw), type); -} - -__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw, - enum isl_dim_type type, unsigned first, unsigned n) -{ - int i; - - if (!pw) - return NULL; - if (n == 0) - return pw; - - if (type == isl_dim_in) - type = isl_dim_set; - - pw = FN(PW,cow)(pw); - if (!pw) - return NULL; - if (!pw->dim) - goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n); - if (!pw->p[i].set) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - -/* Return the space of "pw". - */ -__isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw) -{ - return pw ? pw->dim : NULL; -} - -__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw) -{ - return isl_space_copy(FN(PW,peek_space)(pw)); -} - -/* Return the space of "pw". - * This may be either a copy or the space itself - * if there is only one reference to "pw". - * This allows the space to be modified inplace - * if both the piecewise expression and its space have only a single reference. - * The caller is not allowed to modify "pw" between this call and - * a subsequent call to isl_pw_*_restore_*. - * The only exception is that isl_pw_*_free can be called instead. - */ -__isl_give isl_space *FN(PW,take_space)(__isl_keep PW *pw) -{ - isl_space *space; - - if (!pw) - return NULL; - if (pw->ref != 1) - return FN(PW,get_space)(pw); - space = pw->dim; - pw->dim = NULL; - return space; -} - -/* Set the space of "pw" to "space", where the space of "pw" may be missing - * due to a preceding call to isl_pw_*_take_space. - * However, in this case, "pw" only has a single reference and - * then the call to isl_pw_*_cow has no effect. - */ -__isl_give PW *FN(PW,restore_space)(__isl_take PW *pw, - __isl_take isl_space *space) -{ - if (!pw || !space) - goto error; - - if (pw->dim == space) { - isl_space_free(space); - return pw; - } - pw = FN(PW,cow)(pw); - if (!pw) - goto error; - isl_space_free(pw->dim); - pw->dim = space; + for (i = 0; i < n; ++i) { + pw->p[i].set = isl_set_coalesce(pw->p[i].set); + if (!pw->p[i].set) + goto error; + } return pw; error: FN(PW,free)(pw); - isl_space_free(space); return NULL; } -/* Check that "pos" is a valid position for a cell in "pw". - */ -static isl_stat FN(PW,check_pos)(__isl_keep PW *pw, int pos) +isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw) { - if (!pw) - return isl_stat_error; - if (pos < 0 || pos >= pw->n) - isl_die(FN(PW,get_ctx)(pw), isl_error_internal, - "position out of bounds", return isl_stat_error); - return isl_stat_ok; + return pw ? isl_space_get_ctx(pw->dim) : NULL; } -/* Return the cell at position "pos" in "pw". - */ -static __isl_keep isl_set *FN(PW,peek_domain_at)(__isl_keep PW *pw, int pos) +isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type, + unsigned first, unsigned n) { - if (FN(PW,check_pos)(pw, pos) < 0) - return NULL; - return pw->p[pos].set; + int i; + enum isl_dim_type set_type; + + if (!pw) + return isl_bool_error; + if (pw->n == 0 || n == 0) + return isl_bool_false; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + for (i = 0; i < pw->n; ++i) { + isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD, + type, first, n); + if (involves < 0 || involves) + return involves; + involves = isl_set_involves_dims(pw->p[i].set, + set_type, first, n); + if (involves < 0 || involves) + return involves; + } + return isl_bool_false; } -/* Return a copy of the cell at position "pos" in "pw". - */ -__isl_give isl_set *FN(PW,get_domain_at)(__isl_keep PW *pw, int pos) +__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw, + enum isl_dim_type type, unsigned pos, const char *s) { - return isl_set_copy(FN(PW,peek_domain_at)(pw, pos)); + isl_space *space; + + space = FN(PW,get_space)(pw); + space = isl_space_set_dim_name(space, type, pos, s); + return FN(PW,reset_space)(pw, space); } -/* Return the base expression associated to - * the cell at position "pos" in "pw". - */ -static __isl_keep EL *FN(PW,peek_base_at)(__isl_keep PW *pw, int pos) +__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) { - if (FN(PW,check_pos)(pw, pos) < 0) - return NULL; - return pw->p[pos].FIELD; + int i; + isl_size n_piece; + enum isl_dim_type set_type; + isl_space *space; + + n_piece = FN(PW,n_piece)(pw); + if (n_piece < 0) + return FN(PW,free)(pw); + if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) + return pw; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + space = FN(PW,take_space)(pw); + space = isl_space_drop_dims(space, type, first, n); + pw = FN(PW,restore_space)(pw, space); + for (i = 0; i < n_piece; ++i) { + isl_set *domain; + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,drop_dims)(el, type, first, n); + pw = FN(PW,restore_base_at)(pw, i, el); + if (type == isl_dim_out) + continue; + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_drop(domain, set_type, first, n); + pw = FN(PW,restore_domain_at)(pw, i, domain); + } + + return pw; } -/* Return a copy of the base expression associated to - * the cell at position "pos" in "pw". +/* This function is very similar to drop_dims. + * The only difference is that the cells may still involve + * the specified dimensions. They are removed using + * isl_set_project_out instead of isl_set_drop. */ -__isl_give EL *FN(PW,get_base_at)(__isl_keep PW *pw, int pos) +__isl_give PW *FN(PW,project_out)(__isl_take PW *pw, + enum isl_dim_type type, unsigned first, unsigned n) { - return FN(EL,copy)(FN(PW,peek_base_at)(pw, pos)); + int i; + isl_size n_piece; + enum isl_dim_type set_type; + isl_space *space; + + n_piece = FN(PW,n_piece)(pw); + if (n_piece < 0) + return FN(PW,free)(pw); + if (n == 0 && !isl_space_get_tuple_name(pw->dim, type)) + return pw; + + set_type = type == isl_dim_in ? isl_dim_set : type; + + space = FN(PW,take_space)(pw); + space = isl_space_drop_dims(space, type, first, n); + pw = FN(PW,restore_space)(pw, space); + for (i = 0; i < n_piece; ++i) { + isl_set *domain; + EL *el; + + domain = FN(PW,take_domain_at)(pw, i); + domain = isl_set_project_out(domain, set_type, first, n); + pw = FN(PW,restore_domain_at)(pw, i, domain); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,drop_dims)(el, type, first, n); + pw = FN(PW,restore_base_at)(pw, i, el); + } + + return pw; } -/* Return the base expression associated to - * the cell at position "pos" in "pw". - * This may be either a copy or the base expression itself - * if there is only one reference to "pw". - * This allows the base expression to be modified inplace - * if both the piecewise expression and this base expression - * have only a single reference. - * The caller is not allowed to modify "pw" between this call and - * a subsequent call to isl_pw_*_restore_*. - * The only exception is that isl_pw_*_free can be called instead. +/* Project the domain of pw onto its parameter space. */ -__isl_give EL *FN(PW,take_base_at)(__isl_keep PW *pw, int pos) +__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw) { - EL *el; + isl_space *space; + isl_size n; - if (!pw) - return NULL; - if (pw->ref != 1) - return FN(PW,get_base_at)(pw, pos); - if (FN(PW,check_pos)(pw, pos) < 0) - return NULL; - el = pw->p[pos].FIELD; - pw->p[pos].FIELD = NULL; - return el; + n = FN(PW,dim)(pw, isl_dim_in); + if (n < 0) + return FN(PW,free)(pw); + pw = FN(PW,project_out)(pw, isl_dim_in, 0, n); + space = FN(PW,get_domain_space)(pw); + space = isl_space_params(space); + pw = FN(PW,reset_domain_space)(pw, space); + return pw; } -/* Set the base expression associated to - * the cell at position "pos" in "pw" to "el", - * where this base expression may be missing - * due to a preceding call to isl_pw_*_take_base_at. - * However, in this case, "pw" only has a single reference and - * then the call to isl_pw_*_cow has no effect. +/* Drop all parameters not referenced by "pw". */ -__isl_give PW *FN(PW,restore_base_at)(__isl_take PW *pw, int pos, - __isl_take EL *el) +__isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw) { - if (FN(PW,check_pos)(pw, pos) < 0 || !el) - goto error; + isl_size n; + int i; - if (pw->p[pos].FIELD == el) { - FN(EL,free)(el); - return pw; - } + if (FN(PW,check_named_params)(pw) < 0) + return FN(PW,free)(pw); - pw = FN(PW,cow)(pw); - if (!pw) - goto error; - FN(EL,free)(pw->p[pos].FIELD); - pw->p[pos].FIELD = el; + n = FN(PW,dim)(pw, isl_dim_param); + if (n < 0) + return FN(PW,free)(pw); + for (i = n - 1; i >= 0; i--) { + isl_bool involves; + + involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1); + if (involves < 0) + return FN(PW,free)(pw); + if (!involves) + pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1); + } return pw; -error: - FN(PW,free)(pw); - FN(EL,free)(el); - return NULL; +} + +isl_size FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type) +{ + return isl_space_dim(FN(PW,peek_space)(pw), type); } __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw) @@ -1572,26 +1450,28 @@ static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw, __isl_take isl_space *space, __isl_take isl_space *domain) { int i; + isl_size n; - pw = FN(PW,cow)(pw); - if (!pw || !space || !domain) + n = FN(PW,n_piece)(pw); + if (n < 0 || !space || !domain) goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].set = isl_set_reset_space(pw->p[i].set, - isl_space_copy(domain)); - if (!pw->p[i].set) - goto error; - pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD, + for (i = 0; i < n; ++i) { + isl_set *set; + EL *el; + + set = FN(PW,take_domain_at)(pw, i); + set = isl_set_reset_space(set, isl_space_copy(domain)); + pw = FN(PW,restore_domain_at)(pw, i, set); + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,reset_space_and_domain)(el, isl_space_copy(space), isl_space_copy(domain)); - if (!pw->p[i].FIELD) - goto error; + pw = FN(PW,restore_base_at)(pw, i, el); } isl_space_free(domain); - isl_space_free(pw->dim); - pw->dim = space; + pw = FN(PW,restore_space)(pw, space); return pw; error: @@ -1662,14 +1542,11 @@ __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type) __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw, enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) { - pw = FN(PW,cow)(pw); - if (!pw) - goto error; - pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id); - return FN(PW,reset_space)(pw, isl_space_copy(pw->dim)); -error: - isl_id_free(id); - return FN(PW,free)(pw); + isl_space *space; + + space = FN(PW,get_space)(pw); + space = isl_space_set_dim_id(space, type, pos, id); + return FN(PW,reset_space)(pw, space); } /* Reset the user pointer on all identifiers of parameters and tuples @@ -1844,44 +1721,12 @@ static __isl_give PW *FN(PW,negate_type)(__isl_take PW *pw) } #endif -__isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v) -{ - int i; - - if (isl_int_is_one(v)) - return pw; - if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) { - PW *zero; - isl_space *space = FN(PW,get_space)(pw); - zero = FN(PW,ZERO)(space OPT_TYPE_ARG(pw->)); - FN(PW,free)(pw); - return zero; - } - pw = FN(PW,cow)(pw); - if (isl_int_is_neg(v)) - pw = FN(PW,negate_type)(pw); - if (!pw) - return NULL; - if (pw->n == 0) - return pw; - - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v); - if (!pw->p[i].FIELD) - goto error; - } - - return pw; -error: - FN(PW,free)(pw); - return NULL; -} - /* Multiply the pieces of "pw" by "v" and return the result. */ __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v) { int i; + isl_size n; if (!pw || !v) goto error; @@ -1898,21 +1743,18 @@ __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v) isl_val_free(v); return zero; } - if (pw->n == 0) { - isl_val_free(v); - return pw; - } - pw = FN(PW,cow)(pw); if (isl_val_is_neg(v)) pw = FN(PW,negate_type)(pw); - if (!pw) + n = FN(PW,n_piece)(pw); + if (n < 0) goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD, - isl_val_copy(v)); - if (!pw->p[i].FIELD) - goto error; + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,scale_val)(el, isl_val_copy(v)); + pw = FN(PW,restore_base_at)(pw, i, el); } isl_val_free(v); @@ -1928,6 +1770,7 @@ error: __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v) { int i; + isl_size n; if (!pw || !v) goto error; @@ -1944,21 +1787,18 @@ __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v) isl_die(isl_val_get_ctx(v), isl_error_invalid, "cannot scale down by zero", goto error); - if (pw->n == 0) { - isl_val_free(v); - return pw; - } - pw = FN(PW,cow)(pw); if (isl_val_is_neg(v)) pw = FN(PW,negate_type)(pw); - if (!pw) + n = FN(PW,n_piece)(pw); + if (n < 0) goto error; - for (i = 0; i < pw->n; ++i) { - pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD, - isl_val_copy(v)); - if (!pw->p[i].FIELD) - goto error; + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = FN(EL,scale_down_val)(el, isl_val_copy(v)); + pw = FN(PW,restore_base_at)(pw, i, el); } isl_val_free(v); @@ -1969,11 +1809,6 @@ error: return NULL; } -__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v) -{ - return FN(PW,mul_isl_int)(pw, v); -} - /* Apply some normalization to "pw". * In particular, sort the pieces according to their function value * expressions, combining pairs of adjacent pieces with @@ -1983,12 +1818,12 @@ __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v) * to return NULL, so we need to make sure we don't change the * meaning of any possible other copies of "pw". */ -__isl_give PW *FN(PW,normalize)(__isl_take PW *pw) +static __isl_give PW *FN(PW,normalize)(__isl_take PW *pw) { int i; isl_set *set; - pw = FN(PW,sort)(pw); + pw = FN(PW,sort_unique)(pw); if (!pw) return NULL; for (i = 0; i < pw->n; ++i) { diff --git a/polly/lib/External/isl/isl_pw_un_op_templ.c b/polly/lib/External/isl/isl_pw_un_op_templ.c new file mode 100644 index 0000000..1146090 --- /dev/null +++ b/polly/lib/External/isl/isl_pw_un_op_templ.c @@ -0,0 +1,36 @@ +/* + * Copyright 2010 INRIA Saclay + * + * 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 + */ + +#include + +/* Apply "fn" to each of the base expressions of "pw". + * The function is assumed to have no effect on the default value + * (i.e., zero for those objects with a default value). + */ +static __isl_give PW *FN(PW,un_op)(__isl_take PW *pw, + __isl_give EL *(*fn)(__isl_take EL *el)) +{ + isl_size n; + int i; + + n = FN(PW,n_piece)(pw); + if (n < 0) + return FN(PW,free)(pw); + + for (i = 0; i < n; ++i) { + EL *el; + + el = FN(PW,take_base_at)(pw, i); + el = fn(el); + pw = FN(PW,restore_base_at)(pw, i, el); + } + + return pw; +} diff --git a/polly/lib/External/isl/isl_pw_union_opt.c b/polly/lib/External/isl/isl_pw_union_opt.c index d0fc38c..99b0045 100644 --- a/polly/lib/External/isl/isl_pw_union_opt.c +++ b/polly/lib/External/isl/isl_pw_union_opt.c @@ -321,7 +321,7 @@ static __isl_give PW *FN(PW,union_opt_cmp)( } for (i = 0; i < 2; ++i) { - data[i].pw = FN(PW,sort)(data[i].pw); + data[i].pw = FN(PW,sort_unique)(data[i].pw); data[i].cell = FN(PW,extract_domains)(data[i].pw); } diff --git a/polly/lib/External/isl/isl_read_from_str_templ.c b/polly/lib/External/isl/isl_read_from_str_templ.c new file mode 100644 index 0000000..51fa8ed --- /dev/null +++ b/polly/lib/External/isl/isl_read_from_str_templ.c @@ -0,0 +1,27 @@ +/* + * Copyright 2008 Katholieke Universiteit Leuven + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + */ + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,TYPE_BASE) + +/* Read an object of type TYPE from "str" (using an isl_stream). + */ +__isl_give TYPE *FN(isl,FN(TYPE_BASE,read_from_str))(isl_ctx *ctx, + const char *str) +{ + TYPE *obj; + isl_stream *s = isl_stream_new_str(ctx, str); + if (!s) + return NULL; + obj = FN(isl_stream_read,TYPE_BASE)(s); + isl_stream_free(s); + return obj; +} diff --git a/polly/lib/External/isl/isl_reordering.c b/polly/lib/External/isl/isl_reordering.c index 33a8976..bfbdd9e 100644 --- a/polly/lib/External/isl/isl_reordering.c +++ b/polly/lib/External/isl/isl_reordering.c @@ -13,22 +13,49 @@ #include #include -__isl_give isl_reordering *isl_reordering_alloc(isl_ctx *ctx, int len) +/* Create a new reordering description based on + * the number of source dimensions "src_len" and + * (an initial value for) the number of target dimensions "dst_len". + * + * The caller still needs to fill in the space field and + * possibly adjust the target dimensionality if this is not known yet + * when this function is called. + */ +__isl_give isl_reordering *isl_reordering_alloc(isl_ctx *ctx, int src_len, + int dst_len) { isl_reordering *exp; exp = isl_alloc(ctx, struct isl_reordering, - sizeof(struct isl_reordering) + (len - 1) * sizeof(int)); + sizeof(struct isl_reordering) + (src_len - 1) * sizeof(int)); if (!exp) return NULL; exp->ref = 1; - exp->len = len; + exp->src_len = src_len; + exp->dst_len = dst_len; exp->space = NULL; return exp; } +/* Set r->dst_len to the total dimensionality of r->space. + */ +static __isl_give isl_reordering *isl_reordering_set_dst_len_from_space( + __isl_take isl_reordering *r) +{ + isl_size n; + + if (!r) + return NULL; + + n = isl_space_dim(r->space, isl_dim_all); + if (n < 0) + return isl_reordering_free(r); + r->dst_len = n; + return r; +} + __isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp) { if (!exp) @@ -46,14 +73,15 @@ __isl_give isl_reordering *isl_reordering_dup(__isl_keep isl_reordering *r) if (!r) return NULL; - dup = isl_reordering_alloc(isl_reordering_get_ctx(r), r->len); + dup = isl_reordering_alloc(isl_reordering_get_ctx(r), + r->src_len, r->dst_len); if (!dup) return NULL; dup->space = isl_reordering_get_space(r); if (!dup->space) return isl_reordering_free(dup); - for (i = 0; i < dup->len; ++i) + for (i = 0; i < dup->src_len; ++i) dup->pos[i] = r->pos[i]; return dup; @@ -110,36 +138,44 @@ __isl_give isl_space *isl_reordering_get_space(__isl_keep isl_reordering *r) * to the corresponding parameters in a new dimension specification * that has the parameters of "aligner" first, followed by * any remaining parameters of "alignee" that do not occur in "aligner". + * The other dimensions of "alignee" are mapped to subsequent positions + * in order. */ __isl_give isl_reordering *isl_parameter_alignment_reordering( __isl_keep isl_space *alignee, __isl_keep isl_space *aligner) { - int i, j; + int i, j, offset; + isl_ctx *ctx; isl_reordering *exp; + isl_size dim, n_alignee, n_aligner; - if (!alignee || !aligner) + dim = isl_space_dim(alignee, isl_dim_all); + n_alignee = isl_space_dim(alignee, isl_dim_param); + n_aligner = isl_space_dim(aligner, isl_dim_param); + if (dim < 0 || n_alignee < 0 || n_aligner < 0) return NULL; - exp = isl_reordering_alloc(alignee->ctx, alignee->nparam); + ctx = isl_space_get_ctx(alignee); + exp = isl_reordering_alloc(ctx, dim, dim); if (!exp) return NULL; - exp->space = isl_space_params(isl_space_copy(aligner)); + exp->space = isl_space_replace_params(isl_space_copy(alignee), aligner); - for (i = 0; i < alignee->nparam; ++i) { + for (i = 0; i < n_alignee; ++i) { isl_id *id_i; id_i = isl_space_get_dim_id(alignee, isl_dim_param, i); if (!id_i) - isl_die(alignee->ctx, isl_error_invalid, + isl_die(ctx, isl_error_invalid, "cannot align unnamed parameters", goto error); - for (j = 0; j < aligner->nparam; ++j) { + for (j = 0; j < n_aligner; ++j) { isl_id *id_j; id_j = isl_space_get_dim_id(aligner, isl_dim_param, j); isl_id_free(id_j); if (id_i == id_j) break; } - if (j < aligner->nparam) { + if (j < n_aligner) { exp->pos[i] = j; isl_id_free(id_i); } else { @@ -155,8 +191,14 @@ __isl_give isl_reordering *isl_parameter_alignment_reordering( } } - if (!exp->space) - return isl_reordering_free(exp); + exp = isl_reordering_set_dst_len_from_space(exp); + if (!exp) + return NULL; + + offset = exp->dst_len - exp->src_len; + for (i = n_alignee; i < dim; ++i) + exp->pos[i] = offset + i; + return exp; error: isl_reordering_free(exp); @@ -179,14 +221,16 @@ __isl_give isl_reordering *isl_reordering_unbind_params_insert_domain( { int i, n; int offset, first; + isl_size dim; isl_ctx *ctx; isl_reordering *r; - if (!space || !tuple) + dim = isl_space_dim(space, isl_dim_all); + if (dim < 0 || !tuple) return NULL; ctx = isl_space_get_ctx(space); - r = isl_reordering_alloc(ctx, isl_space_dim(space, isl_dim_all)); + r = isl_reordering_alloc(ctx, dim, dim); if (!r) return NULL; @@ -224,13 +268,13 @@ __isl_give isl_reordering *isl_reordering_unbind_params_insert_domain( r->pos[pos] = offset + i; } - offset = isl_space_dim(r->space, isl_dim_all) - r->len; + offset = isl_space_dim(r->space, isl_dim_all) - dim; first = isl_space_dim(space, isl_dim_param); - n = r->len - first; + n = dim - first; for (i = 0; i < n; ++i) r->pos[first + i] = first + offset + i; - return r; + return isl_reordering_set_dst_len_from_space(r); } __isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp, @@ -238,10 +282,8 @@ __isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp, { int i; isl_ctx *ctx; - isl_space *space; isl_reordering *res; int offset; - isl_size dim; if (!exp) return NULL; @@ -249,18 +291,15 @@ __isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp, return exp; ctx = isl_reordering_get_ctx(exp); - space = isl_reordering_peek_space(exp); - dim = isl_space_dim(space, isl_dim_all); - if (dim < 0) - return isl_reordering_free(exp); - offset = dim - exp->len; - res = isl_reordering_alloc(ctx, exp->len + extra); + offset = exp->dst_len - exp->src_len; + res = isl_reordering_alloc(ctx, exp->src_len + extra, + exp->dst_len + extra); if (!res) goto error; res->space = isl_reordering_get_space(exp); - for (i = 0; i < exp->len; ++i) + for (i = 0; i < exp->src_len; ++i) res->pos[i] = exp->pos[i]; - for (i = exp->len; i < res->len; ++i) + for (i = exp->src_len; i < res->src_len; ++i) res->pos[i] = offset + i; isl_reordering_free(exp); @@ -282,7 +321,8 @@ __isl_give isl_reordering *isl_reordering_extend_space( if (!exp || dim < 0) goto error; - res = isl_reordering_extend(isl_reordering_copy(exp), dim - exp->len); + res = isl_reordering_extend(isl_reordering_copy(exp), + dim - exp->src_len); res = isl_reordering_cow(res); if (!res) goto error; @@ -307,7 +347,7 @@ void isl_reordering_dump(__isl_keep isl_reordering *exp) int i; isl_space_dump(exp->space); - for (i = 0; i < exp->len; ++i) + for (i = 0; i < exp->src_len; ++i) fprintf(stderr, "%d -> %d; ", i, exp->pos[i]); fprintf(stderr, "\n"); } diff --git a/polly/lib/External/isl/isl_reordering.h b/polly/lib/External/isl/isl_reordering.h index 6664749..be56cf8 100644 --- a/polly/lib/External/isl/isl_reordering.h +++ b/polly/lib/External/isl/isl_reordering.h @@ -3,18 +3,19 @@ #include -/* pos maps original dimensions to new dimensions. +/* "pos" has "src_len" entries and maps original dimensions to new dimensions. * The final space is given by "space". * The number of dimensions (i.e., the range of values) in the result * may be larger than the number of dimensions in the input. - * In particular, the possible values of the entries in pos ranges from 0 to - * the total dimension of dim - 1, unless isl_reordering_extend - * has been called. + * In particular, the possible values of the entries in "pos" ranges from 0 to + * to "dst_len" - 1, where "dst_len" is equal to the total dimension of "space", + * unless isl_reordering_extend has been called. */ struct isl_reordering { int ref; isl_space *space; - unsigned len; + unsigned src_len; + unsigned dst_len; int pos[1]; }; typedef struct isl_reordering isl_reordering; diff --git a/polly/lib/External/isl/isl_sample.c b/polly/lib/External/isl/isl_sample.c index e0e2c9b..2e26190 100644 --- a/polly/lib/External/isl/isl_sample.c +++ b/polly/lib/External/isl/isl_sample.c @@ -24,6 +24,9 @@ #include #include +static __isl_give isl_vec *isl_basic_set_sample_bounded( + __isl_take isl_basic_set *bset); + static __isl_give isl_vec *empty_sample(__isl_take isl_basic_set *bset) { struct isl_vec *vec; @@ -1150,12 +1153,10 @@ error: static __isl_give isl_vec *basic_set_sample(__isl_take isl_basic_set *bset, int bounded) { - struct isl_ctx *ctx; isl_size dim; if (!bset) return NULL; - ctx = bset->ctx; if (isl_basic_set_plain_is_empty(bset)) return empty_sample(bset); diff --git a/polly/lib/External/isl/isl_sample.h b/polly/lib/External/isl/isl_sample.h index 13f0e5b..6ffdad8 100644 --- a/polly/lib/External/isl/isl_sample.h +++ b/polly/lib/External/isl/isl_sample.h @@ -18,8 +18,6 @@ extern "C" { #endif __isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset); -__isl_give isl_vec *isl_basic_set_sample_bounded( - __isl_take isl_basic_set *bset); __isl_give isl_vec *isl_basic_set_sample_with_cone( __isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone); diff --git a/polly/lib/External/isl/isl_schedule_constraints.c b/polly/lib/External/isl/isl_schedule_constraints.c index 38a3c6f..c35ac66 100644 --- a/polly/lib/External/isl/isl_schedule_constraints.c +++ b/polly/lib/External/isl/isl_schedule_constraints.c @@ -561,6 +561,12 @@ __isl_give isl_printer *isl_printer_print_schedule_constraints( #define KEY_ERROR isl_sc_key_error #undef KEY_END #define KEY_END isl_sc_key_end +#undef KEY_STR +#define KEY_STR key_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_key +#undef KEY_GET +#define KEY_GET get_key #include "extract_key.c" #undef BASE @@ -588,16 +594,17 @@ __isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints( { isl_ctx *ctx; isl_schedule_constraints *sc; - int more; + isl_bool more; int domain_set = 0; - if (isl_stream_yaml_read_start_mapping(s)) + if (isl_stream_yaml_read_start_mapping(s) < 0) return NULL; ctx = isl_stream_get_ctx(s); sc = isl_schedule_constraints_alloc(ctx); - while ((more = isl_stream_yaml_next(s)) > 0) { + while ((more = isl_stream_yaml_next(s)) == isl_bool_true) { enum isl_sc_key key; + enum isl_edge_type type; isl_set *context; isl_union_set *domain; isl_union_map *constraints; @@ -627,8 +634,10 @@ __isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints( case isl_sc_key_condition: case isl_sc_key_conditional_validity: case isl_sc_key_proximity: + type = (enum isl_edge_type) key; constraints = read_union_map(s); - sc = isl_schedule_constraints_set(sc, key, constraints); + sc = isl_schedule_constraints_set(sc, type, + constraints); if (!sc) return NULL; break; @@ -637,10 +646,8 @@ __isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints( if (more < 0) return isl_schedule_constraints_free(sc); - if (isl_stream_yaml_read_end_mapping(s) < 0) { - isl_stream_error(s, NULL, "unexpected extra elements"); + if (isl_stream_yaml_read_end_mapping(s) < 0) return isl_schedule_constraints_free(sc); - } if (!domain_set) { isl_stream_error(s, NULL, "no domain specified"); @@ -667,22 +674,9 @@ __isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file( return sc; } -/* Read an isl_schedule_constraints object from the string "str". - */ -__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str( - isl_ctx *ctx, const char *str) -{ - struct isl_stream *s; - isl_schedule_constraints *sc; - - s = isl_stream_new_str(ctx, str); - if (!s) - return NULL; - sc = isl_stream_read_schedule_constraints(s); - isl_stream_free(s); - - return sc; -} +#undef TYPE_BASE +#define TYPE_BASE schedule_constraints +#include "isl_read_from_str_templ.c" /* Align the parameters of the fields of "sc". */ diff --git a/polly/lib/External/isl/isl_schedule_node.c b/polly/lib/External/isl/isl_schedule_node.c index 5e37276..9d140e56e 100644 --- a/polly/lib/External/isl/isl_schedule_node.c +++ b/polly/lib/External/isl/isl_schedule_node.c @@ -184,7 +184,7 @@ __isl_give isl_schedule *isl_schedule_node_get_schedule( /* Return a fresh copy of "node". */ -__isl_take isl_schedule_node *isl_schedule_node_dup( +__isl_give isl_schedule_node *isl_schedule_node_dup( __isl_keep isl_schedule_node *node) { if (!node) @@ -1141,6 +1141,14 @@ __isl_give isl_schedule_node *isl_schedule_node_parent( return isl_schedule_node_ancestor(node, 1); } +/* Move the "node" pointer to the parent of its parent. + */ +__isl_give isl_schedule_node *isl_schedule_node_grandparent( + __isl_take isl_schedule_node *node) +{ + return isl_schedule_node_ancestor(node, 2); +} + /* Move the "node" pointer to the root of its schedule tree. */ __isl_give isl_schedule_node *isl_schedule_node_root( @@ -1201,6 +1209,17 @@ __isl_give isl_schedule_node *isl_schedule_node_child( return node; } +/* Move the "node" pointer to the child at position "pos2" of the child + * at position "pos1". + */ +__isl_give isl_schedule_node *isl_schedule_node_grandchild( + __isl_take isl_schedule_node *node, int pos1, int pos2) +{ + node = isl_schedule_node_child(node, pos1); + node = isl_schedule_node_child(node, pos2); + return node; +} + /* Move the "node" pointer to the first child of the node * it currently points to. */ @@ -2273,6 +2292,20 @@ __isl_give isl_id *isl_schedule_node_mark_get_id( return isl_schedule_tree_mark_get_id(node->tree); } +/* Check that "node" is a sequence node. + */ +static isl_stat check_is_sequence(__isl_keep isl_schedule_node *node) +{ + if (!node) + return isl_stat_error; + + if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) + isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, + "not a sequence node", return isl_stat_error); + + return isl_stat_ok; +} + /* Replace the child at position "pos" of the sequence node "node" * by the children of sequence root node of "tree". */ @@ -2282,11 +2315,8 @@ __isl_give isl_schedule_node *isl_schedule_node_sequence_splice( { isl_schedule_tree *node_tree; - if (!node || !tree) + if (check_is_sequence(node) < 0 || !tree) goto error; - if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) - isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, - "not a sequence node", goto error); if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence) isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, "not a sequence node", goto error); @@ -2317,18 +2347,11 @@ __isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child( isl_schedule_node *child; isl_schedule_tree *tree; - if (!node) - return NULL; - if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) - isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, - "not a sequence node", - return isl_schedule_node_free(node)); - node = isl_schedule_node_child(node, pos); - node = isl_schedule_node_child(node, 0); - if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) - isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid, - "not a sequence node", - return isl_schedule_node_free(node)); + if (check_is_sequence(node) < 0) + return isl_schedule_node_free(node); + node = isl_schedule_node_grandchild(node, pos, 0); + if (check_is_sequence(node) < 0) + return isl_schedule_node_free(node); n = isl_schedule_node_n_children(node); if (n < 0) return isl_schedule_node_free(node); @@ -2350,6 +2373,46 @@ __isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child( return node; } +/* Given a sequence node "node", for each child that is also + * (the parent of) a sequence node, attach the children of that node directly + * as children of "node" at the position of the child, + * replacing this original child. + * + * Since splicing in a child may change the positions of later children, + * iterate through the children from last to first. + */ +__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_children( + __isl_take isl_schedule_node *node) +{ + int i; + isl_size n; + + if (check_is_sequence(node) < 0) + return isl_schedule_node_free(node); + n = isl_schedule_node_n_children(node); + if (n < 0) + return isl_schedule_node_free(node); + + for (i = n - 1; i >= 0; --i) { + enum isl_schedule_node_type type; + int is_seq; + + node = isl_schedule_node_grandchild(node, i, 0); + type = isl_schedule_node_get_type(node); + if (type < 0) + return isl_schedule_node_free(node); + is_seq = type == isl_schedule_node_sequence; + node = isl_schedule_node_grandparent(node); + + if (!is_seq) + continue; + + node = isl_schedule_node_sequence_splice_child(node, i); + } + + return node; +} + /* 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 @@ -4151,17 +4214,15 @@ static isl_bool has_ancestors(__isl_keep isl_schedule_node *node, * of both the original extension and the domain elements that reach * that original extension? */ -static int is_disjoint_extension(__isl_keep isl_schedule_node *node, +static isl_bool is_disjoint_extension(__isl_keep isl_schedule_node *node, __isl_keep isl_union_map *extension) { isl_union_map *old; isl_union_set *domain; - int empty; + isl_bool empty; node = isl_schedule_node_copy(node); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); + node = isl_schedule_node_ancestor(node, 3); old = isl_schedule_node_extension_get_extension(node); domain = isl_schedule_node_get_universe_domain(node); isl_schedule_node_free(node); @@ -4195,14 +4256,12 @@ static __isl_give isl_schedule_node *extend_extension( pos = isl_schedule_node_get_child_position(node); if (pos < 0) node = isl_schedule_node_free(node); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); + node = isl_schedule_node_grandparent(node); node_extension = isl_schedule_node_extension_get_extension(node); disjoint = isl_union_map_is_disjoint(extension, node_extension); extension = isl_union_map_union(extension, node_extension); node = isl_schedule_node_extension_set_extension(node, extension); - node = isl_schedule_node_child(node, 0); - node = isl_schedule_node_child(node, pos); + node = isl_schedule_node_grandchild(node, 0, pos); if (disjoint < 0) return isl_schedule_node_free(node); @@ -4279,7 +4338,7 @@ static __isl_give isl_schedule_node *insert_extension( if (in_ext < 0) goto error; if (in_ext) { - int disjoint; + isl_bool disjoint; disjoint = is_disjoint_extension(node, extension); if (disjoint < 0) @@ -4327,8 +4386,7 @@ static __isl_give isl_schedule_node *graft_or_splice( pos = 0; node = isl_schedule_node_graft_tree(node, tree); } - node = isl_schedule_node_child(node, pos + tree_pos); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, pos + tree_pos, 0); return node; } diff --git a/polly/lib/External/isl/isl_schedule_read.c b/polly/lib/External/isl/isl_schedule_read.c index 71fdeed..b98b72b 100644 --- a/polly/lib/External/isl/isl_schedule_read.c +++ b/polly/lib/External/isl/isl_schedule_read.c @@ -56,6 +56,12 @@ static char *key_str[] = { #define KEY_ERROR isl_schedule_key_error #undef KEY_END #define KEY_END isl_schedule_key_end +#undef KEY_STR +#define KEY_STR key_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_key +#undef KEY_GET +#define KEY_GET get_key #include "extract_key.c" static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( @@ -71,7 +77,7 @@ static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -122,7 +128,7 @@ static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -171,7 +177,7 @@ static __isl_give isl_schedule_tree *read_expansion(isl_stream *s) isl_union_pw_multi_aff *contraction = NULL; isl_union_map *expansion = NULL; isl_schedule_tree *tree = NULL; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -216,7 +222,7 @@ static __isl_give isl_schedule_tree *read_expansion(isl_stream *s) isl_die(ctx, isl_error_invalid, "unexpected key", goto error); } - } while ((more = isl_stream_yaml_next(s)) > 0); + } while ((more = isl_stream_yaml_next(s)) == isl_bool_true); if (more < 0) goto error; @@ -248,7 +254,7 @@ static __isl_give isl_schedule_tree *read_extension(isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -299,7 +305,7 @@ static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -350,7 +356,7 @@ static __isl_give isl_schedule_tree *read_guard(isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -401,7 +407,7 @@ static __isl_give isl_schedule_tree *read_mark(isl_stream *s) struct isl_token *tok; enum isl_schedule_key key; char *str; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -443,32 +449,17 @@ error: return NULL; } +#undef EL_BASE +#define EL_BASE val + +#include + /* 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; + return isl_stream_yaml_read_val_list(s); } /* Set the (initial) coincident properties of "band" according to @@ -510,7 +501,7 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) isl_ctx *ctx; isl_schedule_band *band; int permutable = 0; - int more; + isl_bool more; ctx = isl_stream_get_ctx(s); @@ -570,7 +561,7 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s) isl_die(ctx, isl_error_invalid, "unexpected key", goto error); } - } while ((more = isl_stream_yaml_next(s)) > 0); + } while ((more = isl_stream_yaml_next(s)) == isl_bool_true); if (more < 0) goto error; @@ -598,36 +589,25 @@ error: return NULL; } +#undef EL_BASE +#define EL_BASE schedule_tree + +#include + /* 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); + list = isl_stream_yaml_read_schedule_tree_list(s); return isl_schedule_tree_from_children(type, list); } @@ -658,9 +638,9 @@ static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( enum isl_schedule_key key; struct isl_token *tok; isl_schedule_tree *tree = NULL; - int more; + isl_bool more; - if (isl_stream_yaml_read_start_mapping(s)) + if (isl_stream_yaml_read_start_mapping(s) < 0) return NULL; more = isl_stream_yaml_next(s); if (more < 0) @@ -722,10 +702,8 @@ static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( return NULL; } - if (isl_stream_yaml_read_end_mapping(s) < 0) { - isl_stream_error(s, NULL, "unexpected extra elements"); + if (isl_stream_yaml_read_end_mapping(s) < 0) return isl_schedule_tree_free(tree); - } return tree; } @@ -761,19 +739,6 @@ __isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input) 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; -} +#undef TYPE_BASE +#define TYPE_BASE schedule +#include "isl_read_from_str_templ.c" diff --git a/polly/lib/External/isl/isl_schedule_tree.c b/polly/lib/External/isl/isl_schedule_tree.c index 2a20a33..8dfe1d7 100644 --- a/polly/lib/External/isl/isl_schedule_tree.c +++ b/polly/lib/External/isl/isl_schedule_tree.c @@ -67,7 +67,7 @@ static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx, /* Return a fresh copy of "tree". */ -__isl_take isl_schedule_tree *isl_schedule_tree_dup( +__isl_give isl_schedule_tree *isl_schedule_tree_dup( __isl_keep isl_schedule_tree *tree) { isl_ctx *ctx; diff --git a/polly/lib/External/isl/isl_scheduler.c b/polly/lib/External/isl/isl_scheduler.c index 5ab65d2..ddd4a16 100644 --- a/polly/lib/External/isl/isl_scheduler.c +++ b/polly/lib/External/isl/isl_scheduler.c @@ -40,6 +40,9 @@ #include #include +#include "isl_scheduler.h" +#include "isl_scheduler_clustering.h" + /* * The scheduling algorithm implemented in this file was inspired by * Bondhugula et al., "Automatic Transformations for Communication-Minimized @@ -50,82 +53,6 @@ */ -/* Internal information about a node that is used during the construction - * of a schedule. - * space represents the original space in which the domain lives; - * that is, the space is not affected by compression - * sched is a matrix representation of the schedule being constructed - * for this node; if compressed is set, then this schedule is - * defined over the compressed domain space - * sched_map is an isl_map representation of the same (partial) schedule - * sched_map may be NULL; if compressed is set, then this map - * is defined over the uncompressed domain space - * rank is the number of linearly independent rows in the linear part - * of sched - * the rows of "vmap" represent a change of basis for the node - * variables; the first rank rows span the linear part of - * the schedule rows; the remaining rows are linearly independent - * the rows of "indep" represent linear combinations of the schedule - * coefficients that are non-zero when the schedule coefficients are - * linearly independent of previously computed schedule rows. - * start is the first variable in the LP problem in the sequences that - * represents the schedule coefficients of this node - * nvar is the dimension of the (compressed) domain - * nparam is the number of parameters or 0 if we are not constructing - * a parametric schedule - * - * If compressed is set, then hull represents the constraints - * that were used to derive the compression, while compress and - * decompress map the original space to the compressed space and - * vice versa. - * - * scc is the index of SCC (or WCC) this node belongs to - * - * "cluster" is only used inside extract_clusters and identifies - * the cluster of SCCs that the node belongs to. - * - * 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 - * dependence distances are zero. - * - * If the schedule_treat_coalescing option is set, then - * "sizes" contains the sizes of the (compressed) instance set - * in each direction. If there is no fixed size in a given direction, - * then the corresponding size value is set to infinity. - * If the schedule_treat_coalescing option or the schedule_max_coefficient - * option is set, then "max" contains the maximal values for - * schedule coefficients of the (compressed) variables. If no bound - * needs to be imposed on a particular variable, then the corresponding - * value is negative. - * If not NULL, then "bounds" contains a non-parametric set - * in the compressed space that is bounded by the size in each direction. - */ -struct isl_sched_node { - isl_space *space; - int compressed; - isl_set *hull; - isl_multi_aff *compress; - isl_pw_multi_aff *decompress; - isl_mat *sched; - isl_map *sched_map; - int rank; - isl_mat *indep; - isl_mat *vmap; - int start; - int nvar; - int nparam; - - int scc; - int cluster; - - int *coincident; - - isl_multi_val *sizes; - isl_basic_set *bounds; - isl_vec *max; -}; - static isl_bool node_has_tuples(const void *entry, const void *val) { struct isl_sched_node *node = (struct isl_sched_node *)entry; @@ -134,7 +61,7 @@ static isl_bool node_has_tuples(const void *entry, const void *val) return isl_space_has_equal_tuples(node->space, space); } -static int node_scc_exactly(struct isl_sched_node *node, int scc) +int isl_sched_node_scc_exactly(struct isl_sched_node *node, int scc) { return node->scc == scc; } @@ -149,65 +76,10 @@ 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 - * - * map is the dependence relation, with i -> j in the map if j depends on i - * tagged_condition and tagged_validity contain the union of all tagged - * condition or conditional validity dependence relations that - * specialize the dependence relation "map"; that is, - * if (i -> a) -> (j -> b) is an element of "tagged_condition" - * or "tagged_validity", then i -> j is an element of "map". - * If these fields are NULL, then they represent the empty relation. - * src is the source node - * dst is the sink node - * - * types is a bit vector containing the types of this edge. - * validity is set if the edge is used to ensure correctness - * coincidence is used to enforce zero dependence distances - * proximity is set if the edge is used to minimize dependence distances - * condition is set if the edge represents a condition - * for a conditional validity schedule constraint - * local can only be set for condition edges and indicates that - * the dependence distance over the edge should be zero - * conditional_validity is set if the edge is used to conditionally - * ensure correctness - * - * For validity edges, start and end mark the sequence of inequality - * constraints in the LP problem that encode the validity constraint - * corresponding to this edge. - * - * During clustering, an edge may be marked "no_merge" if it should - * not be used to merge clusters. - * The weight is also only used during clustering and it is - * an indication of how many schedule dimensions on either side - * of the schedule constraints can be aligned. - * If the weight is negative, then this means that this edge was postponed - * by has_bounded_distances or any_no_merge. The original weight can - * be retrieved by adding 1 + graph->max_weight, with "graph" - * the graph containing this edge. - */ -struct isl_sched_edge { - isl_map *map; - isl_union_map *tagged_condition; - isl_union_map *tagged_validity; - - struct isl_sched_node *src; - struct isl_sched_node *dst; - - unsigned types; - - int start; - int end; - - int no_merge; - int weight; -}; - /* Is "edge" marked as being of type "type"? */ -static int is_type(struct isl_sched_edge *edge, enum isl_edge_type type) +int isl_sched_edge_has_type(struct isl_sched_edge *edge, + enum isl_edge_type type) { return ISL_FL_ISSET(edge->types, 1 << type); } @@ -230,7 +102,7 @@ static void clear_type(struct isl_sched_edge *edge, enum isl_edge_type type) */ static int is_validity(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_validity); + return isl_sched_edge_has_type(edge, isl_edge_validity); } /* Mark "edge" as a validity edge. @@ -242,16 +114,16 @@ static void set_validity(struct isl_sched_edge *edge) /* Is "edge" marked as a proximity edge? */ -static int is_proximity(struct isl_sched_edge *edge) +int isl_sched_edge_is_proximity(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_proximity); + return isl_sched_edge_has_type(edge, isl_edge_proximity); } /* Is "edge" marked as a local edge? */ static int is_local(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_local); + return isl_sched_edge_has_type(edge, isl_edge_local); } /* Mark "edge" as a local edge. @@ -272,21 +144,21 @@ static void clear_local(struct isl_sched_edge *edge) */ static int is_coincidence(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_coincidence); + return isl_sched_edge_has_type(edge, isl_edge_coincidence); } /* Is "edge" marked as a condition edge? */ -static int is_condition(struct isl_sched_edge *edge) +int isl_sched_edge_is_condition(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_condition); + return isl_sched_edge_has_type(edge, isl_edge_condition); } /* Is "edge" marked as a conditional validity edge? */ -static int is_conditional_validity(struct isl_sched_edge *edge) +int isl_sched_edge_is_conditional_validity(struct isl_sched_edge *edge) { - return is_type(edge, isl_edge_conditional_validity); + return isl_sched_edge_has_type(edge, isl_edge_conditional_validity); } /* Is "edge" of a type that can appear multiple times between @@ -298,103 +170,10 @@ static int is_conditional_validity(struct isl_sched_edge *edge) */ static int is_multi_edge_type(struct isl_sched_edge *edge) { - return is_condition(edge) || is_conditional_validity(edge); + return isl_sched_edge_is_condition(edge) || + isl_sched_edge_is_conditional_validity(edge); } -/* Internal information about the dependence graph used during - * the construction of the schedule. - * - * intra_hmap is a cache, mapping dependence relations to their dual, - * for dependences from a node to itself, possibly without - * coefficients for the parameters - * intra_hmap_param is a cache, mapping dependence relations to their dual, - * for dependences from a node to itself, including coefficients - * for the parameters - * inter_hmap is a cache, mapping dependence relations to their dual, - * for dependences between distinct nodes - * if compression is involved then the key for these maps - * is the original, uncompressed dependence relation, while - * the value is the dual of the compressed dependence relation. - * - * n is the number of nodes - * node is the list of nodes - * maxvar is the maximal number of variables over all nodes - * max_row is the allocated number of rows in the schedule - * 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 - * band_start is the starting row in the node schedules of the current band - * root is set to the original dependence graph from which this graph - * is derived through splitting. If this graph is not the result of - * splitting, then the root field points to the graph itself. - * - * sorted contains a list of node indices sorted according to the - * SCC to which a node belongs - * - * n_edge is the number of edges - * edge is the list of edges - * max_edge contains the maximal number of edges of each type; - * in particular, it contains the number of edges in the inital graph. - * edge_table contains pointers into the edge array, hashed on the source - * and sink spaces; there is one such table for each type; - * a given edge may be referenced from more than one table - * if the corresponding relation appears in more than one of the - * sets of dependences; however, for each type there is only - * a single edge between a given pair of source and sink space - * in the entire graph - * - * node_table contains pointers into the node array, hashed on the space tuples - * - * region contains a list of variable sequences that should be non-trivial - * - * lp contains the (I)LP problem used to obtain new schedule rows - * - * src_scc and dst_scc are the source and sink SCCs of an edge with - * conflicting constraints - * - * scc represents the number of components - * weak is set if the components are weakly connected - * - * max_weight is used during clustering and represents the maximal - * weight of the relevant proximity edges. - */ -struct isl_sched_graph { - isl_map_to_basic_set *intra_hmap; - isl_map_to_basic_set *intra_hmap_param; - isl_map_to_basic_set *inter_hmap; - - struct isl_sched_node *node; - int n; - int maxvar; - int max_row; - int n_row; - - int *sorted; - - int n_total_row; - int band_start; - - struct isl_sched_graph *root; - - struct isl_sched_edge *edge; - int n_edge; - int max_edge[isl_edge_last + 1]; - struct isl_hash_table *edge_table[isl_edge_last + 1]; - - struct isl_hash_table *node_table; - struct isl_trivial_region *region; - - isl_basic_set *lp; - - int src_scc; - int dst_scc; - - int scc; - int weak; - - int max_weight; -}; - /* Initialize node_table based on the list of nodes. */ static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph) @@ -424,7 +203,7 @@ static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph) /* Return a pointer to the node that lives within the given space, * an invalid node if there is no such node, or NULL in case of error. */ -static struct isl_sched_node *graph_find_node(isl_ctx *ctx, +struct isl_sched_node *isl_sched_graph_find_node(isl_ctx *ctx, struct isl_sched_graph *graph, __isl_keep isl_space *space) { struct isl_hash_table_entry *entry; @@ -446,7 +225,7 @@ static struct isl_sched_node *graph_find_node(isl_ctx *ctx, /* Is "node" a node in "graph"? */ -static int is_node(struct isl_sched_graph *graph, +int isl_sched_graph_is_node(struct isl_sched_graph *graph, struct isl_sched_node *node) { return node && node >= &graph->node[0] && node < &graph->node[graph->n]; @@ -490,7 +269,7 @@ static isl_stat graph_edge_tables_add(isl_ctx *ctx, enum isl_edge_type t; for (t = isl_edge_first; t <= isl_edge_last; ++t) { - if (!is_type(edge, t)) + if (!isl_sched_edge_has_type(edge, t)) continue; if (graph_edge_table_add(ctx, graph, t, edge) < 0) return isl_stat_error; @@ -663,7 +442,7 @@ static isl_bool graph_has_any_edge(struct isl_sched_graph *graph, * of strongly connected components and we cannot ignore * conditional validity edges during this detection. */ -static isl_bool graph_has_validity_edge(struct isl_sched_graph *graph, +isl_bool isl_sched_graph_has_validity_edge(struct isl_sched_graph *graph, struct isl_sched_node *src, struct isl_sched_node *dst) { isl_bool r; @@ -730,7 +509,7 @@ static void clear_node(struct isl_sched_graph *graph, isl_vec_free(node->max); } -static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph) +void isl_sched_graph_free(isl_ctx *ctx, struct isl_sched_graph *graph) { int i; @@ -1310,7 +1089,7 @@ static int merge_edge(struct isl_sched_edge *edge1, edge1->types |= edge2->types; isl_map_free(edge2->map); - if (is_condition(edge2)) { + if (isl_sched_edge_is_condition(edge2)) { if (!edge1->tagged_condition) edge1->tagged_condition = edge2->tagged_condition; else @@ -1319,7 +1098,7 @@ static int merge_edge(struct isl_sched_edge *edge1, edge2->tagged_condition); } - if (is_conditional_validity(edge2)) { + if (isl_sched_edge_is_conditional_validity(edge2)) { if (!edge1->tagged_validity) edge1->tagged_validity = edge2->tagged_validity; else @@ -1328,9 +1107,10 @@ static int merge_edge(struct isl_sched_edge *edge1, edge2->tagged_validity); } - if (is_condition(edge2) && !edge1->tagged_condition) + if (isl_sched_edge_is_condition(edge2) && !edge1->tagged_condition) return -1; - if (is_conditional_validity(edge2) && !edge1->tagged_validity) + if (isl_sched_edge_is_conditional_validity(edge2) && + !edge1->tagged_validity) return -1; return 0; @@ -1419,7 +1199,7 @@ static struct isl_sched_node *find_domain_node(isl_ctx *ctx, isl_space *space; space = isl_space_domain(isl_map_get_space(map)); - node = graph_find_node(ctx, graph, space); + node = isl_sched_graph_find_node(ctx, graph, space); isl_space_free(space); return node; @@ -1435,7 +1215,7 @@ static struct isl_sched_node *find_range_node(isl_ctx *ctx, isl_space *space; space = isl_space_range(isl_map_get_space(map)); - node = graph_find_node(ctx, graph, space); + node = isl_sched_graph_find_node(ctx, graph, space); isl_space_free(space); return node; @@ -1501,7 +1281,8 @@ static isl_stat extract_edge(__isl_take isl_map *map, void *user) if (!src || !dst) goto error; - if (!is_node(graph, src) || !is_node(graph, dst)) + if (!isl_sched_graph_is_node(graph, src) || + !isl_sched_graph_is_node(graph, dst)) return skip_edge(map, tagged); if (src->compressed || dst->compressed) { @@ -1558,7 +1339,7 @@ error: * any possible additional equalities. * Note that this intersection is only performed locally here. */ -static isl_stat graph_init(struct isl_sched_graph *graph, +isl_stat isl_sched_graph_init(struct isl_sched_graph *graph, __isl_keep isl_schedule_constraints *sc) { isl_ctx *ctx; @@ -1647,13 +1428,15 @@ static isl_bool node_follows_strong(int i, int j, void *user) { struct isl_sched_graph *graph = user; - return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); + return isl_sched_graph_has_validity_edge(graph, &graph->node[j], + &graph->node[i]); } /* Use Tarjan's algorithm for computing the strongly connected components * in the dependence graph only considering those edges defined by "follows". */ -static isl_stat detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, +isl_stat isl_sched_graph_detect_ccs(isl_ctx *ctx, + struct isl_sched_graph *graph, isl_bool (*follows)(int i, int j, void *user)) { int i, n; @@ -1688,7 +1471,7 @@ static isl_stat detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, static isl_stat detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph) { graph->weak = 0; - return detect_ccs(ctx, graph, &node_follows_strong); + return isl_sched_graph_detect_ccs(ctx, graph, &node_follows_strong); } /* Apply Tarjan's algorithm to detect the (weakly) connected components @@ -1698,7 +1481,7 @@ static isl_stat detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph) static isl_stat detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph) { graph->weak = 1; - return detect_ccs(ctx, graph, &node_follows_weak); + return isl_sched_graph_detect_ccs(ctx, graph, &node_follows_weak); } static int cmp_scc(const void *a, const void *b, void *data) @@ -2409,7 +2192,7 @@ static int add_all_proximity_constraints(struct isl_sched_graph *graph, int zero; zero = force_zero(edge, use_coincidence); - if (!is_proximity(edge) && !zero) + if (!isl_sched_edge_is_proximity(edge) && !zero) continue; if (edge->src == edge->dst && add_intra_proximity_constraints(graph, edge, 1, zero) < 0) @@ -2482,7 +2265,7 @@ static __isl_give isl_mat *extract_linear_schedule(struct isl_sched_node *node) * The rows are normalized to involve as few of the last * coefficients as possible and to have a positive initial value. */ -static int node_update_vmap(struct isl_sched_node *node) +isl_stat isl_sched_node_update_vmap(struct isl_sched_node *node) { isl_mat *H, *U, *Q; @@ -2499,15 +2282,16 @@ static int node_update_vmap(struct isl_sched_node *node) isl_mat_free(H); if (!node->indep || !node->vmap || node->rank < 0) - return -1; - return 0; + return isl_stat_error; + return isl_stat_ok; } /* Is "edge" marked as a validity or a conditional validity edge? */ static int is_any_validity(struct isl_sched_edge *edge) { - return is_validity(edge) || is_conditional_validity(edge); + return is_validity(edge) || + isl_sched_edge_is_conditional_validity(edge); } /* How many times should we count the constraints in "edge"? @@ -2526,7 +2310,8 @@ static int is_any_validity(struct isl_sched_edge *edge) */ static int edge_multiplicity(struct isl_sched_edge *edge, int use_coincidence) { - if (is_proximity(edge) || force_zero(edge, use_coincidence)) + if (isl_sched_edge_is_proximity(edge) || + force_zero(edge, use_coincidence)) return 2; if (is_validity(edge)) return 1; @@ -2547,7 +2332,7 @@ static int parametric_intra_edge_multiplicity(struct isl_sched_edge *edge, { if (edge->src != edge->dst) return 0; - if (!is_proximity(edge)) + if (!isl_sched_edge_is_proximity(edge)) return 0; if (force_zero(edge, use_coincidence)) return 0; @@ -2979,7 +2764,7 @@ static isl_stat setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph, total = param_pos + 2 * nparam; for (i = 0; i < graph->n; ++i) { struct isl_sched_node *node = &graph->node[graph->sorted[i]]; - if (node_update_vmap(node) < 0) + if (isl_sched_node_update_vmap(node) < 0) return isl_stat_error; node->start = total; total += 1 + node->nparam + 2 * node->nvar; @@ -3270,7 +3055,7 @@ error: * * The result is defined over the uncompressed node domain. */ -static __isl_give isl_multi_aff *node_extract_partial_schedule_multi_aff( +__isl_give isl_multi_aff *isl_sched_node_extract_partial_schedule_multi_aff( struct isl_sched_node *node, int first, int n) { int i; @@ -3320,7 +3105,7 @@ static __isl_give isl_multi_aff *node_extract_schedule_multi_aff( nrow = isl_mat_rows(node->sched); if (nrow < 0) return NULL; - return node_extract_partial_schedule_multi_aff(node, 0, nrow); + return isl_sched_node_extract_partial_schedule_multi_aff(node, 0, nrow); } /* Convert node->sched into a map and return this map. @@ -3512,7 +3297,7 @@ static int unconditionalize_adjacent_validity(struct isl_sched_graph *graph, int adjacent; isl_union_map *validity; - if (!is_conditional_validity(&graph->edge[i])) + if (!isl_sched_edge_is_conditional_validity(&graph->edge[i])) continue; if (is_validity(&graph->edge[i])) continue; @@ -3564,7 +3349,7 @@ static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph) isl_union_set *uset; isl_union_map *umap; - if (!is_condition(&graph->edge[i])) + if (!isl_sched_edge_is_condition(&graph->edge[i])) continue; if (is_local(&graph->edge[i])) continue; @@ -3639,10 +3424,20 @@ static __isl_give isl_union_set *isl_sched_graph_domain(isl_ctx *ctx, return dom; } +/* Return a union of universe domains corresponding to the nodes + * in the SCC with index "scc". + */ +__isl_give isl_union_set *isl_sched_graph_extract_scc(isl_ctx *ctx, + struct isl_sched_graph *graph, int scc) +{ + return isl_sched_graph_domain(ctx, graph, + &isl_sched_node_scc_exactly, scc); +} + /* 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, +__isl_give isl_union_set_list *isl_sched_graph_extract_sccs(isl_ctx *ctx, struct isl_sched_graph *graph) { int i; @@ -3652,7 +3447,7 @@ static __isl_give isl_union_set_list *extract_sccs(isl_ctx *ctx, for (i = 0; i < graph->scc; ++i) { isl_union_set *dom; - dom = isl_sched_graph_domain(ctx, graph, &node_scc_exactly, i); + dom = isl_sched_graph_extract_scc(ctx, graph, i); filters = isl_union_set_list_add(filters, dom); } @@ -3750,12 +3545,14 @@ static isl_stat copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst, if (isl_map_plain_is_empty(edge->map)) continue; - dst_src = graph_find_node(ctx, dst, edge->src->space); - dst_dst = graph_find_node(ctx, dst, edge->dst->space); + dst_src = isl_sched_graph_find_node(ctx, dst, edge->src->space); + dst_dst = isl_sched_graph_find_node(ctx, dst, edge->dst->space); if (!dst_src || !dst_dst) return isl_stat_error; - if (!is_node(dst, dst_src) || !is_node(dst, dst_dst)) { - if (is_validity(edge) || is_conditional_validity(edge)) + if (!isl_sched_graph_is_node(dst, dst_src) || + !isl_sched_graph_is_node(dst, dst_dst)) { + if (is_validity(edge) || + isl_sched_edge_is_conditional_validity(edge)) isl_die(ctx, isl_error_internal, "backward (conditional) validity edge", return isl_stat_error); @@ -3794,7 +3591,7 @@ static isl_stat copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst, * with only lower-dimensional domains, we make sure we will * compute the required amount of extra linearly independent rows. */ -static int compute_maxvar(struct isl_sched_graph *graph) +isl_stat isl_sched_graph_compute_maxvar(struct isl_sched_graph *graph) { int i; @@ -3803,21 +3600,22 @@ static int compute_maxvar(struct isl_sched_graph *graph) struct isl_sched_node *node = &graph->node[i]; int nvar; - if (node_update_vmap(node) < 0) - return -1; + if (isl_sched_node_update_vmap(node) < 0) + return isl_stat_error; nvar = node->nvar + graph->n_row - node->rank; if (nvar > graph->maxvar) graph->maxvar = nvar; } - return 0; + return isl_stat_ok; } /* Extract the subgraph of "graph" that consists of the nodes satisfying * "node_pred" and the edges satisfying "edge_pred" and store * the result in "sub". */ -static isl_stat extract_sub_graph(isl_ctx *ctx, struct isl_sched_graph *graph, +isl_stat isl_sched_graph_extract_sub_graph(isl_ctx *ctx, + struct isl_sched_graph *graph, int (*node_pred)(struct isl_sched_node *node, int data), int (*edge_pred)(struct isl_sched_edge *edge, int data), int data, struct isl_sched_graph *sub) @@ -3877,8 +3675,8 @@ static __isl_give isl_schedule_node *compute_sub_schedule( { struct isl_sched_graph split = { 0 }; - if (extract_sub_graph(ctx, graph, node_pred, edge_pred, data, - &split) < 0) + if (isl_sched_graph_extract_sub_graph(ctx, graph, node_pred, edge_pred, + data, &split) < 0) goto error; if (wcc) @@ -3886,14 +3684,14 @@ static __isl_give isl_schedule_node *compute_sub_schedule( else node = compute_schedule(node, &split); - graph_free(ctx, &split); + isl_sched_graph_free(ctx, &split); return node; error: - graph_free(ctx, &split); + isl_sched_graph_free(ctx, &split); return isl_schedule_node_free(node); } -static int edge_scc_exactly(struct isl_sched_edge *edge, int scc) +int isl_sched_edge_scc_exactly(struct isl_sched_edge *edge, int scc) { return edge->src->scc == scc && edge->dst->scc == scc; } @@ -3951,7 +3749,6 @@ static isl_stat reset_band(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 is_seq; isl_ctx *ctx; isl_union_set_list *filters; @@ -3966,27 +3763,19 @@ static __isl_give isl_schedule_node *compute_split_schedule( 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, 1); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, 1, 0); node = compute_sub_schedule(node, ctx, graph, &node_scc_at_least, &edge_src_scc_at_least, graph->src_scc + 1, 0); - is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence; - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); - if (is_seq) - node = isl_schedule_node_sequence_splice_child(node, 1); - node = isl_schedule_node_child(node, 0); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandparent(node); + node = isl_schedule_node_grandchild(node, 0, 0); node = compute_sub_schedule(node, ctx, graph, &node_scc_at_most, &edge_dst_scc_at_most, graph->src_scc, 0); - is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence; - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); - if (is_seq) - node = isl_schedule_node_sequence_splice_child(node, 0); + node = isl_schedule_node_grandparent(node); + + node = isl_schedule_node_sequence_splice_children(node); return node; } @@ -4020,15 +3809,16 @@ static __isl_give isl_schedule_node *insert_current_band( end = graph->n_total_row; n = end - start; - ma = node_extract_partial_schedule_multi_aff(&graph->node[0], start, n); + ma = isl_sched_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); + ma = isl_sched_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); @@ -4216,10 +4006,10 @@ static struct isl_sched_node *graph_find_compressed_node(isl_ctx *ctx, if (!space) return NULL; - node = graph_find_node(ctx, graph, space); + node = isl_sched_graph_find_node(ctx, graph, space); if (!node) return NULL; - if (is_node(graph, node)) + if (isl_sched_graph_is_node(graph, node)) return node; id = isl_space_get_tuple_id(space, isl_dim_set); @@ -4229,12 +4019,12 @@ static struct isl_sched_node *graph_find_compressed_node(isl_ctx *ctx, if (!node) return NULL; - if (!is_node(graph->root, node)) + if (!isl_sched_graph_is_node(graph->root, node)) isl_die(ctx, isl_error_internal, "space points to invalid node", return NULL); if (graph != graph->root) - node = graph_find_node(ctx, graph, node->space); - if (!is_node(graph, node)) + node = isl_sched_graph_find_node(ctx, graph, node->space); + if (!isl_sched_graph_is_node(graph, node)) isl_die(ctx, isl_error_internal, "unable to find node", return NULL); @@ -5462,9 +5252,10 @@ static __isl_give isl_schedule_node *carry_coincidence( /* Topologically sort statements mapped to the same schedule iteration * and add insert a sequence node in front of "node" * corresponding to this order. - * If "initialized" is set, then it may be assumed that compute_maxvar + * If "initialized" is set, then it may be assumed that + * isl_sched_graph_compute_maxvar * has been called on the current band. Otherwise, call - * compute_maxvar if and before carry_dependences gets called. + * isl_sched_graph_compute_maxvar if and before carry_dependences gets called. * * If it turns out to be impossible to sort the statements apart, * because different dependences impose different orderings @@ -5501,12 +5292,12 @@ static __isl_give isl_schedule_node *sort_statements( next_band(graph); if (graph->scc < graph->n) { - if (!initialized && compute_maxvar(graph) < 0) + if (!initialized && isl_sched_graph_compute_maxvar(graph) < 0) return isl_schedule_node_free(node); return carry_dependences(node, graph); } - filters = extract_sccs(ctx, graph); + filters = isl_sched_graph_extract_sccs(ctx, graph); node = isl_schedule_node_insert_sequence(node, filters); return node; @@ -5569,7 +5360,7 @@ static void clear_local_edges(struct isl_sched_graph *graph) int i; for (i = 0; i < graph->n_edge; ++i) - if (is_condition(&graph->edge[i])) + if (isl_sched_edge_is_condition(&graph->edge[i])) clear_local(&graph->edge[i]); } @@ -5582,9 +5373,9 @@ static int need_condition_check(struct isl_sched_graph *graph) int any_conditional_validity = 0; for (i = 0; i < graph->n_edge; ++i) { - if (is_condition(&graph->edge[i])) + if (isl_sched_edge_is_condition(&graph->edge[i])) any_condition = 1; - if (is_conditional_validity(&graph->edge[i])) + if (isl_sched_edge_is_conditional_validity(&graph->edge[i])) any_conditional_validity = 1; } @@ -5615,7 +5406,8 @@ static __isl_give isl_map *final_row(struct isl_sched_node *node) n_row = isl_mat_rows(node->sched); if (n_row < 0) return NULL; - ma = node_extract_partial_schedule_multi_aff(node, n_row - 1, 1); + ma = isl_sched_node_extract_partial_schedule_multi_aff(node, + n_row - 1, 1); return isl_map_from_multi_aff(ma); } @@ -5666,7 +5458,7 @@ static int has_adjacent_true_conditions(struct isl_sched_graph *graph, int adjacent, local; isl_union_map *condition; - if (!is_condition(&graph->edge[i])) + if (!isl_sched_edge_is_condition(&graph->edge[i])) continue; if (is_local(&graph->edge[i])) continue; @@ -5721,7 +5513,7 @@ static int has_violated_conditional_constraint(isl_ctx *ctx, isl_union_map *umap; int violated; - if (!is_conditional_validity(&graph->edge[i])) + if (!isl_sched_edge_is_conditional_validity(&graph->edge[i])) continue; violated = is_violated(graph, i); @@ -5758,9 +5550,10 @@ error: /* Examine the current band (the rows between graph->band_start and * graph->n_total_row), deciding whether to drop it or add it to "node" * and then continue with the computation of the next band, if any. - * If "initialized" is set, then it may be assumed that compute_maxvar + * If "initialized" is set, then it may be assumed that + * isl_sched_graph_compute_maxvar * has been called on the current band. Otherwise, call - * compute_maxvar if and before carry_dependences gets called. + * isl_sched_graph_compute_maxvar if and before carry_dependences gets called. * * The caller keeps looking for a new row as long as * graph->n_row < graph->maxvar. If the latest attempt to find @@ -5787,7 +5580,7 @@ error: * will necessarily be empty, but the graph may still be split up * into weakly connected components before arriving back here. */ -static __isl_give isl_schedule_node *compute_schedule_finish_band( +__isl_give isl_schedule_node *isl_schedule_node_compute_finish_band( __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, int initialized) { @@ -5809,7 +5602,7 @@ static __isl_give isl_schedule_node *compute_schedule_finish_band( return compute_next_band(node, graph, 1); if (graph->scc > 1) return compute_component_schedule(node, graph, 1); - if (!initialized && compute_maxvar(graph) < 0) + if (!initialized && isl_sched_graph_compute_maxvar(graph) < 0) return isl_schedule_node_free(node); if (isl_options_get_schedule_outer_coincidence(ctx)) return carry_coincidence(node, graph); @@ -5823,7 +5616,7 @@ static __isl_give isl_schedule_node *compute_schedule_finish_band( /* Construct a band of schedule rows for a connected dependence graph. * The caller is responsible for determining the strongly connected - * components and calling compute_maxvar first. + * components and calling isl_sched_graph_compute_maxvar first. * * 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 @@ -5853,7 +5646,7 @@ static __isl_give isl_schedule_node *compute_schedule_finish_band( * Since there are only a finite number of dependences, * there will only be a finite number of iterations. */ -static isl_stat compute_schedule_wcc_band(isl_ctx *ctx, +isl_stat isl_schedule_node_compute_wcc_band(isl_ctx *ctx, struct isl_sched_graph *graph) { int has_coincidence; @@ -5918,8 +5711,8 @@ static isl_stat compute_schedule_wcc_band(isl_ctx *ctx, * the graph as a whole and return the updated schedule node. * * The actual schedule rows of the current band are computed by - * compute_schedule_wcc_band. compute_schedule_finish_band takes - * care of integrating the band into "node" and continuing + * isl_schedule_node_compute_wcc_band. isl_schedule_node_compute_finish_band + * takes care of integrating the band into "node" and continuing * the computation. */ static __isl_give isl_schedule_node *compute_schedule_wcc_whole( @@ -5931,1535 +5724,10 @@ static __isl_give isl_schedule_node *compute_schedule_wcc_whole( return NULL; ctx = isl_schedule_node_get_ctx(node); - if (compute_schedule_wcc_band(ctx, graph) < 0) + if (isl_schedule_node_compute_wcc_band(ctx, graph) < 0) return isl_schedule_node_free(node); - return compute_schedule_finish_band(node, graph, 1); -} - -/* Clustering information used by compute_schedule_wcc_clustering. - * - * "n" is the number of SCCs in the original dependence graph - * "scc" is an array of "n" elements, each representing an SCC - * of the original dependence graph. All entries in the same cluster - * have the same number of schedule rows. - * "scc_cluster" maps each SCC index to the cluster to which it belongs, - * where each cluster is represented by the index of the first SCC - * in the cluster. Initially, each SCC belongs to a cluster containing - * only that SCC. - * - * "scc_in_merge" is used by merge_clusters_along_edge to keep - * track of which SCCs need to be merged. - * - * "cluster" contains the merged clusters of SCCs after the clustering - * has completed. - * - * "scc_node" is a temporary data structure used inside copy_partial. - * For each SCC, it keeps track of the number of nodes in the SCC - * that have already been copied. - */ -struct isl_clustering { - int n; - struct isl_sched_graph *scc; - struct isl_sched_graph *cluster; - int *scc_cluster; - int *scc_node; - int *scc_in_merge; -}; - -/* Initialize the clustering data structure "c" from "graph". - * - * In particular, allocate memory, extract the SCCs from "graph" - * into c->scc, initialize scc_cluster and construct - * a band of schedule rows for each SCC. - * Within each SCC, there is only one SCC by definition. - * Each SCC initially belongs to a cluster containing only that SCC. - */ -static isl_stat clustering_init(isl_ctx *ctx, struct isl_clustering *c, - struct isl_sched_graph *graph) -{ - int i; - - c->n = graph->scc; - c->scc = isl_calloc_array(ctx, struct isl_sched_graph, c->n); - c->cluster = isl_calloc_array(ctx, struct isl_sched_graph, c->n); - c->scc_cluster = isl_calloc_array(ctx, int, c->n); - c->scc_node = isl_calloc_array(ctx, int, c->n); - c->scc_in_merge = isl_calloc_array(ctx, int, c->n); - if (!c->scc || !c->cluster || - !c->scc_cluster || !c->scc_node || !c->scc_in_merge) - return isl_stat_error; - - for (i = 0; i < c->n; ++i) { - if (extract_sub_graph(ctx, graph, &node_scc_exactly, - &edge_scc_exactly, i, &c->scc[i]) < 0) - return isl_stat_error; - c->scc[i].scc = 1; - if (compute_maxvar(&c->scc[i]) < 0) - return isl_stat_error; - if (compute_schedule_wcc_band(ctx, &c->scc[i]) < 0) - return isl_stat_error; - c->scc_cluster[i] = i; - } - - return isl_stat_ok; -} - -/* Free all memory allocated for "c". - */ -static void clustering_free(isl_ctx *ctx, struct isl_clustering *c) -{ - int i; - - if (c->scc) - for (i = 0; i < c->n; ++i) - graph_free(ctx, &c->scc[i]); - free(c->scc); - if (c->cluster) - for (i = 0; i < c->n; ++i) - graph_free(ctx, &c->cluster[i]); - free(c->cluster); - free(c->scc_cluster); - free(c->scc_node); - free(c->scc_in_merge); -} - -/* Should we refrain from merging the cluster in "graph" with - * any other cluster? - * In particular, is its current schedule band empty and incomplete. - */ -static int bad_cluster(struct isl_sched_graph *graph) -{ - return graph->n_row < graph->maxvar && - graph->n_total_row == graph->band_start; -} - -/* Is "edge" a proximity edge with a non-empty dependence relation? - */ -static isl_bool is_non_empty_proximity(struct isl_sched_edge *edge) -{ - if (!is_proximity(edge)) - return isl_bool_false; - return isl_bool_not(isl_map_plain_is_empty(edge->map)); -} - -/* Return the index of an edge in "graph" that can be used to merge - * two clusters in "c". - * Return graph->n_edge if no such edge can be found. - * Return -1 on error. - * - * In particular, return a proximity edge between two clusters - * that is not marked "no_merge" and such that neither of the - * two clusters has an incomplete, empty band. - * - * If there are multiple such edges, then try and find the most - * appropriate edge to use for merging. In particular, pick the edge - * with the greatest weight. If there are multiple of those, - * then pick one with the shortest distance between - * the two cluster representatives. - */ -static int find_proximity(struct isl_sched_graph *graph, - struct isl_clustering *c) -{ - int i, best = graph->n_edge, best_dist, best_weight; - - for (i = 0; i < graph->n_edge; ++i) { - struct isl_sched_edge *edge = &graph->edge[i]; - int dist, weight; - isl_bool prox; - - prox = is_non_empty_proximity(edge); - if (prox < 0) - return -1; - if (!prox) - continue; - if (edge->no_merge) - continue; - if (bad_cluster(&c->scc[edge->src->scc]) || - bad_cluster(&c->scc[edge->dst->scc])) - continue; - dist = c->scc_cluster[edge->dst->scc] - - c->scc_cluster[edge->src->scc]; - if (dist == 0) - continue; - weight = edge->weight; - if (best < graph->n_edge) { - if (best_weight > weight) - continue; - if (best_weight == weight && best_dist <= dist) - continue; - } - best = i; - best_dist = dist; - best_weight = weight; - } - - return best; -} - -/* Internal data structure used in mark_merge_sccs. - * - * "graph" is the dependence graph in which a strongly connected - * component is constructed. - * "scc_cluster" maps each SCC index to the cluster to which it belongs. - * "src" and "dst" are the indices of the nodes that are being merged. - */ -struct isl_mark_merge_sccs_data { - struct isl_sched_graph *graph; - int *scc_cluster; - int src; - int dst; -}; - -/* Check whether the cluster containing node "i" depends on the cluster - * containing node "j". If "i" and "j" belong to the same cluster, - * then they are taken to depend on each other to ensure that - * the resulting strongly connected component consists of complete - * clusters. Furthermore, if "i" and "j" are the two nodes that - * are being merged, then they are taken to depend on each other as well. - * Otherwise, check if there is a (conditional) validity dependence - * from node[j] to node[i], forcing node[i] to follow node[j]. - */ -static isl_bool cluster_follows(int i, int j, void *user) -{ - struct isl_mark_merge_sccs_data *data = user; - struct isl_sched_graph *graph = data->graph; - int *scc_cluster = data->scc_cluster; - - if (data->src == i && data->dst == j) - return isl_bool_true; - if (data->src == j && data->dst == i) - return isl_bool_true; - if (scc_cluster[graph->node[i].scc] == scc_cluster[graph->node[j].scc]) - return isl_bool_true; - - return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); -} - -/* Mark all SCCs that belong to either of the two clusters in "c" - * connected by the edge in "graph" with index "edge", or to any - * of the intermediate clusters. - * The marking is recorded in c->scc_in_merge. - * - * The given edge has been selected for merging two clusters, - * meaning that there is at least a proximity edge between the two nodes. - * However, there may also be (indirect) validity dependences - * between the two nodes. When merging the two clusters, all clusters - * containing one or more of the intermediate nodes along the - * indirect validity dependences need to be merged in as well. - * - * First collect all such nodes by computing the strongly connected - * component (SCC) containing the two nodes connected by the edge, where - * the two nodes are considered to depend on each other to make - * sure they end up in the same SCC. Similarly, each node is considered - * to depend on every other node in the same cluster to ensure - * that the SCC consists of complete clusters. - * - * Then the original SCCs that contain any of these nodes are marked - * in c->scc_in_merge. - */ -static isl_stat mark_merge_sccs(isl_ctx *ctx, struct isl_sched_graph *graph, - int edge, struct isl_clustering *c) -{ - struct isl_mark_merge_sccs_data data; - struct isl_tarjan_graph *g; - int i; - - for (i = 0; i < c->n; ++i) - c->scc_in_merge[i] = 0; - - data.graph = graph; - data.scc_cluster = c->scc_cluster; - data.src = graph->edge[edge].src - graph->node; - data.dst = graph->edge[edge].dst - graph->node; - - g = isl_tarjan_graph_component(ctx, graph->n, data.dst, - &cluster_follows, &data); - if (!g) - goto error; - - i = g->op; - if (i < 3) - isl_die(ctx, isl_error_internal, - "expecting at least two nodes in component", - goto error); - if (g->order[--i] != -1) - isl_die(ctx, isl_error_internal, - "expecting end of component marker", goto error); - - for (--i; i >= 0 && g->order[i] != -1; --i) { - int scc = graph->node[g->order[i]].scc; - c->scc_in_merge[scc] = 1; - } - - isl_tarjan_graph_free(g); - return isl_stat_ok; -error: - isl_tarjan_graph_free(g); - return isl_stat_error; -} - -/* Construct the identifier "cluster_i". - */ -static __isl_give isl_id *cluster_id(isl_ctx *ctx, int i) -{ - char name[40]; - - snprintf(name, sizeof(name), "cluster_%d", i); - return isl_id_alloc(ctx, name, NULL); -} - -/* Construct the space of the cluster with index "i" containing - * the strongly connected component "scc". - * - * In particular, construct a space called cluster_i with dimension equal - * to the number of schedule rows in the current band of "scc". - */ -static __isl_give isl_space *cluster_space(struct isl_sched_graph *scc, int i) -{ - int nvar; - isl_space *space; - isl_id *id; - - nvar = scc->n_total_row - scc->band_start; - space = isl_space_copy(scc->node[0].space); - space = isl_space_params(space); - space = isl_space_set_from_params(space); - space = isl_space_add_dims(space, isl_dim_set, nvar); - id = cluster_id(isl_space_get_ctx(space), i); - space = isl_space_set_tuple_id(space, isl_dim_set, id); - - return space; -} - -/* Collect the domain of the graph for merging clusters. - * - * In particular, for each cluster with first SCC "i", construct - * a set in the space called cluster_i with dimension equal - * to the number of schedule rows in the current band of the cluster. - */ -static __isl_give isl_union_set *collect_domain(isl_ctx *ctx, - struct isl_sched_graph *graph, struct isl_clustering *c) -{ - int i; - isl_space *space; - isl_union_set *domain; - - space = isl_space_params_alloc(ctx, 0); - domain = isl_union_set_empty(space); - - for (i = 0; i < graph->scc; ++i) { - isl_space *space; - - if (!c->scc_in_merge[i]) - continue; - if (c->scc_cluster[i] != i) - continue; - space = cluster_space(&c->scc[i], i); - domain = isl_union_set_add_set(domain, isl_set_universe(space)); - } - - return domain; -} - -/* Construct a map from the original instances to the corresponding - * cluster instance in the current bands of the clusters in "c". - */ -static __isl_give isl_union_map *collect_cluster_map(isl_ctx *ctx, - struct isl_sched_graph *graph, struct isl_clustering *c) -{ - int i, j; - isl_space *space; - isl_union_map *cluster_map; - - space = isl_space_params_alloc(ctx, 0); - cluster_map = isl_union_map_empty(space); - for (i = 0; i < graph->scc; ++i) { - int start, n; - isl_id *id; - - if (!c->scc_in_merge[i]) - continue; - - id = cluster_id(ctx, c->scc_cluster[i]); - start = c->scc[i].band_start; - n = c->scc[i].n_total_row - start; - for (j = 0; j < c->scc[i].n; ++j) { - isl_multi_aff *ma; - isl_map *map; - struct isl_sched_node *node = &c->scc[i].node[j]; - - ma = node_extract_partial_schedule_multi_aff(node, - start, n); - ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, - isl_id_copy(id)); - map = isl_map_from_multi_aff(ma); - cluster_map = isl_union_map_add_map(cluster_map, map); - } - isl_id_free(id); - } - - return cluster_map; -} - -/* Add "umap" to the schedule constraints "sc" of all types of "edge" - * that are not isl_edge_condition or isl_edge_conditional_validity. - */ -static __isl_give isl_schedule_constraints *add_non_conditional_constraints( - struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, - __isl_take isl_schedule_constraints *sc) -{ - enum isl_edge_type t; - - if (!sc) - return NULL; - - for (t = isl_edge_first; t <= isl_edge_last; ++t) { - if (t == isl_edge_condition || - t == isl_edge_conditional_validity) - continue; - if (!is_type(edge, t)) - continue; - sc = isl_schedule_constraints_add(sc, t, - isl_union_map_copy(umap)); - } - - return sc; -} - -/* Add schedule constraints of types isl_edge_condition and - * isl_edge_conditional_validity to "sc" by applying "umap" to - * the domains of the wrapped relations in domain and range - * of the corresponding tagged constraints of "edge". - */ -static __isl_give isl_schedule_constraints *add_conditional_constraints( - struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, - __isl_take isl_schedule_constraints *sc) -{ - enum isl_edge_type t; - isl_union_map *tagged; - - for (t = isl_edge_condition; t <= isl_edge_conditional_validity; ++t) { - if (!is_type(edge, t)) - continue; - if (t == isl_edge_condition) - tagged = isl_union_map_copy(edge->tagged_condition); - else - tagged = isl_union_map_copy(edge->tagged_validity); - tagged = isl_union_map_zip(tagged); - tagged = isl_union_map_apply_domain(tagged, - isl_union_map_copy(umap)); - tagged = isl_union_map_zip(tagged); - sc = isl_schedule_constraints_add(sc, t, tagged); - if (!sc) - return NULL; - } - - return sc; -} - -/* Given a mapping "cluster_map" from the original instances to - * the cluster instances, add schedule constraints on the clusters - * to "sc" corresponding to the original constraints represented by "edge". - * - * For non-tagged dependence constraints, the cluster constraints - * are obtained by applying "cluster_map" to the edge->map. - * - * For tagged dependence constraints, "cluster_map" needs to be applied - * to the domains of the wrapped relations in domain and range - * of the tagged dependence constraints. Pick out the mappings - * from these domains from "cluster_map" and construct their product. - * This mapping can then be applied to the pair of domains. - */ -static __isl_give isl_schedule_constraints *collect_edge_constraints( - struct isl_sched_edge *edge, __isl_keep isl_union_map *cluster_map, - __isl_take isl_schedule_constraints *sc) -{ - isl_union_map *umap; - isl_space *space; - isl_union_set *uset; - isl_union_map *umap1, *umap2; - - if (!sc) - return NULL; - - umap = isl_union_map_from_map(isl_map_copy(edge->map)); - umap = isl_union_map_apply_domain(umap, - isl_union_map_copy(cluster_map)); - umap = isl_union_map_apply_range(umap, - isl_union_map_copy(cluster_map)); - sc = add_non_conditional_constraints(edge, umap, sc); - isl_union_map_free(umap); - - if (!sc || (!is_condition(edge) && !is_conditional_validity(edge))) - return sc; - - space = isl_space_domain(isl_map_get_space(edge->map)); - uset = isl_union_set_from_set(isl_set_universe(space)); - umap1 = isl_union_map_copy(cluster_map); - umap1 = isl_union_map_intersect_domain(umap1, uset); - space = isl_space_range(isl_map_get_space(edge->map)); - uset = isl_union_set_from_set(isl_set_universe(space)); - umap2 = isl_union_map_copy(cluster_map); - umap2 = isl_union_map_intersect_domain(umap2, uset); - umap = isl_union_map_product(umap1, umap2); - - sc = add_conditional_constraints(edge, umap, sc); - - isl_union_map_free(umap); - return sc; -} - -/* Given a mapping "cluster_map" from the original instances to - * the cluster instances, add schedule constraints on the clusters - * to "sc" corresponding to all edges in "graph" between nodes that - * belong to SCCs that are marked for merging in "scc_in_merge". - */ -static __isl_give isl_schedule_constraints *collect_constraints( - struct isl_sched_graph *graph, int *scc_in_merge, - __isl_keep isl_union_map *cluster_map, - __isl_take isl_schedule_constraints *sc) -{ - int i; - - for (i = 0; i < graph->n_edge; ++i) { - struct isl_sched_edge *edge = &graph->edge[i]; - - if (!scc_in_merge[edge->src->scc]) - continue; - if (!scc_in_merge[edge->dst->scc]) - continue; - sc = collect_edge_constraints(edge, cluster_map, sc); - } - - return sc; -} - -/* Construct a dependence graph for scheduling clusters with respect - * to each other and store the result in "merge_graph". - * In particular, the nodes of the graph correspond to the schedule - * dimensions of the current bands of those clusters that have been - * marked for merging in "c". - * - * First construct an isl_schedule_constraints object for this domain - * by transforming the edges in "graph" to the domain. - * Then initialize a dependence graph for scheduling from these - * constraints. - */ -static isl_stat init_merge_graph(isl_ctx *ctx, struct isl_sched_graph *graph, - struct isl_clustering *c, struct isl_sched_graph *merge_graph) -{ - isl_union_set *domain; - isl_union_map *cluster_map; - isl_schedule_constraints *sc; - isl_stat r; - - domain = collect_domain(ctx, graph, c); - sc = isl_schedule_constraints_on_domain(domain); - if (!sc) - return isl_stat_error; - cluster_map = collect_cluster_map(ctx, graph, c); - sc = collect_constraints(graph, c->scc_in_merge, cluster_map, sc); - isl_union_map_free(cluster_map); - - r = graph_init(merge_graph, sc); - - isl_schedule_constraints_free(sc); - - return r; -} - -/* Compute the maximal number of remaining schedule rows that still need - * to be computed for the nodes that belong to clusters with the maximal - * dimension for the current band (i.e., the band that is to be merged). - * Only clusters that are about to be merged are considered. - * "maxvar" is the maximal dimension for the current band. - * "c" contains information about the clusters. - * - * Return the maximal number of remaining schedule rows or -1 on error. - */ -static int compute_maxvar_max_slack(int maxvar, struct isl_clustering *c) -{ - int i, j; - int max_slack; - - max_slack = 0; - for (i = 0; i < c->n; ++i) { - int nvar; - struct isl_sched_graph *scc; - - if (!c->scc_in_merge[i]) - continue; - scc = &c->scc[i]; - nvar = scc->n_total_row - scc->band_start; - if (nvar != maxvar) - continue; - for (j = 0; j < scc->n; ++j) { - struct isl_sched_node *node = &scc->node[j]; - int slack; - - if (node_update_vmap(node) < 0) - return -1; - slack = node->nvar - node->rank; - if (slack > max_slack) - max_slack = slack; - } - } - - return max_slack; -} - -/* If there are any clusters where the dimension of the current band - * (i.e., the band that is to be merged) is smaller than "maxvar" and - * if there are any nodes in such a cluster where the number - * of remaining schedule rows that still need to be computed - * is greater than "max_slack", then return the smallest current band - * dimension of all these clusters. Otherwise return the original value - * of "maxvar". Return -1 in case of any error. - * Only clusters that are about to be merged are considered. - * "c" contains information about the clusters. - */ -static int limit_maxvar_to_slack(int maxvar, int max_slack, - struct isl_clustering *c) -{ - int i, j; - - for (i = 0; i < c->n; ++i) { - int nvar; - struct isl_sched_graph *scc; - - if (!c->scc_in_merge[i]) - continue; - scc = &c->scc[i]; - nvar = scc->n_total_row - scc->band_start; - if (nvar >= maxvar) - continue; - for (j = 0; j < scc->n; ++j) { - struct isl_sched_node *node = &scc->node[j]; - int slack; - - if (node_update_vmap(node) < 0) - return -1; - slack = node->nvar - node->rank; - if (slack > max_slack) { - maxvar = nvar; - break; - } - } - } - - return maxvar; -} - -/* Adjust merge_graph->maxvar based on the number of remaining schedule rows - * that still need to be computed. In particular, if there is a node - * in a cluster where the dimension of the current band is smaller - * than merge_graph->maxvar, but the number of remaining schedule rows - * is greater than that of any node in a cluster with the maximal - * dimension for the current band (i.e., merge_graph->maxvar), - * then adjust merge_graph->maxvar to the (smallest) current band dimension - * of those clusters. Without this adjustment, the total number of - * schedule dimensions would be increased, resulting in a skewed view - * of the number of coincident dimensions. - * "c" contains information about the clusters. - * - * If the maximize_band_depth option is set and merge_graph->maxvar is reduced, - * then there is no point in attempting any merge since it will be rejected - * anyway. Set merge_graph->maxvar to zero in such cases. - */ -static isl_stat adjust_maxvar_to_slack(isl_ctx *ctx, - struct isl_sched_graph *merge_graph, struct isl_clustering *c) -{ - int max_slack, maxvar; - - max_slack = compute_maxvar_max_slack(merge_graph->maxvar, c); - if (max_slack < 0) - return isl_stat_error; - maxvar = limit_maxvar_to_slack(merge_graph->maxvar, max_slack, c); - if (maxvar < 0) - return isl_stat_error; - - if (maxvar < merge_graph->maxvar) { - if (isl_options_get_schedule_maximize_band_depth(ctx)) - merge_graph->maxvar = 0; - else - merge_graph->maxvar = maxvar; - } - - return isl_stat_ok; -} - -/* Return the number of coincident dimensions in the current band of "graph", - * where the nodes of "graph" are assumed to be scheduled by a single band. - */ -static int get_n_coincident(struct isl_sched_graph *graph) -{ - int i; - - for (i = graph->band_start; i < graph->n_total_row; ++i) - if (!graph->node[0].coincident[i]) - break; - - return i - graph->band_start; -} - -/* Should the clusters be merged based on the cluster schedule - * in the current (and only) band of "merge_graph", given that - * coincidence should be maximized? - * - * If the number of coincident schedule dimensions in the merged band - * would be less than the maximal number of coincident schedule dimensions - * in any of the merged clusters, then the clusters should not be merged. - */ -static isl_bool ok_to_merge_coincident(struct isl_clustering *c, - struct isl_sched_graph *merge_graph) -{ - int i; - int n_coincident; - int max_coincident; - - max_coincident = 0; - for (i = 0; i < c->n; ++i) { - if (!c->scc_in_merge[i]) - continue; - n_coincident = get_n_coincident(&c->scc[i]); - if (n_coincident > max_coincident) - max_coincident = n_coincident; - } - - n_coincident = get_n_coincident(merge_graph); - - return isl_bool_ok(n_coincident >= max_coincident); -} - -/* Return the transformation on "node" expressed by the current (and only) - * band of "merge_graph" applied to the clusters in "c". - * - * First find the representation of "node" in its SCC in "c" and - * extract the transformation expressed by the current band. - * Then extract the transformation applied by "merge_graph" - * to the cluster to which this SCC belongs. - * Combine the two to obtain the complete transformation on the node. - * - * Note that the range of the first transformation is an anonymous space, - * while the domain of the second is named "cluster_X". The range - * of the former therefore needs to be adjusted before the two - * can be combined. - */ -static __isl_give isl_map *extract_node_transformation(isl_ctx *ctx, - struct isl_sched_node *node, struct isl_clustering *c, - struct isl_sched_graph *merge_graph) -{ - struct isl_sched_node *scc_node, *cluster_node; - int start, n; - isl_id *id; - isl_space *space; - isl_multi_aff *ma, *ma2; - - scc_node = graph_find_node(ctx, &c->scc[node->scc], node->space); - if (scc_node && !is_node(&c->scc[node->scc], scc_node)) - isl_die(ctx, isl_error_internal, "unable to find node", - return NULL); - start = c->scc[node->scc].band_start; - n = c->scc[node->scc].n_total_row - start; - ma = node_extract_partial_schedule_multi_aff(scc_node, start, n); - space = cluster_space(&c->scc[node->scc], c->scc_cluster[node->scc]); - cluster_node = graph_find_node(ctx, merge_graph, space); - if (cluster_node && !is_node(merge_graph, cluster_node)) - isl_die(ctx, isl_error_internal, "unable to find cluster", - space = isl_space_free(space)); - id = isl_space_get_tuple_id(space, isl_dim_set); - ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, id); - isl_space_free(space); - n = merge_graph->n_total_row; - ma2 = node_extract_partial_schedule_multi_aff(cluster_node, 0, n); - ma = isl_multi_aff_pullback_multi_aff(ma2, ma); - - return isl_map_from_multi_aff(ma); -} - -/* Give a set of distances "set", are they bounded by a small constant - * in direction "pos"? - * In practice, check if they are bounded by 2 by checking that there - * are no elements with a value greater than or equal to 3 or - * smaller than or equal to -3. - */ -static isl_bool distance_is_bounded(__isl_keep isl_set *set, int pos) -{ - isl_bool bounded; - isl_set *test; - - if (!set) - return isl_bool_error; - - test = isl_set_copy(set); - test = isl_set_lower_bound_si(test, isl_dim_set, pos, 3); - bounded = isl_set_is_empty(test); - isl_set_free(test); - - if (bounded < 0 || !bounded) - return bounded; - - test = isl_set_copy(set); - test = isl_set_upper_bound_si(test, isl_dim_set, pos, -3); - bounded = isl_set_is_empty(test); - isl_set_free(test); - - return bounded; -} - -/* Does the set "set" have a fixed (but possible parametric) value - * at dimension "pos"? - */ -static isl_bool has_single_value(__isl_keep isl_set *set, int pos) -{ - isl_size n; - isl_bool single; - - n = isl_set_dim(set, isl_dim_set); - if (n < 0) - return isl_bool_error; - set = isl_set_copy(set); - set = isl_set_project_out(set, isl_dim_set, pos + 1, n - (pos + 1)); - set = isl_set_project_out(set, isl_dim_set, 0, pos); - single = isl_set_is_singleton(set); - isl_set_free(set); - - return single; -} - -/* Does "map" have a fixed (but possible parametric) value - * at dimension "pos" of either its domain or its range? - */ -static isl_bool has_singular_src_or_dst(__isl_keep isl_map *map, int pos) -{ - isl_set *set; - isl_bool single; - - set = isl_map_domain(isl_map_copy(map)); - single = has_single_value(set, pos); - isl_set_free(set); - - if (single < 0 || single) - return single; - - set = isl_map_range(isl_map_copy(map)); - single = has_single_value(set, pos); - isl_set_free(set); - - return single; -} - -/* Does the edge "edge" from "graph" have bounded dependence distances - * in the merged graph "merge_graph" of a selection of clusters in "c"? - * - * Extract the complete transformations of the source and destination - * nodes of the edge, apply them to the edge constraints and - * compute the differences. Finally, check if these differences are bounded - * in each direction. - * - * If the dimension of the band is greater than the number of - * dimensions that can be expected to be optimized by the edge - * (based on its weight), then also allow the differences to be unbounded - * in the remaining dimensions, but only if either the source or - * the destination has a fixed value in that direction. - * This allows a statement that produces values that are used by - * several instances of another statement to be merged with that - * other statement. - * However, merging such clusters will introduce an inherently - * large proximity distance inside the merged cluster, meaning - * that proximity distances will no longer be optimized in - * subsequent merges. These merges are therefore only allowed - * after all other possible merges have been tried. - * The first time such a merge is encountered, the weight of the edge - * is replaced by a negative weight. The second time (i.e., after - * all merges over edges with a non-negative weight have been tried), - * the merge is allowed. - */ -static isl_bool has_bounded_distances(isl_ctx *ctx, struct isl_sched_edge *edge, - struct isl_sched_graph *graph, struct isl_clustering *c, - struct isl_sched_graph *merge_graph) -{ - int i, n_slack; - isl_size n; - isl_bool bounded; - isl_map *map, *t; - isl_set *dist; - - map = isl_map_copy(edge->map); - t = extract_node_transformation(ctx, edge->src, c, merge_graph); - map = isl_map_apply_domain(map, t); - t = extract_node_transformation(ctx, edge->dst, c, merge_graph); - map = isl_map_apply_range(map, t); - dist = isl_map_deltas(isl_map_copy(map)); - - bounded = isl_bool_true; - n = isl_set_dim(dist, isl_dim_set); - if (n < 0) - goto error; - n_slack = n - edge->weight; - if (edge->weight < 0) - n_slack -= graph->max_weight + 1; - for (i = 0; i < n; ++i) { - isl_bool bounded_i, singular_i; - - bounded_i = distance_is_bounded(dist, i); - if (bounded_i < 0) - goto error; - if (bounded_i) - continue; - if (edge->weight >= 0) - bounded = isl_bool_false; - n_slack--; - if (n_slack < 0) - break; - singular_i = has_singular_src_or_dst(map, i); - if (singular_i < 0) - goto error; - if (singular_i) - continue; - bounded = isl_bool_false; - break; - } - if (!bounded && i >= n && edge->weight >= 0) - edge->weight -= graph->max_weight + 1; - isl_map_free(map); - isl_set_free(dist); - - return bounded; -error: - isl_map_free(map); - isl_set_free(dist); - return isl_bool_error; -} - -/* Should the clusters be merged based on the cluster schedule - * in the current (and only) band of "merge_graph"? - * "graph" is the original dependence graph, while "c" records - * which SCCs are involved in the latest merge. - * - * In particular, is there at least one proximity constraint - * that is optimized by the merge? - * - * A proximity constraint is considered to be optimized - * if the dependence distances are small. - */ -static isl_bool ok_to_merge_proximity(isl_ctx *ctx, - struct isl_sched_graph *graph, struct isl_clustering *c, - struct isl_sched_graph *merge_graph) -{ - int i; - - for (i = 0; i < graph->n_edge; ++i) { - struct isl_sched_edge *edge = &graph->edge[i]; - isl_bool bounded; - - if (!is_proximity(edge)) - continue; - if (!c->scc_in_merge[edge->src->scc]) - continue; - if (!c->scc_in_merge[edge->dst->scc]) - continue; - if (c->scc_cluster[edge->dst->scc] == - c->scc_cluster[edge->src->scc]) - continue; - bounded = has_bounded_distances(ctx, edge, graph, c, - merge_graph); - if (bounded < 0 || bounded) - return bounded; - } - - return isl_bool_false; -} - -/* Should the clusters be merged based on the cluster schedule - * in the current (and only) band of "merge_graph"? - * "graph" is the original dependence graph, while "c" records - * which SCCs are involved in the latest merge. - * - * If the current band is empty, then the clusters should not be merged. - * - * If the band depth should be maximized and the merge schedule - * is incomplete (meaning that the dimension of some of the schedule - * bands in the original schedule will be reduced), then the clusters - * should not be merged. - * - * If the schedule_maximize_coincidence option is set, then check that - * the number of coincident schedule dimensions is not reduced. - * - * Finally, only allow the merge if at least one proximity - * constraint is optimized. - */ -static isl_bool ok_to_merge(isl_ctx *ctx, struct isl_sched_graph *graph, - struct isl_clustering *c, struct isl_sched_graph *merge_graph) -{ - if (merge_graph->n_total_row == merge_graph->band_start) - return isl_bool_false; - - if (isl_options_get_schedule_maximize_band_depth(ctx) && - merge_graph->n_total_row < merge_graph->maxvar) - return isl_bool_false; - - if (isl_options_get_schedule_maximize_coincidence(ctx)) { - isl_bool ok; - - ok = ok_to_merge_coincident(c, merge_graph); - if (ok < 0 || !ok) - return ok; - } - - return ok_to_merge_proximity(ctx, graph, c, merge_graph); -} - -/* Apply the schedule in "t_node" to the "n" rows starting at "first" - * of the schedule in "node" and return the result. - * - * That is, essentially compute - * - * T * N(first:first+n-1) - * - * taking into account the constant term and the parameter coefficients - * in "t_node". - */ -static __isl_give isl_mat *node_transformation(isl_ctx *ctx, - struct isl_sched_node *t_node, struct isl_sched_node *node, - int first, int n) -{ - int i, j; - isl_mat *t; - isl_size n_row, n_col; - int n_param, n_var; - - n_param = node->nparam; - n_var = node->nvar; - n_row = isl_mat_rows(t_node->sched); - n_col = isl_mat_cols(node->sched); - if (n_row < 0 || n_col < 0) - return NULL; - t = isl_mat_alloc(ctx, n_row, n_col); - if (!t) - return NULL; - for (i = 0; i < n_row; ++i) { - isl_seq_cpy(t->row[i], t_node->sched->row[i], 1 + n_param); - isl_seq_clr(t->row[i] + 1 + n_param, n_var); - for (j = 0; j < n; ++j) - isl_seq_addmul(t->row[i], - t_node->sched->row[i][1 + n_param + j], - node->sched->row[first + j], - 1 + n_param + n_var); - } - return t; -} - -/* Apply the cluster schedule in "t_node" to the current band - * schedule of the nodes in "graph". - * - * In particular, replace the rows starting at band_start - * by the result of applying the cluster schedule in "t_node" - * to the original rows. - * - * The coincidence of the schedule is determined by the coincidence - * of the cluster schedule. - */ -static isl_stat transform(isl_ctx *ctx, struct isl_sched_graph *graph, - struct isl_sched_node *t_node) -{ - int i, j; - isl_size n_new; - int start, n; - - start = graph->band_start; - n = graph->n_total_row - start; - - n_new = isl_mat_rows(t_node->sched); - if (n_new < 0) - return isl_stat_error; - for (i = 0; i < graph->n; ++i) { - struct isl_sched_node *node = &graph->node[i]; - isl_mat *t; - - t = node_transformation(ctx, t_node, node, start, n); - node->sched = isl_mat_drop_rows(node->sched, start, n); - node->sched = isl_mat_concat(node->sched, t); - node->sched_map = isl_map_free(node->sched_map); - if (!node->sched) - return isl_stat_error; - for (j = 0; j < n_new; ++j) - node->coincident[start + j] = t_node->coincident[j]; - } - graph->n_total_row -= n; - graph->n_row -= n; - graph->n_total_row += n_new; - graph->n_row += n_new; - - return isl_stat_ok; -} - -/* Merge the clusters marked for merging in "c" into a single - * cluster using the cluster schedule in the current band of "merge_graph". - * The representative SCC for the new cluster is the SCC with - * the smallest index. - * - * The current band schedule of each SCC in the new cluster is obtained - * by applying the schedule of the corresponding original cluster - * to the original band schedule. - * All SCCs in the new cluster have the same number of schedule rows. - */ -static isl_stat merge(isl_ctx *ctx, struct isl_clustering *c, - struct isl_sched_graph *merge_graph) -{ - int i; - int cluster = -1; - isl_space *space; - - for (i = 0; i < c->n; ++i) { - struct isl_sched_node *node; - - if (!c->scc_in_merge[i]) - continue; - if (cluster < 0) - cluster = i; - space = cluster_space(&c->scc[i], c->scc_cluster[i]); - node = graph_find_node(ctx, merge_graph, space); - isl_space_free(space); - if (!node) - return isl_stat_error; - if (!is_node(merge_graph, node)) - isl_die(ctx, isl_error_internal, - "unable to find cluster", - return isl_stat_error); - if (transform(ctx, &c->scc[i], node) < 0) - return isl_stat_error; - c->scc_cluster[i] = cluster; - } - - return isl_stat_ok; -} - -/* Try and merge the clusters of SCCs marked in c->scc_in_merge - * by scheduling the current cluster bands with respect to each other. - * - * Construct a dependence graph with a space for each cluster and - * with the coordinates of each space corresponding to the schedule - * dimensions of the current band of that cluster. - * Construct a cluster schedule in this cluster dependence graph and - * apply it to the current cluster bands if it is applicable - * according to ok_to_merge. - * - * If the number of remaining schedule dimensions in a cluster - * with a non-maximal current schedule dimension is greater than - * the number of remaining schedule dimensions in clusters - * with a maximal current schedule dimension, then restrict - * the number of rows to be computed in the cluster schedule - * to the minimal such non-maximal current schedule dimension. - * Do this by adjusting merge_graph.maxvar. - * - * Return isl_bool_true if the clusters have effectively been merged - * into a single cluster. - * - * Note that since the standard scheduling algorithm minimizes the maximal - * distance over proximity constraints, the proximity constraints between - * the merged clusters may not be optimized any further than what is - * sufficient to bring the distances within the limits of the internal - * proximity constraints inside the individual clusters. - * It may therefore make sense to perform an additional translation step - * to bring the clusters closer to each other, while maintaining - * the linear part of the merging schedule found using the standard - * scheduling algorithm. - */ -static isl_bool try_merge(isl_ctx *ctx, struct isl_sched_graph *graph, - struct isl_clustering *c) -{ - struct isl_sched_graph merge_graph = { 0 }; - isl_bool merged; - - if (init_merge_graph(ctx, graph, c, &merge_graph) < 0) - goto error; - - if (compute_maxvar(&merge_graph) < 0) - goto error; - if (adjust_maxvar_to_slack(ctx, &merge_graph,c) < 0) - goto error; - if (compute_schedule_wcc_band(ctx, &merge_graph) < 0) - goto error; - merged = ok_to_merge(ctx, graph, c, &merge_graph); - if (merged && merge(ctx, c, &merge_graph) < 0) - goto error; - - graph_free(ctx, &merge_graph); - return merged; -error: - graph_free(ctx, &merge_graph); - return isl_bool_error; -} - -/* Is there any edge marked "no_merge" between two SCCs that are - * about to be merged (i.e., that are set in "scc_in_merge")? - * "merge_edge" is the proximity edge along which the clusters of SCCs - * are going to be merged. - * - * If there is any edge between two SCCs with a negative weight, - * while the weight of "merge_edge" is non-negative, then this - * means that the edge was postponed. "merge_edge" should then - * also be postponed since merging along the edge with negative weight should - * be postponed until all edges with non-negative weight have been tried. - * Replace the weight of "merge_edge" by a negative weight as well and - * tell the caller not to attempt a merge. - */ -static int any_no_merge(struct isl_sched_graph *graph, int *scc_in_merge, - struct isl_sched_edge *merge_edge) -{ - int i; - - for (i = 0; i < graph->n_edge; ++i) { - struct isl_sched_edge *edge = &graph->edge[i]; - - if (!scc_in_merge[edge->src->scc]) - continue; - if (!scc_in_merge[edge->dst->scc]) - continue; - if (edge->no_merge) - return 1; - if (merge_edge->weight >= 0 && edge->weight < 0) { - merge_edge->weight -= graph->max_weight + 1; - return 1; - } - } - - return 0; -} - -/* Merge the two clusters in "c" connected by the edge in "graph" - * with index "edge" into a single cluster. - * If it turns out to be impossible to merge these two clusters, - * then mark the edge as "no_merge" such that it will not be - * considered again. - * - * First mark all SCCs that need to be merged. This includes the SCCs - * in the two clusters, but it may also include the SCCs - * of intermediate clusters. - * If there is already a no_merge edge between any pair of such SCCs, - * then simply mark the current edge as no_merge as well. - * Likewise, if any of those edges was postponed by has_bounded_distances, - * then postpone the current edge as well. - * Otherwise, try and merge the clusters and mark "edge" as "no_merge" - * if the clusters did not end up getting merged, unless the non-merge - * is due to the fact that the edge was postponed. This postponement - * can be recognized by a change in weight (from non-negative to negative). - */ -static isl_stat merge_clusters_along_edge(isl_ctx *ctx, - struct isl_sched_graph *graph, int edge, struct isl_clustering *c) -{ - isl_bool merged; - int edge_weight = graph->edge[edge].weight; - - if (mark_merge_sccs(ctx, graph, edge, c) < 0) - return isl_stat_error; - - if (any_no_merge(graph, c->scc_in_merge, &graph->edge[edge])) - merged = isl_bool_false; - else - merged = try_merge(ctx, graph, c); - if (merged < 0) - return isl_stat_error; - if (!merged && edge_weight == graph->edge[edge].weight) - graph->edge[edge].no_merge = 1; - - return isl_stat_ok; -} - -/* Does "node" belong to the cluster identified by "cluster"? - */ -static int node_cluster_exactly(struct isl_sched_node *node, int cluster) -{ - return node->cluster == cluster; -} - -/* Does "edge" connect two nodes belonging to the cluster - * identified by "cluster"? - */ -static int edge_cluster_exactly(struct isl_sched_edge *edge, int cluster) -{ - return edge->src->cluster == cluster && edge->dst->cluster == cluster; -} - -/* Swap the schedule of "node1" and "node2". - * Both nodes have been derived from the same node in a common parent graph. - * Since the "coincident" field is shared with that node - * in the parent graph, there is no need to also swap this field. - */ -static void swap_sched(struct isl_sched_node *node1, - struct isl_sched_node *node2) -{ - isl_mat *sched; - isl_map *sched_map; - - sched = node1->sched; - node1->sched = node2->sched; - node2->sched = sched; - - sched_map = node1->sched_map; - node1->sched_map = node2->sched_map; - node2->sched_map = sched_map; -} - -/* Copy the current band schedule from the SCCs that form the cluster - * with index "pos" to the actual cluster at position "pos". - * By construction, the index of the first SCC that belongs to the cluster - * is also "pos". - * - * The order of the nodes inside both the SCCs and the cluster - * is assumed to be same as the order in the original "graph". - * - * Since the SCC graphs will no longer be used after this function, - * the schedules are actually swapped rather than copied. - */ -static isl_stat copy_partial(struct isl_sched_graph *graph, - struct isl_clustering *c, int pos) -{ - int i, j; - - c->cluster[pos].n_total_row = c->scc[pos].n_total_row; - c->cluster[pos].n_row = c->scc[pos].n_row; - c->cluster[pos].maxvar = c->scc[pos].maxvar; - j = 0; - for (i = 0; i < graph->n; ++i) { - int k; - int s; - - if (graph->node[i].cluster != pos) - continue; - s = graph->node[i].scc; - k = c->scc_node[s]++; - swap_sched(&c->cluster[pos].node[j], &c->scc[s].node[k]); - if (c->scc[s].maxvar > c->cluster[pos].maxvar) - c->cluster[pos].maxvar = c->scc[s].maxvar; - ++j; - } - - return isl_stat_ok; -} - -/* Is there a (conditional) validity dependence from node[j] to node[i], - * forcing node[i] to follow node[j] or do the nodes belong to the same - * cluster? - */ -static isl_bool node_follows_strong_or_same_cluster(int i, int j, void *user) -{ - struct isl_sched_graph *graph = user; - - if (graph->node[i].cluster == graph->node[j].cluster) - return isl_bool_true; - return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]); -} - -/* Extract the merged clusters of SCCs in "graph", sort them, and - * store them in c->clusters. Update c->scc_cluster accordingly. - * - * First keep track of the cluster containing the SCC to which a node - * belongs in the node itself. - * Then extract the clusters into c->clusters, copying the current - * band schedule from the SCCs that belong to the cluster. - * Do this only once per cluster. - * - * Finally, topologically sort the clusters and update c->scc_cluster - * to match the new scc numbering. While the SCCs were originally - * sorted already, some SCCs that depend on some other SCCs may - * have been merged with SCCs that appear before these other SCCs. - * A reordering may therefore be required. - */ -static isl_stat extract_clusters(isl_ctx *ctx, struct isl_sched_graph *graph, - struct isl_clustering *c) -{ - int i; - - for (i = 0; i < graph->n; ++i) - graph->node[i].cluster = c->scc_cluster[graph->node[i].scc]; - - for (i = 0; i < graph->scc; ++i) { - if (c->scc_cluster[i] != i) - continue; - if (extract_sub_graph(ctx, graph, &node_cluster_exactly, - &edge_cluster_exactly, i, &c->cluster[i]) < 0) - return isl_stat_error; - c->cluster[i].src_scc = -1; - c->cluster[i].dst_scc = -1; - if (copy_partial(graph, c, i) < 0) - return isl_stat_error; - } - - if (detect_ccs(ctx, graph, &node_follows_strong_or_same_cluster) < 0) - return isl_stat_error; - for (i = 0; i < graph->n; ++i) - c->scc_cluster[graph->node[i].scc] = graph->node[i].cluster; - - return isl_stat_ok; -} - -/* Compute weights on the proximity edges of "graph" that can - * be used by find_proximity to find the most appropriate - * proximity edge to use to merge two clusters in "c". - * The weights are also used by has_bounded_distances to determine - * whether the merge should be allowed. - * Store the maximum of the computed weights in graph->max_weight. - * - * The computed weight is a measure for the number of remaining schedule - * dimensions that can still be completely aligned. - * In particular, compute the number of equalities between - * input dimensions and output dimensions in the proximity constraints. - * The directions that are already handled by outer schedule bands - * are projected out prior to determining this number. - * - * Edges that will never be considered by find_proximity are ignored. - */ -static isl_stat compute_weights(struct isl_sched_graph *graph, - struct isl_clustering *c) -{ - int i; - - graph->max_weight = 0; - - for (i = 0; i < graph->n_edge; ++i) { - struct isl_sched_edge *edge = &graph->edge[i]; - struct isl_sched_node *src = edge->src; - struct isl_sched_node *dst = edge->dst; - isl_basic_map *hull; - isl_bool prox; - isl_size n_in, n_out, n; - - prox = is_non_empty_proximity(edge); - if (prox < 0) - return isl_stat_error; - if (!prox) - continue; - if (bad_cluster(&c->scc[edge->src->scc]) || - bad_cluster(&c->scc[edge->dst->scc])) - continue; - if (c->scc_cluster[edge->dst->scc] == - c->scc_cluster[edge->src->scc]) - continue; - - hull = isl_map_affine_hull(isl_map_copy(edge->map)); - hull = isl_basic_map_transform_dims(hull, isl_dim_in, 0, - isl_mat_copy(src->vmap)); - hull = isl_basic_map_transform_dims(hull, isl_dim_out, 0, - isl_mat_copy(dst->vmap)); - hull = isl_basic_map_project_out(hull, - isl_dim_in, 0, src->rank); - hull = isl_basic_map_project_out(hull, - isl_dim_out, 0, dst->rank); - hull = isl_basic_map_remove_divs(hull); - n_in = isl_basic_map_dim(hull, isl_dim_in); - n_out = isl_basic_map_dim(hull, isl_dim_out); - if (n_in < 0 || n_out < 0) - hull = isl_basic_map_free(hull); - hull = isl_basic_map_drop_constraints_not_involving_dims(hull, - isl_dim_in, 0, n_in); - hull = isl_basic_map_drop_constraints_not_involving_dims(hull, - isl_dim_out, 0, n_out); - n = isl_basic_map_n_equality(hull); - isl_basic_map_free(hull); - if (n < 0) - return isl_stat_error; - edge->weight = n; - - if (edge->weight > graph->max_weight) - graph->max_weight = edge->weight; - } - - return isl_stat_ok; -} - -/* Call compute_schedule_finish_band on each of the clusters in "c" - * in their topological order. This order is determined by the scc - * fields of the nodes in "graph". - * Combine the results in a sequence expressing the topological order. - * - * If there is only one cluster left, then there is no need to introduce - * a sequence node. Also, in this case, the cluster necessarily contains - * the SCC at position 0 in the original graph and is therefore also - * stored in the first cluster of "c". - */ -static __isl_give isl_schedule_node *finish_bands_clustering( - __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, - struct isl_clustering *c) -{ - int i; - isl_ctx *ctx; - isl_union_set_list *filters; - - if (graph->scc == 1) - return compute_schedule_finish_band(node, &c->cluster[0], 0); - - ctx = isl_schedule_node_get_ctx(node); - - filters = extract_sccs(ctx, graph); - node = isl_schedule_node_insert_sequence(node, filters); - - for (i = 0; i < graph->scc; ++i) { - int j = c->scc_cluster[i]; - node = isl_schedule_node_child(node, i); - node = isl_schedule_node_child(node, 0); - node = compute_schedule_finish_band(node, &c->cluster[j], 0); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); - } - - return node; -} - -/* Compute a schedule for a connected dependence graph by first considering - * each strongly connected component (SCC) in the graph separately and then - * incrementally combining them into clusters. - * Return the updated schedule node. - * - * Initially, each cluster consists of a single SCC, each with its - * own band schedule. The algorithm then tries to merge pairs - * of clusters along a proximity edge until no more suitable - * proximity edges can be found. During this merging, the schedule - * is maintained in the individual SCCs. - * After the merging is completed, the full resulting clusters - * are extracted and in finish_bands_clustering, - * compute_schedule_finish_band is called on each of them to integrate - * the band into "node" and to continue the computation. - * - * compute_weights initializes the weights that are used by find_proximity. - */ -static __isl_give isl_schedule_node *compute_schedule_wcc_clustering( - __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) -{ - isl_ctx *ctx; - struct isl_clustering c; - int i; - - ctx = isl_schedule_node_get_ctx(node); - - if (clustering_init(ctx, &c, graph) < 0) - goto error; - - if (compute_weights(graph, &c) < 0) - goto error; - - for (;;) { - i = find_proximity(graph, &c); - if (i < 0) - goto error; - if (i >= graph->n_edge) - break; - if (merge_clusters_along_edge(ctx, graph, i, &c) < 0) - goto error; - } - - if (extract_clusters(ctx, graph, &c) < 0) - goto error; - - node = finish_bands_clustering(node, graph, &c); - - clustering_free(ctx, &c); - return node; -error: - clustering_free(ctx, &c); - return isl_schedule_node_free(node); + return isl_schedule_node_compute_finish_band(node, graph, 1); } /* Compute a schedule for a connected dependence graph and return @@ -7469,12 +5737,12 @@ error: * as many validity dependences as possible. When all validity dependences * are satisfied we extend the schedule to a full-dimensional schedule. * - * Call compute_schedule_wcc_whole or compute_schedule_wcc_clustering + * Call compute_schedule_wcc_whole or isl_schedule_node_compute_wcc_clustering * depending on whether the user has selected the option to try and * compute a schedule for the entire (weakly connected) component first. * If there is only a single strongly connected component (SCC), then * there is no point in trying to combine SCCs - * in compute_schedule_wcc_clustering, so compute_schedule_wcc_whole + * in isl_schedule_node_compute_wcc_clustering, so compute_schedule_wcc_whole * is called instead. */ static __isl_give isl_schedule_node *compute_schedule_wcc( @@ -7489,7 +5757,7 @@ static __isl_give isl_schedule_node *compute_schedule_wcc( if (detect_sccs(ctx, graph) < 0) return isl_schedule_node_free(node); - if (compute_maxvar(graph) < 0) + if (isl_sched_graph_compute_maxvar(graph) < 0) return isl_schedule_node_free(node); if (need_feautrier_step(ctx, graph)) @@ -7498,7 +5766,7 @@ static __isl_give isl_schedule_node *compute_schedule_wcc( if (graph->scc <= 1 || isl_options_get_schedule_whole_component(ctx)) return compute_schedule_wcc_whole(node, graph); else - return compute_schedule_wcc_clustering(node, graph); + return isl_schedule_node_compute_wcc_clustering(node, graph); } /* Compute a schedule for each group of nodes identified by node->scc @@ -7531,27 +5799,26 @@ static __isl_give isl_schedule_node *compute_component_schedule( return NULL; if (graph->weak && graph->scc == graph->n) { - if (compute_maxvar(graph) < 0) + if (isl_sched_graph_compute_maxvar(graph) < 0) return isl_schedule_node_free(node); if (graph->n_row >= graph->maxvar) return node; } ctx = isl_schedule_node_get_ctx(node); - filters = extract_sccs(ctx, graph); + filters = isl_sched_graph_extract_sccs(ctx, graph); if (graph->weak) node = isl_schedule_node_insert_set(node, filters); else node = isl_schedule_node_insert_sequence(node, filters); for (component = 0; component < graph->scc; ++component) { - node = isl_schedule_node_child(node, component); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, component, 0); node = compute_sub_schedule(node, ctx, graph, - &node_scc_exactly, - &edge_scc_exactly, component, wcc); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); + &isl_sched_node_scc_exactly, + &isl_sched_edge_scc_exactly, + component, wcc); + node = isl_schedule_node_grandparent(node); } return node; @@ -7624,7 +5891,7 @@ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( return isl_schedule_from_domain(domain); } - if (n < 0 || graph_init(&graph, sc) < 0) + if (n < 0 || isl_sched_graph_init(&graph, sc) < 0) domain = isl_union_set_free(domain); node = isl_schedule_node_from_domain(domain); @@ -7634,7 +5901,7 @@ __isl_give isl_schedule *isl_schedule_constraints_compute_schedule( sched = isl_schedule_node_get_schedule(node); isl_schedule_node_free(node); - graph_free(ctx, &graph); + isl_sched_graph_free(ctx, &graph); isl_schedule_constraints_free(sc); return sched; diff --git a/polly/lib/External/isl/isl_scheduler.h b/polly/lib/External/isl/isl_scheduler.h new file mode 100644 index 0000000..d5d68e4 --- /dev/null +++ b/polly/lib/External/isl/isl_scheduler.h @@ -0,0 +1,289 @@ +#ifndef ISL_SCHEDULER_H +#define ISL_SCHEDULER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isl_schedule_constraints.h" +#include "isl_tab.h" + +/* Internal information about a node that is used during the construction + * of a schedule. + * space represents the original space in which the domain lives; + * that is, the space is not affected by compression + * sched is a matrix representation of the schedule being constructed + * for this node; if compressed is set, then this schedule is + * defined over the compressed domain space + * sched_map is an isl_map representation of the same (partial) schedule + * sched_map may be NULL; if compressed is set, then this map + * is defined over the uncompressed domain space + * rank is the number of linearly independent rows in the linear part + * of sched + * the rows of "vmap" represent a change of basis for the node + * variables; the first rank rows span the linear part of + * the schedule rows; the remaining rows are linearly independent + * the rows of "indep" represent linear combinations of the schedule + * coefficients that are non-zero when the schedule coefficients are + * linearly independent of previously computed schedule rows. + * start is the first variable in the LP problem in the sequences that + * represents the schedule coefficients of this node + * nvar is the dimension of the (compressed) domain + * nparam is the number of parameters or 0 if we are not constructing + * a parametric schedule + * + * If compressed is set, then hull represents the constraints + * that were used to derive the compression, while compress and + * decompress map the original space to the compressed space and + * vice versa. + * + * scc is the index of SCC (or WCC) this node belongs to + * + * "cluster" is only used inside extract_clusters and identifies + * the cluster of SCCs that the node belongs to. + * + * 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 + * dependence distances are zero. + * + * If the schedule_treat_coalescing option is set, then + * "sizes" contains the sizes of the (compressed) instance set + * in each direction. If there is no fixed size in a given direction, + * then the corresponding size value is set to infinity. + * If the schedule_treat_coalescing option or the schedule_max_coefficient + * option is set, then "max" contains the maximal values for + * schedule coefficients of the (compressed) variables. If no bound + * needs to be imposed on a particular variable, then the corresponding + * value is negative. + * If not NULL, then "bounds" contains a non-parametric set + * in the compressed space that is bounded by the size in each direction. + */ +struct isl_sched_node { + isl_space *space; + int compressed; + isl_set *hull; + isl_multi_aff *compress; + isl_pw_multi_aff *decompress; + isl_mat *sched; + isl_map *sched_map; + int rank; + isl_mat *indep; + isl_mat *vmap; + int start; + int nvar; + int nparam; + + int scc; + int cluster; + + int *coincident; + + isl_multi_val *sizes; + isl_basic_set *bounds; + isl_vec *max; +}; + +int isl_sched_node_scc_exactly(struct isl_sched_node *node, int scc); + +isl_stat isl_sched_node_update_vmap(struct isl_sched_node *node); +__isl_give isl_multi_aff *isl_sched_node_extract_partial_schedule_multi_aff( + struct isl_sched_node *node, int first, int n); + +/* 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 + * + * map is the dependence relation, with i -> j in the map if j depends on i + * tagged_condition and tagged_validity contain the union of all tagged + * condition or conditional validity dependence relations that + * specialize the dependence relation "map"; that is, + * if (i -> a) -> (j -> b) is an element of "tagged_condition" + * or "tagged_validity", then i -> j is an element of "map". + * If these fields are NULL, then they represent the empty relation. + * src is the source node + * dst is the sink node + * + * types is a bit vector containing the types of this edge. + * validity is set if the edge is used to ensure correctness + * coincidence is used to enforce zero dependence distances + * proximity is set if the edge is used to minimize dependence distances + * condition is set if the edge represents a condition + * for a conditional validity schedule constraint + * local can only be set for condition edges and indicates that + * the dependence distance over the edge should be zero + * conditional_validity is set if the edge is used to conditionally + * ensure correctness + * + * For validity edges, start and end mark the sequence of inequality + * constraints in the LP problem that encode the validity constraint + * corresponding to this edge. + * + * During clustering, an edge may be marked "no_merge" if it should + * not be used to merge clusters. + * The weight is also only used during clustering and it is + * an indication of how many schedule dimensions on either side + * of the schedule constraints can be aligned. + * If the weight is negative, then this means that this edge was postponed + * by has_bounded_distances or any_no_merge. The original weight can + * be retrieved by adding 1 + graph->max_weight, with "graph" + * the graph containing this edge. + */ +struct isl_sched_edge { + isl_map *map; + isl_union_map *tagged_condition; + isl_union_map *tagged_validity; + + struct isl_sched_node *src; + struct isl_sched_node *dst; + + unsigned types; + + int start; + int end; + + int no_merge; + int weight; +}; + +int isl_sched_edge_has_type(struct isl_sched_edge *edge, + enum isl_edge_type type); +int isl_sched_edge_is_condition(struct isl_sched_edge *edge); +int isl_sched_edge_is_conditional_validity(struct isl_sched_edge *edge); +int isl_sched_edge_scc_exactly(struct isl_sched_edge *edge, int scc); +int isl_sched_edge_is_proximity(struct isl_sched_edge *edge); + +/* Internal information about the dependence graph used during + * the construction of the schedule. + * + * intra_hmap is a cache, mapping dependence relations to their dual, + * for dependences from a node to itself, possibly without + * coefficients for the parameters + * intra_hmap_param is a cache, mapping dependence relations to their dual, + * for dependences from a node to itself, including coefficients + * for the parameters + * inter_hmap is a cache, mapping dependence relations to their dual, + * for dependences between distinct nodes + * if compression is involved then the key for these maps + * is the original, uncompressed dependence relation, while + * the value is the dual of the compressed dependence relation. + * + * n is the number of nodes + * node is the list of nodes + * maxvar is the maximal number of variables over all nodes + * max_row is the allocated number of rows in the schedule + * 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 + * band_start is the starting row in the node schedules of the current band + * root is set to the original dependence graph from which this graph + * is derived through splitting. If this graph is not the result of + * splitting, then the root field points to the graph itself. + * + * sorted contains a list of node indices sorted according to the + * SCC to which a node belongs + * + * n_edge is the number of edges + * edge is the list of edges + * max_edge contains the maximal number of edges of each type; + * in particular, it contains the number of edges in the inital graph. + * edge_table contains pointers into the edge array, hashed on the source + * and sink spaces; there is one such table for each type; + * a given edge may be referenced from more than one table + * if the corresponding relation appears in more than one of the + * sets of dependences; however, for each type there is only + * a single edge between a given pair of source and sink space + * in the entire graph + * + * node_table contains pointers into the node array, hashed on the space tuples + * + * region contains a list of variable sequences that should be non-trivial + * + * lp contains the (I)LP problem used to obtain new schedule rows + * + * src_scc and dst_scc are the source and sink SCCs of an edge with + * conflicting constraints + * + * scc represents the number of components + * weak is set if the components are weakly connected + * + * max_weight is used during clustering and represents the maximal + * weight of the relevant proximity edges. + */ +struct isl_sched_graph { + isl_map_to_basic_set *intra_hmap; + isl_map_to_basic_set *intra_hmap_param; + isl_map_to_basic_set *inter_hmap; + + struct isl_sched_node *node; + int n; + int maxvar; + int max_row; + int n_row; + + int *sorted; + + int n_total_row; + int band_start; + + struct isl_sched_graph *root; + + struct isl_sched_edge *edge; + int n_edge; + int max_edge[isl_edge_last + 1]; + struct isl_hash_table *edge_table[isl_edge_last + 1]; + + struct isl_hash_table *node_table; + struct isl_trivial_region *region; + + isl_basic_set *lp; + + int src_scc; + int dst_scc; + + int scc; + int weak; + + int max_weight; +}; + +isl_stat isl_sched_graph_init(struct isl_sched_graph *graph, + __isl_keep isl_schedule_constraints *sc); +void isl_sched_graph_free(isl_ctx *ctx, struct isl_sched_graph *graph); + +int isl_sched_graph_is_node(struct isl_sched_graph *graph, + struct isl_sched_node *node); +isl_bool isl_sched_graph_has_validity_edge(struct isl_sched_graph *graph, + struct isl_sched_node *src, struct isl_sched_node *dst); + +struct isl_sched_node *isl_sched_graph_find_node(isl_ctx *ctx, + struct isl_sched_graph *graph, __isl_keep isl_space *space); + +isl_stat isl_sched_graph_detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, + isl_bool (*follows)(int i, int j, void *user)); + +__isl_give isl_union_set *isl_sched_graph_extract_scc(isl_ctx *ctx, + struct isl_sched_graph *graph, int scc); +__isl_give isl_union_set_list *isl_sched_graph_extract_sccs(isl_ctx *ctx, + struct isl_sched_graph *graph); +isl_stat isl_sched_graph_extract_sub_graph(isl_ctx *ctx, + struct isl_sched_graph *graph, + int (*node_pred)(struct isl_sched_node *node, int data), + int (*edge_pred)(struct isl_sched_edge *edge, int data), + int data, struct isl_sched_graph *sub); +isl_stat isl_sched_graph_compute_maxvar(struct isl_sched_graph *graph); +isl_stat isl_schedule_node_compute_wcc_band(isl_ctx *ctx, + struct isl_sched_graph *graph); +__isl_give isl_schedule_node *isl_schedule_node_compute_finish_band( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + int initialized); + +#endif diff --git a/polly/lib/External/isl/isl_scheduler_clustering.c b/polly/lib/External/isl/isl_scheduler_clustering.c new file mode 100644 index 0000000..c2e91c9 --- /dev/null +++ b/polly/lib/External/isl/isl_scheduler_clustering.c @@ -0,0 +1,1565 @@ +/* + * Copyright 2015 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege + */ + +#include "isl_map_private.h" + +#include +#include +#include + +#include "isl_mat_private.h" +#include "isl_scheduler_clustering.h" +#include "isl_scheduler_scc.h" +#include "isl_seq.h" +#include "isl_tarjan.h" + +/* Initialize the clustering data structure "c" from "graph". + * + * In particular, allocate memory, extract the SCCs from "graph" + * into c->scc, initialize scc_cluster and construct + * a band of schedule rows for each SCC. + * Within each SCC, there is only one SCC by definition. + * Each SCC initially belongs to a cluster containing only that SCC. + */ +static isl_stat clustering_init(isl_ctx *ctx, struct isl_clustering *c, + struct isl_sched_graph *graph) +{ + int i; + + c->n = graph->scc; + c->scc = isl_calloc_array(ctx, struct isl_sched_graph, c->n); + c->cluster = isl_calloc_array(ctx, struct isl_sched_graph, c->n); + c->scc_cluster = isl_calloc_array(ctx, int, c->n); + c->scc_node = isl_calloc_array(ctx, int, c->n); + c->scc_in_merge = isl_calloc_array(ctx, int, c->n); + if (!c->scc || !c->cluster || + !c->scc_cluster || !c->scc_node || !c->scc_in_merge) + return isl_stat_error; + + for (i = 0; i < c->n; ++i) { + if (isl_sched_graph_extract_sub_graph(ctx, graph, + &isl_sched_node_scc_exactly, + &isl_sched_edge_scc_exactly, + i, &c->scc[i]) < 0) + return isl_stat_error; + c->scc[i].scc = 1; + if (isl_sched_graph_compute_maxvar(&c->scc[i]) < 0) + return isl_stat_error; + if (isl_schedule_node_compute_wcc_band(ctx, &c->scc[i]) < 0) + return isl_stat_error; + c->scc_cluster[i] = i; + } + + return isl_stat_ok; +} + +/* Free all memory allocated for "c". + */ +static void clustering_free(isl_ctx *ctx, struct isl_clustering *c) +{ + int i; + + if (c->scc) + for (i = 0; i < c->n; ++i) + isl_sched_graph_free(ctx, &c->scc[i]); + free(c->scc); + if (c->cluster) + for (i = 0; i < c->n; ++i) + isl_sched_graph_free(ctx, &c->cluster[i]); + free(c->cluster); + free(c->scc_cluster); + free(c->scc_node); + free(c->scc_in_merge); +} + +/* Should we refrain from merging the cluster in "graph" with + * any other cluster? + * In particular, is its current schedule band empty and incomplete. + */ +static int bad_cluster(struct isl_sched_graph *graph) +{ + return graph->n_row < graph->maxvar && + graph->n_total_row == graph->band_start; +} + +/* Is "edge" a proximity edge with a non-empty dependence relation? + */ +static isl_bool is_non_empty_proximity(struct isl_sched_edge *edge) +{ + if (!isl_sched_edge_is_proximity(edge)) + return isl_bool_false; + return isl_bool_not(isl_map_plain_is_empty(edge->map)); +} + +/* Return the index of an edge in "graph" that can be used to merge + * two clusters in "c". + * Return graph->n_edge if no such edge can be found. + * Return -1 on error. + * + * In particular, return a proximity edge between two clusters + * that is not marked "no_merge" and such that neither of the + * two clusters has an incomplete, empty band. + * + * If there are multiple such edges, then try and find the most + * appropriate edge to use for merging. In particular, pick the edge + * with the greatest weight. If there are multiple of those, + * then pick one with the shortest distance between + * the two cluster representatives. + */ +static int find_proximity(struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i, best = graph->n_edge, best_dist, best_weight; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + int dist, weight; + isl_bool prox; + + prox = is_non_empty_proximity(edge); + if (prox < 0) + return -1; + if (!prox) + continue; + if (edge->no_merge) + continue; + if (bad_cluster(&c->scc[edge->src->scc]) || + bad_cluster(&c->scc[edge->dst->scc])) + continue; + dist = c->scc_cluster[edge->dst->scc] - + c->scc_cluster[edge->src->scc]; + if (dist == 0) + continue; + weight = edge->weight; + if (best < graph->n_edge) { + if (best_weight > weight) + continue; + if (best_weight == weight && best_dist <= dist) + continue; + } + best = i; + best_dist = dist; + best_weight = weight; + } + + return best; +} + +/* Internal data structure used in mark_merge_sccs. + * + * "graph" is the dependence graph in which a strongly connected + * component is constructed. + * "scc_cluster" maps each SCC index to the cluster to which it belongs. + * "src" and "dst" are the indices of the nodes that are being merged. + */ +struct isl_mark_merge_sccs_data { + struct isl_sched_graph *graph; + int *scc_cluster; + int src; + int dst; +}; + +/* Check whether the cluster containing node "i" depends on the cluster + * containing node "j". If "i" and "j" belong to the same cluster, + * then they are taken to depend on each other to ensure that + * the resulting strongly connected component consists of complete + * clusters. Furthermore, if "i" and "j" are the two nodes that + * are being merged, then they are taken to depend on each other as well. + * Otherwise, check if there is a (conditional) validity dependence + * from node[j] to node[i], forcing node[i] to follow node[j]. + */ +static isl_bool cluster_follows(int i, int j, void *user) +{ + struct isl_mark_merge_sccs_data *data = user; + struct isl_sched_graph *graph = data->graph; + int *scc_cluster = data->scc_cluster; + + if (data->src == i && data->dst == j) + return isl_bool_true; + if (data->src == j && data->dst == i) + return isl_bool_true; + if (scc_cluster[graph->node[i].scc] == scc_cluster[graph->node[j].scc]) + return isl_bool_true; + + return isl_sched_graph_has_validity_edge(graph, &graph->node[j], + &graph->node[i]); +} + +/* Mark all SCCs that belong to either of the two clusters in "c" + * connected by the edge in "graph" with index "edge", or to any + * of the intermediate clusters. + * The marking is recorded in c->scc_in_merge. + * + * The given edge has been selected for merging two clusters, + * meaning that there is at least a proximity edge between the two nodes. + * However, there may also be (indirect) validity dependences + * between the two nodes. When merging the two clusters, all clusters + * containing one or more of the intermediate nodes along the + * indirect validity dependences need to be merged in as well. + * + * First collect all such nodes by computing the strongly connected + * component (SCC) containing the two nodes connected by the edge, where + * the two nodes are considered to depend on each other to make + * sure they end up in the same SCC. Similarly, each node is considered + * to depend on every other node in the same cluster to ensure + * that the SCC consists of complete clusters. + * + * Then the original SCCs that contain any of these nodes are marked + * in c->scc_in_merge. + */ +static isl_stat mark_merge_sccs(isl_ctx *ctx, struct isl_sched_graph *graph, + int edge, struct isl_clustering *c) +{ + struct isl_mark_merge_sccs_data data; + struct isl_tarjan_graph *g; + int i; + + for (i = 0; i < c->n; ++i) + c->scc_in_merge[i] = 0; + + data.graph = graph; + data.scc_cluster = c->scc_cluster; + data.src = graph->edge[edge].src - graph->node; + data.dst = graph->edge[edge].dst - graph->node; + + g = isl_tarjan_graph_component(ctx, graph->n, data.dst, + &cluster_follows, &data); + if (!g) + goto error; + + i = g->op; + if (i < 3) + isl_die(ctx, isl_error_internal, + "expecting at least two nodes in component", + goto error); + if (g->order[--i] != -1) + isl_die(ctx, isl_error_internal, + "expecting end of component marker", goto error); + + for (--i; i >= 0 && g->order[i] != -1; --i) { + int scc = graph->node[g->order[i]].scc; + c->scc_in_merge[scc] = 1; + } + + isl_tarjan_graph_free(g); + return isl_stat_ok; +error: + isl_tarjan_graph_free(g); + return isl_stat_error; +} + +/* Construct the identifier "cluster_i". + */ +static __isl_give isl_id *cluster_id(isl_ctx *ctx, int i) +{ + char name[40]; + + snprintf(name, sizeof(name), "cluster_%d", i); + return isl_id_alloc(ctx, name, NULL); +} + +/* Construct the space of the cluster with index "i" containing + * the strongly connected component "scc". + * + * In particular, construct a space called cluster_i with dimension equal + * to the number of schedule rows in the current band of "scc". + */ +static __isl_give isl_space *cluster_space(struct isl_sched_graph *scc, int i) +{ + int nvar; + isl_space *space; + isl_id *id; + + nvar = scc->n_total_row - scc->band_start; + space = isl_space_copy(scc->node[0].space); + space = isl_space_params(space); + space = isl_space_set_from_params(space); + space = isl_space_add_dims(space, isl_dim_set, nvar); + id = cluster_id(isl_space_get_ctx(space), i); + space = isl_space_set_tuple_id(space, isl_dim_set, id); + + return space; +} + +/* Collect the domain of the graph for merging clusters. + * + * In particular, for each cluster with first SCC "i", construct + * a set in the space called cluster_i with dimension equal + * to the number of schedule rows in the current band of the cluster. + */ +static __isl_give isl_union_set *collect_domain(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i; + isl_space *space; + isl_union_set *domain; + + space = isl_space_params_alloc(ctx, 0); + domain = isl_union_set_empty(space); + + for (i = 0; i < graph->scc; ++i) { + isl_space *space; + + if (!c->scc_in_merge[i]) + continue; + if (c->scc_cluster[i] != i) + continue; + space = cluster_space(&c->scc[i], i); + domain = isl_union_set_add_set(domain, isl_set_universe(space)); + } + + return domain; +} + +/* Construct a map from the original instances to the corresponding + * cluster instance in the current bands of the clusters in "c". + */ +static __isl_give isl_union_map *collect_cluster_map(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i, j; + isl_space *space; + isl_union_map *cluster_map; + + space = isl_space_params_alloc(ctx, 0); + cluster_map = isl_union_map_empty(space); + for (i = 0; i < graph->scc; ++i) { + int start, n; + isl_id *id; + + if (!c->scc_in_merge[i]) + continue; + + id = cluster_id(ctx, c->scc_cluster[i]); + start = c->scc[i].band_start; + n = c->scc[i].n_total_row - start; + for (j = 0; j < c->scc[i].n; ++j) { + isl_multi_aff *ma; + isl_map *map; + struct isl_sched_node *node = &c->scc[i].node[j]; + + ma = isl_sched_node_extract_partial_schedule_multi_aff( + node, start, n); + ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, + isl_id_copy(id)); + map = isl_map_from_multi_aff(ma); + cluster_map = isl_union_map_add_map(cluster_map, map); + } + isl_id_free(id); + } + + return cluster_map; +} + +/* Add "umap" to the schedule constraints "sc" of all types of "edge" + * that are not isl_edge_condition or isl_edge_conditional_validity. + */ +static __isl_give isl_schedule_constraints *add_non_conditional_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, + __isl_take isl_schedule_constraints *sc) +{ + enum isl_edge_type t; + + if (!sc) + return NULL; + + for (t = isl_edge_first; t <= isl_edge_last; ++t) { + if (t == isl_edge_condition || + t == isl_edge_conditional_validity) + continue; + if (!isl_sched_edge_has_type(edge, t)) + continue; + sc = isl_schedule_constraints_add(sc, t, + isl_union_map_copy(umap)); + } + + return sc; +} + +/* Add schedule constraints of types isl_edge_condition and + * isl_edge_conditional_validity to "sc" by applying "umap" to + * the domains of the wrapped relations in domain and range + * of the corresponding tagged constraints of "edge". + */ +static __isl_give isl_schedule_constraints *add_conditional_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *umap, + __isl_take isl_schedule_constraints *sc) +{ + enum isl_edge_type t; + isl_union_map *tagged; + + for (t = isl_edge_condition; t <= isl_edge_conditional_validity; ++t) { + if (!isl_sched_edge_has_type(edge, t)) + continue; + if (t == isl_edge_condition) + tagged = isl_union_map_copy(edge->tagged_condition); + else + tagged = isl_union_map_copy(edge->tagged_validity); + tagged = isl_union_map_zip(tagged); + tagged = isl_union_map_apply_domain(tagged, + isl_union_map_copy(umap)); + tagged = isl_union_map_zip(tagged); + sc = isl_schedule_constraints_add(sc, t, tagged); + if (!sc) + return NULL; + } + + return sc; +} + +/* Given a mapping "cluster_map" from the original instances to + * the cluster instances, add schedule constraints on the clusters + * to "sc" corresponding to the original constraints represented by "edge". + * + * For non-tagged dependence constraints, the cluster constraints + * are obtained by applying "cluster_map" to the edge->map. + * + * For tagged dependence constraints, "cluster_map" needs to be applied + * to the domains of the wrapped relations in domain and range + * of the tagged dependence constraints. Pick out the mappings + * from these domains from "cluster_map" and construct their product. + * This mapping can then be applied to the pair of domains. + */ +static __isl_give isl_schedule_constraints *collect_edge_constraints( + struct isl_sched_edge *edge, __isl_keep isl_union_map *cluster_map, + __isl_take isl_schedule_constraints *sc) +{ + isl_union_map *umap; + isl_space *space; + isl_union_set *uset; + isl_union_map *umap1, *umap2; + + if (!sc) + return NULL; + + umap = isl_union_map_from_map(isl_map_copy(edge->map)); + umap = isl_union_map_apply_domain(umap, + isl_union_map_copy(cluster_map)); + umap = isl_union_map_apply_range(umap, + isl_union_map_copy(cluster_map)); + sc = add_non_conditional_constraints(edge, umap, sc); + isl_union_map_free(umap); + + if (!sc || + (!isl_sched_edge_is_condition(edge) && + !isl_sched_edge_is_conditional_validity(edge))) + return sc; + + space = isl_space_domain(isl_map_get_space(edge->map)); + uset = isl_union_set_from_set(isl_set_universe(space)); + umap1 = isl_union_map_copy(cluster_map); + umap1 = isl_union_map_intersect_domain(umap1, uset); + space = isl_space_range(isl_map_get_space(edge->map)); + uset = isl_union_set_from_set(isl_set_universe(space)); + umap2 = isl_union_map_copy(cluster_map); + umap2 = isl_union_map_intersect_domain(umap2, uset); + umap = isl_union_map_product(umap1, umap2); + + sc = add_conditional_constraints(edge, umap, sc); + + isl_union_map_free(umap); + return sc; +} + +/* Given a mapping "cluster_map" from the original instances to + * the cluster instances, add schedule constraints on the clusters + * to "sc" corresponding to all edges in "graph" between nodes that + * belong to SCCs that are marked for merging in "scc_in_merge". + */ +static __isl_give isl_schedule_constraints *collect_constraints( + struct isl_sched_graph *graph, int *scc_in_merge, + __isl_keep isl_union_map *cluster_map, + __isl_take isl_schedule_constraints *sc) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + + if (!scc_in_merge[edge->src->scc]) + continue; + if (!scc_in_merge[edge->dst->scc]) + continue; + sc = collect_edge_constraints(edge, cluster_map, sc); + } + + return sc; +} + +/* Construct a dependence graph for scheduling clusters with respect + * to each other and store the result in "merge_graph". + * In particular, the nodes of the graph correspond to the schedule + * dimensions of the current bands of those clusters that have been + * marked for merging in "c". + * + * First construct an isl_schedule_constraints object for this domain + * by transforming the edges in "graph" to the domain. + * Then initialize a dependence graph for scheduling from these + * constraints. + */ +static isl_stat init_merge_graph(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c, struct isl_sched_graph *merge_graph) +{ + isl_union_set *domain; + isl_union_map *cluster_map; + isl_schedule_constraints *sc; + isl_stat r; + + domain = collect_domain(ctx, graph, c); + sc = isl_schedule_constraints_on_domain(domain); + if (!sc) + return isl_stat_error; + cluster_map = collect_cluster_map(ctx, graph, c); + sc = collect_constraints(graph, c->scc_in_merge, cluster_map, sc); + isl_union_map_free(cluster_map); + + r = isl_sched_graph_init(merge_graph, sc); + + isl_schedule_constraints_free(sc); + + return r; +} + +/* Compute the maximal number of remaining schedule rows that still need + * to be computed for the nodes that belong to clusters with the maximal + * dimension for the current band (i.e., the band that is to be merged). + * Only clusters that are about to be merged are considered. + * "maxvar" is the maximal dimension for the current band. + * "c" contains information about the clusters. + * + * Return the maximal number of remaining schedule rows or + * isl_size_error on error. + */ +static isl_size compute_maxvar_max_slack(int maxvar, struct isl_clustering *c) +{ + int i, j; + int max_slack; + + max_slack = 0; + for (i = 0; i < c->n; ++i) { + int nvar; + struct isl_sched_graph *scc; + + if (!c->scc_in_merge[i]) + continue; + scc = &c->scc[i]; + nvar = scc->n_total_row - scc->band_start; + if (nvar != maxvar) + continue; + for (j = 0; j < scc->n; ++j) { + struct isl_sched_node *node = &scc->node[j]; + int slack; + + if (isl_sched_node_update_vmap(node) < 0) + return isl_size_error; + slack = node->nvar - node->rank; + if (slack > max_slack) + max_slack = slack; + } + } + + return max_slack; +} + +/* If there are any clusters where the dimension of the current band + * (i.e., the band that is to be merged) is smaller than "maxvar" and + * if there are any nodes in such a cluster where the number + * of remaining schedule rows that still need to be computed + * is greater than "max_slack", then return the smallest current band + * dimension of all these clusters. Otherwise return the original value + * of "maxvar". Return isl_size_error in case of any error. + * Only clusters that are about to be merged are considered. + * "c" contains information about the clusters. + */ +static isl_size limit_maxvar_to_slack(int maxvar, int max_slack, + struct isl_clustering *c) +{ + int i, j; + + for (i = 0; i < c->n; ++i) { + int nvar; + struct isl_sched_graph *scc; + + if (!c->scc_in_merge[i]) + continue; + scc = &c->scc[i]; + nvar = scc->n_total_row - scc->band_start; + if (nvar >= maxvar) + continue; + for (j = 0; j < scc->n; ++j) { + struct isl_sched_node *node = &scc->node[j]; + int slack; + + if (isl_sched_node_update_vmap(node) < 0) + return isl_size_error; + slack = node->nvar - node->rank; + if (slack > max_slack) { + maxvar = nvar; + break; + } + } + } + + return maxvar; +} + +/* Adjust merge_graph->maxvar based on the number of remaining schedule rows + * that still need to be computed. In particular, if there is a node + * in a cluster where the dimension of the current band is smaller + * than merge_graph->maxvar, but the number of remaining schedule rows + * is greater than that of any node in a cluster with the maximal + * dimension for the current band (i.e., merge_graph->maxvar), + * then adjust merge_graph->maxvar to the (smallest) current band dimension + * of those clusters. Without this adjustment, the total number of + * schedule dimensions would be increased, resulting in a skewed view + * of the number of coincident dimensions. + * "c" contains information about the clusters. + * + * If the maximize_band_depth option is set and merge_graph->maxvar is reduced, + * then there is no point in attempting any merge since it will be rejected + * anyway. Set merge_graph->maxvar to zero in such cases. + */ +static isl_stat adjust_maxvar_to_slack(isl_ctx *ctx, + struct isl_sched_graph *merge_graph, struct isl_clustering *c) +{ + isl_size max_slack, maxvar; + + max_slack = compute_maxvar_max_slack(merge_graph->maxvar, c); + if (max_slack < 0) + return isl_stat_error; + maxvar = limit_maxvar_to_slack(merge_graph->maxvar, max_slack, c); + if (maxvar < 0) + return isl_stat_error; + + if (maxvar < merge_graph->maxvar) { + if (isl_options_get_schedule_maximize_band_depth(ctx)) + merge_graph->maxvar = 0; + else + merge_graph->maxvar = maxvar; + } + + return isl_stat_ok; +} + +/* Return the number of coincident dimensions in the current band of "graph", + * where the nodes of "graph" are assumed to be scheduled by a single band. + */ +static int get_n_coincident(struct isl_sched_graph *graph) +{ + int i; + + for (i = graph->band_start; i < graph->n_total_row; ++i) + if (!graph->node[0].coincident[i]) + break; + + return i - graph->band_start; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph", given that + * coincidence should be maximized? + * + * If the number of coincident schedule dimensions in the merged band + * would be less than the maximal number of coincident schedule dimensions + * in any of the merged clusters, then the clusters should not be merged. + */ +static isl_bool ok_to_merge_coincident(struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + int n_coincident; + int max_coincident; + + max_coincident = 0; + for (i = 0; i < c->n; ++i) { + if (!c->scc_in_merge[i]) + continue; + n_coincident = get_n_coincident(&c->scc[i]); + if (n_coincident > max_coincident) + max_coincident = n_coincident; + } + + n_coincident = get_n_coincident(merge_graph); + + return isl_bool_ok(n_coincident >= max_coincident); +} + +/* Return the transformation on "node" expressed by the current (and only) + * band of "merge_graph" applied to the clusters in "c". + * + * First find the representation of "node" in its SCC in "c" and + * extract the transformation expressed by the current band. + * Then extract the transformation applied by "merge_graph" + * to the cluster to which this SCC belongs. + * Combine the two to obtain the complete transformation on the node. + * + * Note that the range of the first transformation is an anonymous space, + * while the domain of the second is named "cluster_X". The range + * of the former therefore needs to be adjusted before the two + * can be combined. + */ +static __isl_give isl_map *extract_node_transformation(isl_ctx *ctx, + struct isl_sched_node *node, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + struct isl_sched_node *scc_node, *cluster_node; + int start, n; + isl_id *id; + isl_space *space; + isl_multi_aff *ma, *ma2; + + scc_node = isl_sched_graph_find_node(ctx, &c->scc[node->scc], + node->space); + if (scc_node && !isl_sched_graph_is_node(&c->scc[node->scc], scc_node)) + isl_die(ctx, isl_error_internal, "unable to find node", + return NULL); + start = c->scc[node->scc].band_start; + n = c->scc[node->scc].n_total_row - start; + ma = isl_sched_node_extract_partial_schedule_multi_aff(scc_node, + start, n); + space = cluster_space(&c->scc[node->scc], c->scc_cluster[node->scc]); + cluster_node = isl_sched_graph_find_node(ctx, merge_graph, space); + if (cluster_node && !isl_sched_graph_is_node(merge_graph, cluster_node)) + isl_die(ctx, isl_error_internal, "unable to find cluster", + space = isl_space_free(space)); + id = isl_space_get_tuple_id(space, isl_dim_set); + ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, id); + isl_space_free(space); + n = merge_graph->n_total_row; + ma2 = isl_sched_node_extract_partial_schedule_multi_aff(cluster_node, + 0, n); + ma = isl_multi_aff_pullback_multi_aff(ma2, ma); + + return isl_map_from_multi_aff(ma); +} + +/* Give a set of distances "set", are they bounded by a small constant + * in direction "pos"? + * In practice, check if they are bounded by 2 by checking that there + * are no elements with a value greater than or equal to 3 or + * smaller than or equal to -3. + */ +static isl_bool distance_is_bounded(__isl_keep isl_set *set, int pos) +{ + isl_bool bounded; + isl_set *test; + + if (!set) + return isl_bool_error; + + test = isl_set_copy(set); + test = isl_set_lower_bound_si(test, isl_dim_set, pos, 3); + bounded = isl_set_is_empty(test); + isl_set_free(test); + + if (bounded < 0 || !bounded) + return bounded; + + test = isl_set_copy(set); + test = isl_set_upper_bound_si(test, isl_dim_set, pos, -3); + bounded = isl_set_is_empty(test); + isl_set_free(test); + + return bounded; +} + +/* Does the set "set" have a fixed (but possible parametric) value + * at dimension "pos"? + */ +static isl_bool has_single_value(__isl_keep isl_set *set, int pos) +{ + isl_size n; + isl_bool single; + + n = isl_set_dim(set, isl_dim_set); + if (n < 0) + return isl_bool_error; + set = isl_set_copy(set); + set = isl_set_project_out(set, isl_dim_set, pos + 1, n - (pos + 1)); + set = isl_set_project_out(set, isl_dim_set, 0, pos); + single = isl_set_is_singleton(set); + isl_set_free(set); + + return single; +} + +/* Does "map" have a fixed (but possible parametric) value + * at dimension "pos" of either its domain or its range? + */ +static isl_bool has_singular_src_or_dst(__isl_keep isl_map *map, int pos) +{ + isl_set *set; + isl_bool single; + + set = isl_map_domain(isl_map_copy(map)); + single = has_single_value(set, pos); + isl_set_free(set); + + if (single < 0 || single) + return single; + + set = isl_map_range(isl_map_copy(map)); + single = has_single_value(set, pos); + isl_set_free(set); + + return single; +} + +/* Does the edge "edge" from "graph" have bounded dependence distances + * in the merged graph "merge_graph" of a selection of clusters in "c"? + * + * Extract the complete transformations of the source and destination + * nodes of the edge, apply them to the edge constraints and + * compute the differences. Finally, check if these differences are bounded + * in each direction. + * + * If the dimension of the band is greater than the number of + * dimensions that can be expected to be optimized by the edge + * (based on its weight), then also allow the differences to be unbounded + * in the remaining dimensions, but only if either the source or + * the destination has a fixed value in that direction. + * This allows a statement that produces values that are used by + * several instances of another statement to be merged with that + * other statement. + * However, merging such clusters will introduce an inherently + * large proximity distance inside the merged cluster, meaning + * that proximity distances will no longer be optimized in + * subsequent merges. These merges are therefore only allowed + * after all other possible merges have been tried. + * The first time such a merge is encountered, the weight of the edge + * is replaced by a negative weight. The second time (i.e., after + * all merges over edges with a non-negative weight have been tried), + * the merge is allowed. + */ +static isl_bool has_bounded_distances(isl_ctx *ctx, struct isl_sched_edge *edge, + struct isl_sched_graph *graph, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i, n_slack; + isl_size n; + isl_bool bounded; + isl_map *map, *t; + isl_set *dist; + + map = isl_map_copy(edge->map); + t = extract_node_transformation(ctx, edge->src, c, merge_graph); + map = isl_map_apply_domain(map, t); + t = extract_node_transformation(ctx, edge->dst, c, merge_graph); + map = isl_map_apply_range(map, t); + dist = isl_map_deltas(isl_map_copy(map)); + + bounded = isl_bool_true; + n = isl_set_dim(dist, isl_dim_set); + if (n < 0) + goto error; + n_slack = n - edge->weight; + if (edge->weight < 0) + n_slack -= graph->max_weight + 1; + for (i = 0; i < n; ++i) { + isl_bool bounded_i, singular_i; + + bounded_i = distance_is_bounded(dist, i); + if (bounded_i < 0) + goto error; + if (bounded_i) + continue; + if (edge->weight >= 0) + bounded = isl_bool_false; + n_slack--; + if (n_slack < 0) + break; + singular_i = has_singular_src_or_dst(map, i); + if (singular_i < 0) + goto error; + if (singular_i) + continue; + bounded = isl_bool_false; + break; + } + if (!bounded && i >= n && edge->weight >= 0) + edge->weight -= graph->max_weight + 1; + isl_map_free(map); + isl_set_free(dist); + + return bounded; +error: + isl_map_free(map); + isl_set_free(dist); + return isl_bool_error; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph"? + * "graph" is the original dependence graph, while "c" records + * which SCCs are involved in the latest merge. + * + * In particular, is there at least one proximity constraint + * that is optimized by the merge? + * + * A proximity constraint is considered to be optimized + * if the dependence distances are small. + */ +static isl_bool ok_to_merge_proximity(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + isl_bool bounded; + + if (!isl_sched_edge_is_proximity(edge)) + continue; + if (!c->scc_in_merge[edge->src->scc]) + continue; + if (!c->scc_in_merge[edge->dst->scc]) + continue; + if (c->scc_cluster[edge->dst->scc] == + c->scc_cluster[edge->src->scc]) + continue; + bounded = has_bounded_distances(ctx, edge, graph, c, + merge_graph); + if (bounded < 0 || bounded) + return bounded; + } + + return isl_bool_false; +} + +/* Should the clusters be merged based on the cluster schedule + * in the current (and only) band of "merge_graph"? + * "graph" is the original dependence graph, while "c" records + * which SCCs are involved in the latest merge. + * + * If the current band is empty, then the clusters should not be merged. + * + * If the band depth should be maximized and the merge schedule + * is incomplete (meaning that the dimension of some of the schedule + * bands in the original schedule will be reduced), then the clusters + * should not be merged. + * + * If the schedule_maximize_coincidence option is set, then check that + * the number of coincident schedule dimensions is not reduced. + * + * Finally, only allow the merge if at least one proximity + * constraint is optimized. + */ +static isl_bool ok_to_merge(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c, struct isl_sched_graph *merge_graph) +{ + if (merge_graph->n_total_row == merge_graph->band_start) + return isl_bool_false; + + if (isl_options_get_schedule_maximize_band_depth(ctx) && + merge_graph->n_total_row < merge_graph->maxvar) + return isl_bool_false; + + if (isl_options_get_schedule_maximize_coincidence(ctx)) { + isl_bool ok; + + ok = ok_to_merge_coincident(c, merge_graph); + if (ok < 0 || !ok) + return ok; + } + + return ok_to_merge_proximity(ctx, graph, c, merge_graph); +} + +/* Apply the schedule in "t_node" to the "n" rows starting at "first" + * of the schedule in "node" and return the result. + * + * That is, essentially compute + * + * T * N(first:first+n-1) + * + * taking into account the constant term and the parameter coefficients + * in "t_node". + */ +static __isl_give isl_mat *node_transformation(isl_ctx *ctx, + struct isl_sched_node *t_node, struct isl_sched_node *node, + int first, int n) +{ + int i, j; + isl_mat *t; + isl_size n_row, n_col; + int n_param, n_var; + + n_param = node->nparam; + n_var = node->nvar; + n_row = isl_mat_rows(t_node->sched); + n_col = isl_mat_cols(node->sched); + if (n_row < 0 || n_col < 0) + return NULL; + t = isl_mat_alloc(ctx, n_row, n_col); + if (!t) + return NULL; + for (i = 0; i < n_row; ++i) { + isl_seq_cpy(t->row[i], t_node->sched->row[i], 1 + n_param); + isl_seq_clr(t->row[i] + 1 + n_param, n_var); + for (j = 0; j < n; ++j) + isl_seq_addmul(t->row[i], + t_node->sched->row[i][1 + n_param + j], + node->sched->row[first + j], + 1 + n_param + n_var); + } + return t; +} + +/* Apply the cluster schedule in "t_node" to the current band + * schedule of the nodes in "graph". + * + * In particular, replace the rows starting at band_start + * by the result of applying the cluster schedule in "t_node" + * to the original rows. + * + * The coincidence of the schedule is determined by the coincidence + * of the cluster schedule. + */ +static isl_stat transform(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_sched_node *t_node) +{ + int i, j; + isl_size n_new; + int start, n; + + start = graph->band_start; + n = graph->n_total_row - start; + + n_new = isl_mat_rows(t_node->sched); + if (n_new < 0) + return isl_stat_error; + for (i = 0; i < graph->n; ++i) { + struct isl_sched_node *node = &graph->node[i]; + isl_mat *t; + + t = node_transformation(ctx, t_node, node, start, n); + node->sched = isl_mat_drop_rows(node->sched, start, n); + node->sched = isl_mat_concat(node->sched, t); + node->sched_map = isl_map_free(node->sched_map); + if (!node->sched) + return isl_stat_error; + for (j = 0; j < n_new; ++j) + node->coincident[start + j] = t_node->coincident[j]; + } + graph->n_total_row -= n; + graph->n_row -= n; + graph->n_total_row += n_new; + graph->n_row += n_new; + + return isl_stat_ok; +} + +/* Merge the clusters marked for merging in "c" into a single + * cluster using the cluster schedule in the current band of "merge_graph". + * The representative SCC for the new cluster is the SCC with + * the smallest index. + * + * The current band schedule of each SCC in the new cluster is obtained + * by applying the schedule of the corresponding original cluster + * to the original band schedule. + * All SCCs in the new cluster have the same number of schedule rows. + */ +static isl_stat merge(isl_ctx *ctx, struct isl_clustering *c, + struct isl_sched_graph *merge_graph) +{ + int i; + int cluster = -1; + isl_space *space; + + for (i = 0; i < c->n; ++i) { + struct isl_sched_node *node; + + if (!c->scc_in_merge[i]) + continue; + if (cluster < 0) + cluster = i; + space = cluster_space(&c->scc[i], c->scc_cluster[i]); + node = isl_sched_graph_find_node(ctx, merge_graph, space); + isl_space_free(space); + if (!node) + return isl_stat_error; + if (!isl_sched_graph_is_node(merge_graph, node)) + isl_die(ctx, isl_error_internal, + "unable to find cluster", + return isl_stat_error); + if (transform(ctx, &c->scc[i], node) < 0) + return isl_stat_error; + c->scc_cluster[i] = cluster; + } + + return isl_stat_ok; +} + +/* Try and merge the clusters of SCCs marked in c->scc_in_merge + * by scheduling the current cluster bands with respect to each other. + * + * Construct a dependence graph with a space for each cluster and + * with the coordinates of each space corresponding to the schedule + * dimensions of the current band of that cluster. + * Construct a cluster schedule in this cluster dependence graph and + * apply it to the current cluster bands if it is applicable + * according to ok_to_merge. + * + * If the number of remaining schedule dimensions in a cluster + * with a non-maximal current schedule dimension is greater than + * the number of remaining schedule dimensions in clusters + * with a maximal current schedule dimension, then restrict + * the number of rows to be computed in the cluster schedule + * to the minimal such non-maximal current schedule dimension. + * Do this by adjusting merge_graph.maxvar. + * + * Return isl_bool_true if the clusters have effectively been merged + * into a single cluster. + * + * Note that since the standard scheduling algorithm minimizes the maximal + * distance over proximity constraints, the proximity constraints between + * the merged clusters may not be optimized any further than what is + * sufficient to bring the distances within the limits of the internal + * proximity constraints inside the individual clusters. + * It may therefore make sense to perform an additional translation step + * to bring the clusters closer to each other, while maintaining + * the linear part of the merging schedule found using the standard + * scheduling algorithm. + */ +static isl_bool try_merge(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + struct isl_sched_graph merge_graph = { 0 }; + isl_bool merged; + + if (init_merge_graph(ctx, graph, c, &merge_graph) < 0) + goto error; + + if (isl_sched_graph_compute_maxvar(&merge_graph) < 0) + goto error; + if (adjust_maxvar_to_slack(ctx, &merge_graph,c) < 0) + goto error; + if (isl_schedule_node_compute_wcc_band(ctx, &merge_graph) < 0) + goto error; + merged = ok_to_merge(ctx, graph, c, &merge_graph); + if (merged && merge(ctx, c, &merge_graph) < 0) + goto error; + + isl_sched_graph_free(ctx, &merge_graph); + return merged; +error: + isl_sched_graph_free(ctx, &merge_graph); + return isl_bool_error; +} + +/* Is there any edge marked "no_merge" between two SCCs that are + * about to be merged (i.e., that are set in "scc_in_merge")? + * "merge_edge" is the proximity edge along which the clusters of SCCs + * are going to be merged. + * + * If there is any edge between two SCCs with a negative weight, + * while the weight of "merge_edge" is non-negative, then this + * means that the edge was postponed. "merge_edge" should then + * also be postponed since merging along the edge with negative weight should + * be postponed until all edges with non-negative weight have been tried. + * Replace the weight of "merge_edge" by a negative weight as well and + * tell the caller not to attempt a merge. + */ +static int any_no_merge(struct isl_sched_graph *graph, int *scc_in_merge, + struct isl_sched_edge *merge_edge) +{ + int i; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + + if (!scc_in_merge[edge->src->scc]) + continue; + if (!scc_in_merge[edge->dst->scc]) + continue; + if (edge->no_merge) + return 1; + if (merge_edge->weight >= 0 && edge->weight < 0) { + merge_edge->weight -= graph->max_weight + 1; + return 1; + } + } + + return 0; +} + +/* Merge the two clusters in "c" connected by the edge in "graph" + * with index "edge" into a single cluster. + * If it turns out to be impossible to merge these two clusters, + * then mark the edge as "no_merge" such that it will not be + * considered again. + * + * First mark all SCCs that need to be merged. This includes the SCCs + * in the two clusters, but it may also include the SCCs + * of intermediate clusters. + * If there is already a no_merge edge between any pair of such SCCs, + * then simply mark the current edge as no_merge as well. + * Likewise, if any of those edges was postponed by has_bounded_distances, + * then postpone the current edge as well. + * Otherwise, try and merge the clusters and mark "edge" as "no_merge" + * if the clusters did not end up getting merged, unless the non-merge + * is due to the fact that the edge was postponed. This postponement + * can be recognized by a change in weight (from non-negative to negative). + */ +static isl_stat merge_clusters_along_edge(isl_ctx *ctx, + struct isl_sched_graph *graph, int edge, struct isl_clustering *c) +{ + isl_bool merged; + int edge_weight = graph->edge[edge].weight; + + if (mark_merge_sccs(ctx, graph, edge, c) < 0) + return isl_stat_error; + + if (any_no_merge(graph, c->scc_in_merge, &graph->edge[edge])) + merged = isl_bool_false; + else + merged = try_merge(ctx, graph, c); + if (merged < 0) + return isl_stat_error; + if (!merged && edge_weight == graph->edge[edge].weight) + graph->edge[edge].no_merge = 1; + + return isl_stat_ok; +} + +/* Does "node" belong to the cluster identified by "cluster"? + */ +static int node_cluster_exactly(struct isl_sched_node *node, int cluster) +{ + return node->cluster == cluster; +} + +/* Does "edge" connect two nodes belonging to the cluster + * identified by "cluster"? + */ +static int edge_cluster_exactly(struct isl_sched_edge *edge, int cluster) +{ + return edge->src->cluster == cluster && edge->dst->cluster == cluster; +} + +/* Swap the schedule of "node1" and "node2". + * Both nodes have been derived from the same node in a common parent graph. + * Since the "coincident" field is shared with that node + * in the parent graph, there is no need to also swap this field. + */ +static void swap_sched(struct isl_sched_node *node1, + struct isl_sched_node *node2) +{ + isl_mat *sched; + isl_map *sched_map; + + sched = node1->sched; + node1->sched = node2->sched; + node2->sched = sched; + + sched_map = node1->sched_map; + node1->sched_map = node2->sched_map; + node2->sched_map = sched_map; +} + +/* Copy the current band schedule from the SCCs that form the cluster + * with index "pos" to the actual cluster at position "pos". + * By construction, the index of the first SCC that belongs to the cluster + * is also "pos". + * + * The order of the nodes inside both the SCCs and the cluster + * is assumed to be same as the order in the original "graph". + * + * Since the SCC graphs will no longer be used after this function, + * the schedules are actually swapped rather than copied. + */ +static isl_stat copy_partial(struct isl_sched_graph *graph, + struct isl_clustering *c, int pos) +{ + int i, j; + + c->cluster[pos].n_total_row = c->scc[pos].n_total_row; + c->cluster[pos].n_row = c->scc[pos].n_row; + c->cluster[pos].maxvar = c->scc[pos].maxvar; + j = 0; + for (i = 0; i < graph->n; ++i) { + int k; + int s; + + if (graph->node[i].cluster != pos) + continue; + s = graph->node[i].scc; + k = c->scc_node[s]++; + swap_sched(&c->cluster[pos].node[j], &c->scc[s].node[k]); + if (c->scc[s].maxvar > c->cluster[pos].maxvar) + c->cluster[pos].maxvar = c->scc[s].maxvar; + ++j; + } + + return isl_stat_ok; +} + +/* Is there a (conditional) validity dependence from node[j] to node[i], + * forcing node[i] to follow node[j] or do the nodes belong to the same + * cluster? + */ +static isl_bool node_follows_strong_or_same_cluster(int i, int j, void *user) +{ + struct isl_sched_graph *graph = user; + + if (graph->node[i].cluster == graph->node[j].cluster) + return isl_bool_true; + return isl_sched_graph_has_validity_edge(graph, &graph->node[j], + &graph->node[i]); +} + +/* Extract the merged clusters of SCCs in "graph", sort them, and + * store them in c->clusters. Update c->scc_cluster accordingly. + * + * First keep track of the cluster containing the SCC to which a node + * belongs in the node itself. + * Then extract the clusters into c->clusters, copying the current + * band schedule from the SCCs that belong to the cluster. + * Do this only once per cluster. + * + * Finally, topologically sort the clusters and update c->scc_cluster + * to match the new scc numbering. While the SCCs were originally + * sorted already, some SCCs that depend on some other SCCs may + * have been merged with SCCs that appear before these other SCCs. + * A reordering may therefore be required. + */ +static isl_stat extract_clusters(isl_ctx *ctx, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + + for (i = 0; i < graph->n; ++i) + graph->node[i].cluster = c->scc_cluster[graph->node[i].scc]; + + for (i = 0; i < graph->scc; ++i) { + if (c->scc_cluster[i] != i) + continue; + if (isl_sched_graph_extract_sub_graph(ctx, graph, + &node_cluster_exactly, + &edge_cluster_exactly, i, &c->cluster[i]) < 0) + return isl_stat_error; + c->cluster[i].src_scc = -1; + c->cluster[i].dst_scc = -1; + if (copy_partial(graph, c, i) < 0) + return isl_stat_error; + } + + if (isl_sched_graph_detect_ccs(ctx, graph, + &node_follows_strong_or_same_cluster) < 0) + return isl_stat_error; + for (i = 0; i < graph->n; ++i) + c->scc_cluster[graph->node[i].scc] = graph->node[i].cluster; + + return isl_stat_ok; +} + +/* Compute weights on the proximity edges of "graph" that can + * be used by find_proximity to find the most appropriate + * proximity edge to use to merge two clusters in "c". + * The weights are also used by has_bounded_distances to determine + * whether the merge should be allowed. + * Store the maximum of the computed weights in graph->max_weight. + * + * The computed weight is a measure for the number of remaining schedule + * dimensions that can still be completely aligned. + * In particular, compute the number of equalities between + * input dimensions and output dimensions in the proximity constraints. + * The directions that are already handled by outer schedule bands + * are projected out prior to determining this number. + * + * Edges that will never be considered by find_proximity are ignored. + */ +static isl_stat compute_weights(struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + + graph->max_weight = 0; + + for (i = 0; i < graph->n_edge; ++i) { + struct isl_sched_edge *edge = &graph->edge[i]; + struct isl_sched_node *src = edge->src; + struct isl_sched_node *dst = edge->dst; + isl_basic_map *hull; + isl_bool prox; + isl_size n_in, n_out, n; + + prox = is_non_empty_proximity(edge); + if (prox < 0) + return isl_stat_error; + if (!prox) + continue; + if (bad_cluster(&c->scc[edge->src->scc]) || + bad_cluster(&c->scc[edge->dst->scc])) + continue; + if (c->scc_cluster[edge->dst->scc] == + c->scc_cluster[edge->src->scc]) + continue; + + hull = isl_map_affine_hull(isl_map_copy(edge->map)); + hull = isl_basic_map_transform_dims(hull, isl_dim_in, 0, + isl_mat_copy(src->vmap)); + hull = isl_basic_map_transform_dims(hull, isl_dim_out, 0, + isl_mat_copy(dst->vmap)); + hull = isl_basic_map_project_out(hull, + isl_dim_in, 0, src->rank); + hull = isl_basic_map_project_out(hull, + isl_dim_out, 0, dst->rank); + hull = isl_basic_map_remove_divs(hull); + n_in = isl_basic_map_dim(hull, isl_dim_in); + n_out = isl_basic_map_dim(hull, isl_dim_out); + if (n_in < 0 || n_out < 0) + hull = isl_basic_map_free(hull); + hull = isl_basic_map_drop_constraints_not_involving_dims(hull, + isl_dim_in, 0, n_in); + hull = isl_basic_map_drop_constraints_not_involving_dims(hull, + isl_dim_out, 0, n_out); + n = isl_basic_map_n_equality(hull); + isl_basic_map_free(hull); + if (n < 0) + return isl_stat_error; + edge->weight = n; + + if (edge->weight > graph->max_weight) + graph->max_weight = edge->weight; + } + + return isl_stat_ok; +} + +/* Call isl_schedule_node_compute_finish_band on each of the clusters in "c" and + * update "node" to arrange for them to be executed in an order + * possibly involving set nodes that generalizes the topological order + * determined by the scc fields of the nodes in "graph". + * + * Note that at this stage, there are graph->scc clusters and + * their positions in c->cluster are determined by the values + * of c->scc_cluster. + * + * Construct an isl_scc_graph and perform the decomposition + * using this graph. + */ +static __isl_give isl_schedule_node *finish_bands_decompose( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + isl_ctx *ctx; + struct isl_scc_graph *scc_graph; + + ctx = isl_schedule_node_get_ctx(node); + + scc_graph = isl_scc_graph_from_sched_graph(ctx, graph, c); + node = isl_scc_graph_decompose(scc_graph, node); + isl_scc_graph_free(scc_graph); + + return node; +} + +/* Call isl_schedule_node_compute_finish_band on each of the clusters in "c" + * in their topological order. This order is determined by the scc + * fields of the nodes in "graph". + * Combine the results in a sequence expressing the topological order. + * + * If there is only one cluster left, then there is no need to introduce + * a sequence node. Also, in this case, the cluster necessarily contains + * the SCC at position 0 in the original graph and is therefore also + * stored in the first cluster of "c". + * + * If there are more than two clusters left, then some subsets of the clusters + * may still be independent of each other. These could then still + * be reordered with respect to each other. Call finish_bands_decompose + * to try and construct an ordering involving set and sequence nodes + * that generalizes the topological order. + * Note that at the outermost level there can be no independent components + * because isl_schedule_node_compute_wcc_clustering is called + * on a (weakly) connected component. + */ +static __isl_give isl_schedule_node *finish_bands_clustering( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph, + struct isl_clustering *c) +{ + int i; + isl_ctx *ctx; + isl_union_set_list *filters; + + if (graph->scc == 1) + return isl_schedule_node_compute_finish_band(node, + &c->cluster[0], 0); + if (graph->scc > 2) + return finish_bands_decompose(node, graph, c); + + ctx = isl_schedule_node_get_ctx(node); + + filters = isl_sched_graph_extract_sccs(ctx, graph); + node = isl_schedule_node_insert_sequence(node, filters); + + for (i = 0; i < graph->scc; ++i) { + int j = c->scc_cluster[i]; + node = isl_schedule_node_grandchild(node, i, 0); + node = isl_schedule_node_compute_finish_band(node, + &c->cluster[j], 0); + node = isl_schedule_node_grandparent(node); + } + + return node; +} + +/* Compute a schedule for a connected dependence graph by first considering + * each strongly connected component (SCC) in the graph separately and then + * incrementally combining them into clusters. + * Return the updated schedule node. + * + * Initially, each cluster consists of a single SCC, each with its + * own band schedule. The algorithm then tries to merge pairs + * of clusters along a proximity edge until no more suitable + * proximity edges can be found. During this merging, the schedule + * is maintained in the individual SCCs. + * After the merging is completed, the full resulting clusters + * are extracted and in finish_bands_clustering, + * isl_schedule_node_compute_finish_band is called on each of them to integrate + * the band into "node" and to continue the computation. + * + * compute_weights initializes the weights that are used by find_proximity. + */ +__isl_give isl_schedule_node *isl_schedule_node_compute_wcc_clustering( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph) +{ + isl_ctx *ctx; + struct isl_clustering c; + int i; + + ctx = isl_schedule_node_get_ctx(node); + + if (clustering_init(ctx, &c, graph) < 0) + goto error; + + if (compute_weights(graph, &c) < 0) + goto error; + + for (;;) { + i = find_proximity(graph, &c); + if (i < 0) + goto error; + if (i >= graph->n_edge) + break; + if (merge_clusters_along_edge(ctx, graph, i, &c) < 0) + goto error; + } + + if (extract_clusters(ctx, graph, &c) < 0) + goto error; + + node = finish_bands_clustering(node, graph, &c); + + clustering_free(ctx, &c); + return node; +error: + clustering_free(ctx, &c); + return isl_schedule_node_free(node); +} diff --git a/polly/lib/External/isl/isl_scheduler_clustering.h b/polly/lib/External/isl/isl_scheduler_clustering.h new file mode 100644 index 0000000..bc00326 --- /dev/null +++ b/polly/lib/External/isl/isl_scheduler_clustering.h @@ -0,0 +1,39 @@ +#ifndef ISL_SCHEDULER_CLUSTERING_H +#define ISL_SCHEDULER_CLUSTERING_H + +#include "isl_scheduler.h" + +/* Clustering information used by isl_schedule_node_compute_wcc_clustering. + * + * "n" is the number of SCCs in the original dependence graph + * "scc" is an array of "n" elements, each representing an SCC + * of the original dependence graph. All entries in the same cluster + * have the same number of schedule rows. + * "scc_cluster" maps each SCC index to the cluster to which it belongs, + * where each cluster is represented by the index of the first SCC + * in the cluster. Initially, each SCC belongs to a cluster containing + * only that SCC. + * + * "scc_in_merge" is used by merge_clusters_along_edge to keep + * track of which SCCs need to be merged. + * + * "cluster" contains the merged clusters of SCCs after the clustering + * has completed. + * + * "scc_node" is a temporary data structure used inside copy_partial. + * For each SCC, it keeps track of the number of nodes in the SCC + * that have already been copied. + */ +struct isl_clustering { + int n; + struct isl_sched_graph *scc; + struct isl_sched_graph *cluster; + int *scc_cluster; + int *scc_node; + int *scc_in_merge; +}; + +__isl_give isl_schedule_node *isl_schedule_node_compute_wcc_clustering( + __isl_take isl_schedule_node *node, struct isl_sched_graph *graph); + +#endif diff --git a/polly/lib/External/isl/isl_scheduler_scc.c b/polly/lib/External/isl/isl_scheduler_scc.c new file mode 100644 index 0000000..ffbcfe2 --- /dev/null +++ b/polly/lib/External/isl/isl_scheduler_scc.c @@ -0,0 +1,1209 @@ +/* + * Copyright 2021 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege + */ + +#include + +#include +#include +#include + +#include "isl_hash_private.h" +#include "isl_scheduler_scc.h" +#include "isl_sort.h" + +/* Internal data structure for ordering the SCCs of "graph", + * where each SCC i consists of the single cluster determined + * by c->scc_cluster[i]. The nodes in this cluster all have + * their "scc" field set to i. + * + * "graph" is the original schedule graph. + * "c" contains the clustering information. + * + * "n" is the number of SCCs in the isl_scc_graph, which may be + * a subset of those in "graph". + * "graph_scc" maps the local index of an SCC in this isl_scc_graph + * to the corresponding index in "graph", i.e, the index of c->scc_cluster. + * The entries of "graph_scc" are kept in topological order. + * + * "component" contains the component to which an SCC belongs, + * where the component is represented by the index of the first SCC + * in the component. + * The index of this first SCC is always smaller than or equal + * to the index of the SCC itself. + * This field is initialized by isl_scc_graph_init_component and + * used by detect_components. + * During construction, "component" may also contain the index + * of some other SCC in the component, but then it is necessarily + * smaller than the index of the current SCC and the first SCC + * can be reached by recursively looking up "component". + * "size" contains the number of elements in the components + * indexed by a component sequence number. + * + * "pos" is used locally inside isl_scc_graph_sort_components + * to store the position of the next SCC within a component. + * It is also used inside isl_scc_graph_sub to map + * the position in the original graph to the position in the subgraph. + * + * "sorted" contains the (possibly) reordered local indices, + * sorted per component. Within each component, the original + * topological order is preserved. + * + * "edge_table" contains "n" edge tables, one for each SCC + * in this isl_scc_graph. Each table contains the local indices + * of the SCCs that depend on this SCC. These local indices + * are encoded as pointers to the corresponding entry in "graph_scc". + * The value stored at that location is the global SCC index. + * "reverse_edge_table" contains the inverse edges. + */ +struct isl_scc_graph { + isl_ctx *ctx; + struct isl_sched_graph *graph; + struct isl_clustering *c; + + int n; + int *graph_scc; + int *component; + int *size; + int *pos; + int *sorted; + struct isl_hash_table **edge_table; + struct isl_hash_table **reverse_edge_table; +}; + +/* The source SCC of a collection of edges. + * + * "scc_graph" is the SCC graph containing the edges. + * "src" is the local index of the source SCC. + */ +struct isl_edge_src { + struct isl_scc_graph *scc_graph; + int src; +}; + +/* isl_hash_table_foreach callback for printing an edge + * between "src" and the node identified by "entry". + * The edge is printed in terms of the global SCC indices. + */ +static isl_stat print_edge(void **entry, void *user) +{ + int *dst = *entry; + int *src = user; + + fprintf(stderr, "%d -> %d; ", *src, *dst); + + return isl_stat_ok; +} + +/* Print some debugging information about "scc_graph". + * + * In particular, print the nodes and the edges (both forward and backward). + */ +void isl_scc_graph_dump(struct isl_scc_graph *scc_graph) +{ + int i; + isl_ctx *ctx; + + if (!scc_graph) + return; + + ctx = scc_graph->ctx; + for (i = 0; i < scc_graph->n; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "%d", scc_graph->graph_scc[i]); + } + fprintf(stderr, "\n"); + for (i = 0; i < scc_graph->n; ++i) { + isl_hash_table_foreach(ctx, scc_graph->edge_table[i], + &print_edge, &scc_graph->graph_scc[i]); + } + fprintf(stderr, "\n"); + for (i = 0; i < scc_graph->n; ++i) { + isl_hash_table_foreach(ctx, scc_graph->reverse_edge_table[i], + &print_edge, &scc_graph->graph_scc[i]); + } + fprintf(stderr, "\n"); +} + +/* Free all memory allocated for "scc_graph" and return NULL. + */ +struct isl_scc_graph *isl_scc_graph_free(struct isl_scc_graph *scc_graph) +{ + int i; + isl_ctx *ctx; + + if (!scc_graph) + return NULL; + + ctx = scc_graph->ctx; + if (scc_graph->edge_table) { + for (i = 0; i < scc_graph->n; ++i) + isl_hash_table_free(ctx, scc_graph->edge_table[i]); + } + if (scc_graph->reverse_edge_table) { + for (i = 0; i < scc_graph->n; ++i) + isl_hash_table_free(ctx, + scc_graph->reverse_edge_table[i]); + } + + free(scc_graph->graph_scc); + free(scc_graph->component); + free(scc_graph->size); + free(scc_graph->pos); + free(scc_graph->sorted); + free(scc_graph->edge_table); + free(scc_graph->reverse_edge_table); + isl_ctx_deref(scc_graph->ctx); + free(scc_graph); + return NULL; +} + +/* Return an encoding of the local SCC index "pos" in "scc_graph" + * as a pointer. + * In particular, return a pointer to the corresponding entry + * in scc_graph->graph_scc. + */ +static void *isl_scc_graph_encode_local_index(struct isl_scc_graph *scc_graph, + int pos) +{ + return &scc_graph->graph_scc[pos]; +} + +/* Return the local SCC index in "scc_graph" corresponding + * to the "data" encoding in the edge table. + */ +static int isl_scc_graph_local_index(struct isl_scc_graph *scc_graph, int *data) +{ + return data - &scc_graph->graph_scc[0]; +} + +/* isl_hash_table_find callback to check whether the given entry + * refers to an SCC encoded as "val". + */ +static isl_bool is_scc_node(const void *entry, const void *val) +{ + return entry == val; +} + +/* Return the edge from local SCC index "src" to local SCC index "dst" + * in "edge_table" of "scc_graph", creating one if "reserve" is set. + * If "reserve" is not set, then return isl_hash_table_entry_none + * if there is no such edge. + * + * The destination of the edge is encoded as a pointer + * to the corresponding entry in scc_graph->graph_scc. + */ +struct isl_hash_table_entry *isl_scc_graph_find_edge( + struct isl_scc_graph *scc_graph, struct isl_hash_table **edge_table, + int src, int dst, int reserve) +{ + isl_ctx *ctx; + uint32_t hash; + void *val; + + ctx = scc_graph->ctx; + hash = isl_hash_builtin(isl_hash_init(), dst); + val = isl_scc_graph_encode_local_index(scc_graph, dst); + return isl_hash_table_find(ctx, edge_table[src], hash, + &is_scc_node, val, reserve); +} + +/* Remove the edge between the SCCs with local indices "src" and + * "dst" in "scc_graph", if it exits. + * Return isl_bool_true if this is the case. + * + * The edge is only removed from scc_graph->edge_table. + * scc_graph->reverse_edge_table is assumed to be empty + * when this function is called. + */ +static isl_bool isl_scc_graph_remove_edge(struct isl_scc_graph *scc_graph, + int src, int dst) +{ + isl_ctx *ctx; + struct isl_hash_table_entry *edge_entry; + + edge_entry = isl_scc_graph_find_edge(scc_graph, scc_graph->edge_table, + src, dst, 0); + if (edge_entry == isl_hash_table_entry_none) + return isl_bool_false; + if (!edge_entry) + return isl_bool_error; + + ctx = scc_graph->ctx; + isl_hash_table_remove(ctx, scc_graph->edge_table[src], edge_entry); + + return isl_bool_true; +} + +/* Internal data structure used by next_nodes. + * + * "scc_graph" is the SCC graph. + * "next" collects the next nodes. + * "n" is the number of next nodes already collected. + */ +struct isl_extract_dst_data { + struct isl_scc_graph *scc_graph; + int *next; + int n; +}; + +/* Given an entry in the edge table, add the corresponding + * target local SCC index to data->next. + */ +static isl_stat extract_dst(void **entry, void *user) +{ + int *dst = *entry; + struct isl_extract_dst_data *data = user; + + data->next[data->n++] = isl_scc_graph_local_index(data->scc_graph, dst); + + return isl_stat_ok; +} + +/* isl_sort callback for sorting integers in increasing order. + */ +static int cmp_int(const void *a, const void *b, void *data) +{ + const int *i1 = a; + const int *i2 = b; + + return *i1 - *i2; +} + +/* Return the local indices of the SCCs in "scc_graph" + * for which there is an edge from the SCC with local index "i". + * The indices are returned in increasing order, + * i.e., in the original topological order. + */ +static int *next_nodes(struct isl_scc_graph *scc_graph, int i) +{ + struct isl_extract_dst_data data; + int n_next; + int *next; + + n_next = scc_graph->edge_table[i]->n; + next = isl_alloc_array(scc_graph->ctx, int, n_next); + if (!next) + return NULL; + data.scc_graph = scc_graph; + data.next = next; + data.n = 0; + if (isl_hash_table_foreach(scc_graph->ctx, scc_graph->edge_table[i], + &extract_dst, &data) < 0) + goto error; + if (isl_sort(next, n_next, sizeof(int), &cmp_int, NULL) < 0) + goto error; + return next; +error: + free(next); + return NULL; +} + +/* Internal data structure for foreach_reachable. + * + * "scc_graph" is the SCC graph being visited. + * "fn" is the function that needs to be called on each reachable node. + * "user" is the user argument to "fn". + */ +struct isl_foreach_reachable_data { + struct isl_scc_graph *scc_graph; + isl_bool (*fn)(int pos, void *user); + void *user; +}; + +static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data, + int pos); + +/* isl_hash_table_foreach callback for calling data->fn on each SCC + * reachable from the SCC encoded in "entry", + * continuing from an SCC as long as data->fn returns isl_bool_true. + */ +static isl_stat recurse_foreach_reachable(void **entry, void *user) +{ + struct isl_foreach_reachable_data *data = user; + int pos; + isl_bool more; + + pos = isl_scc_graph_local_index(data->scc_graph, *entry); + more = data->fn(pos, data->user); + if (more < 0) + return isl_stat_error; + if (!more) + return isl_stat_ok; + + return foreach_reachable(data, pos); +} + +/* Call data->fn on each SCC reachable from the SCC with local index "pos", + * continuing from an SCC as long as data->fn returns isl_bool_true. + * + * Handle chains directly and recurse when an SCC has more than one + * outgoing edge. + */ +static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data, + int pos) +{ + isl_ctx *ctx; + struct isl_hash_table **edge_table = data->scc_graph->edge_table; + + while (edge_table[pos]->n == 1) { + struct isl_hash_table_entry *entry; + isl_bool more; + + entry = isl_hash_table_first(edge_table[pos]); + pos = isl_scc_graph_local_index(data->scc_graph, entry->data); + more = data->fn(pos, data->user); + if (more < 0) + return isl_stat_error; + if (!more) + return isl_stat_ok; + } + + if (edge_table[pos]->n == 0) + return isl_stat_ok; + + ctx = data->scc_graph->ctx; + return isl_hash_table_foreach(ctx, edge_table[pos], + &recurse_foreach_reachable, data); +} + +/* If there is an edge from data->src to "pos", then remove it. + * Return isl_bool_true if descendants of "pos" still need to be considered. + * + * Descendants only need to be considered if no edge is removed. + */ +static isl_bool elim_or_next(int pos, void *user) +{ + struct isl_edge_src *data = user; + struct isl_scc_graph *scc_graph = data->scc_graph; + isl_bool removed; + + removed = isl_scc_graph_remove_edge(scc_graph, data->src, pos); + return isl_bool_not(removed); +} + +/* Remove transitive edges from "scc_graph". + * + * Consider the SCC nodes "i" in reverse topological order. + * If there is more than one edge emanating from a node, + * then eliminate the edges to those nodes that can also be reached + * through an edge to a node with a smaller index. + * In particular, consider all but the last next nodes "next[j]" + * in reverse topological order. If any node "k" can be reached + * from such a node for which there is also an edge from "i" + * then this edge can be removed because this node can also + * be reached from "i" through the edge to "next[j]". + * If such an edge is removed, then any further descendant of "k" + * does not need to be considered since these were already considered + * for a previous "next[j]" equal to "k", or "k" is the last next node, + * in which case there is no further node with an edge from "i". + */ +static struct isl_scc_graph *isl_scc_graph_reduce( + struct isl_scc_graph *scc_graph) +{ + struct isl_edge_src elim_data; + struct isl_foreach_reachable_data data = { + .scc_graph = scc_graph, + .fn = &elim_or_next, + .user = &elim_data, + }; + int i, j; + + elim_data.scc_graph = scc_graph; + for (i = scc_graph->n - 3; i >= 0; --i) { + int *next; + int n_next; + + n_next = scc_graph->edge_table[i]->n; + if (n_next <= 1) + continue; + next = next_nodes(scc_graph, i); + if (!next) + return isl_scc_graph_free(scc_graph); + + elim_data.src = i; + for (j = n_next - 2; j >= 0; --j) + if (foreach_reachable(&data, next[j]) < 0) + break; + free(next); + if (j >= 0) + return isl_scc_graph_free(scc_graph); + } + + return scc_graph; +} + +/* Add an edge to "edge_table" between the SCCs with local indices "src" and + * "dst" in "scc_graph". + * + * If the edge already appeared in the table, then it is simply overwritten + * with the same information. + */ +static isl_stat isl_scc_graph_add_edge(struct isl_scc_graph *scc_graph, + struct isl_hash_table **edge_table, int src, int dst) +{ + struct isl_hash_table_entry *edge_entry; + + edge_entry = + isl_scc_graph_find_edge(scc_graph, edge_table, src, dst, 1); + if (!edge_entry) + return isl_stat_error; + edge_entry->data = &scc_graph->graph_scc[dst]; + + return isl_stat_ok; +} + +/* Add an edge from "dst" to data->src + * to data->scc_graph->reverse_edge_table. + */ +static isl_stat add_reverse(void **entry, void *user) +{ + struct isl_edge_src *data = user; + int dst; + + dst = isl_scc_graph_local_index(data->scc_graph, *entry); + return isl_scc_graph_add_edge(data->scc_graph, + data->scc_graph->reverse_edge_table, dst, data->src); +} + +/* Add an (inverse) edge to scc_graph->reverse_edge_table + * for each edge in scc_graph->edge_table. + */ +static struct isl_scc_graph *isl_scc_graph_add_reverse_edges( + struct isl_scc_graph *scc_graph) +{ + struct isl_edge_src data; + isl_ctx *ctx; + + if (!scc_graph) + return NULL; + + ctx = scc_graph->ctx; + data.scc_graph = scc_graph; + for (data.src = 0; data.src < scc_graph->n; ++data.src) { + if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src], + &add_reverse, &data) < 0) + return isl_scc_graph_free(scc_graph); + } + return scc_graph; +} + +/* Given an edge in the schedule graph, add an edge between + * the corresponding SCCs in "scc_graph", if they are distinct. + * + * This function is used to create edges in the original isl_scc_graph. + * where the local SCC indices are equal to the corresponding global + * indices. + */ +static isl_stat add_scc_edge(void **entry, void *user) +{ + struct isl_sched_edge *edge = *entry; + struct isl_scc_graph *scc_graph = user; + int src = edge->src->scc; + int dst = edge->dst->scc; + + if (src == dst) + return isl_stat_ok; + + return isl_scc_graph_add_edge(scc_graph, scc_graph->edge_table, + src, dst); +} + +/* Allocate an isl_scc_graph for ordering "n" SCCs of "graph" + * with clustering information in "c". + * + * The caller still needs to fill in the edges. + */ +static struct isl_scc_graph *isl_scc_graph_alloc(isl_ctx *ctx, int n, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i; + struct isl_scc_graph *scc_graph; + + scc_graph = isl_alloc_type(ctx, struct isl_scc_graph); + if (!scc_graph) + return NULL; + + scc_graph->ctx = ctx; + isl_ctx_ref(ctx); + scc_graph->graph = graph; + scc_graph->c = c; + + scc_graph->n = n; + scc_graph->graph_scc = isl_alloc_array(ctx, int, n); + scc_graph->component = isl_alloc_array(ctx, int, n); + scc_graph->size = isl_alloc_array(ctx, int, n); + scc_graph->pos = isl_alloc_array(ctx, int, n); + scc_graph->sorted = isl_alloc_array(ctx, int, n); + scc_graph->edge_table = + isl_calloc_array(ctx, struct isl_hash_table *, n); + scc_graph->reverse_edge_table = + isl_calloc_array(ctx, struct isl_hash_table *, n); + if (!scc_graph->graph_scc || !scc_graph->component || + !scc_graph->size || !scc_graph->pos || !scc_graph->sorted || + !scc_graph->edge_table || !scc_graph->reverse_edge_table) + return isl_scc_graph_free(scc_graph); + + for (i = 0; i < n; ++i) { + scc_graph->edge_table[i] = isl_hash_table_alloc(ctx, 2); + scc_graph->reverse_edge_table[i] = isl_hash_table_alloc(ctx, 2); + if (!scc_graph->edge_table[i] || + !scc_graph->reverse_edge_table[i]) + return isl_scc_graph_free(scc_graph); + } + + return scc_graph; +} + +/* Construct an isl_scc_graph for ordering the SCCs of "graph", + * where each SCC i consists of the single cluster determined + * by c->scc_cluster[i]. The nodes in this cluster all have + * their "scc" field set to i. + * + * The initial isl_scc_graph has as many SCCs as "graph" and + * their local indices are the same as their indices in "graph". + * + * Add edges between different SCCs for each (conditional) validity edge + * between nodes in those SCCs, remove transitive edges and + * construct the inverse edges from the remaining forward edges. + */ +struct isl_scc_graph *isl_scc_graph_from_sched_graph(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c) +{ + int i; + struct isl_scc_graph *scc_graph; + + scc_graph = isl_scc_graph_alloc(ctx, graph->scc, graph, c); + if (!scc_graph) + return NULL; + + for (i = 0; i < graph->scc; ++i) + scc_graph->graph_scc[i] = i; + + if (isl_hash_table_foreach(ctx, graph->edge_table[isl_edge_validity], + &add_scc_edge, scc_graph) < 0) + return isl_scc_graph_free(scc_graph); + if (isl_hash_table_foreach(ctx, + graph->edge_table[isl_edge_conditional_validity], + &add_scc_edge, scc_graph) < 0) + return isl_scc_graph_free(scc_graph); + + scc_graph = isl_scc_graph_reduce(scc_graph); + scc_graph = isl_scc_graph_add_reverse_edges(scc_graph); + + return scc_graph; +} + +/* Internal data structure for copy_edge. + * + * "scc_graph" is the original graph. + * "sub" is the subgraph to which edges are being copied. + * "src" is the local index in "scc_graph" of the source of the edges + * currently being copied. + */ +struct isl_copy_edge_data { + struct isl_scc_graph *scc_graph; + struct isl_scc_graph *sub; + int src; +}; + +/* isl_hash_table_foreach callback for copying the edge + * from data->src to the node identified by "entry" + * to data->sub, provided the two nodes belong to the same component. + * Note that by construction, there are no edges between different components + * in the region handled by detect_components, but there may + * be edges to nodes outside this region. + * The components therefore need to be initialized for all nodes + * in isl_scc_graph_init_component. + */ +static isl_stat copy_edge(void **entry, void *user) +{ + struct isl_copy_edge_data *data = user; + struct isl_scc_graph *scc_graph = data->scc_graph; + struct isl_scc_graph *sub = data->sub; + int dst, sub_dst, sub_src; + + dst = isl_scc_graph_local_index(data->scc_graph, *entry); + if (scc_graph->component[dst] != scc_graph->component[data->src]) + return isl_stat_ok; + + sub_src = scc_graph->pos[data->src]; + sub_dst = scc_graph->pos[dst]; + + return isl_scc_graph_add_edge(sub, sub->edge_table, sub_src, sub_dst); +} + +/* Construct a subgraph of "scc_graph" for the components + * consisting of the "n" SCCs with local indices in "pos". + * These SCCs have the same value in scc_graph->component and + * this value is different from that of any other SCC. + * + * The forward edges with source and destination in the component + * are copied from "scc_graph". + * The local index in the subgraph corresponding to a local index + * in "scc_graph" is stored in scc_graph->pos for use by copy_edge(). + * The inverse edges are constructed directly from the forward edges. + */ +static struct isl_scc_graph *isl_scc_graph_sub(struct isl_scc_graph *scc_graph, + int *pos, int n) +{ + int i; + isl_ctx *ctx; + struct isl_scc_graph *sub; + struct isl_copy_edge_data data; + + if (!scc_graph) + return NULL; + + ctx = scc_graph->ctx; + sub = isl_scc_graph_alloc(ctx, n, scc_graph->graph, scc_graph->c); + if (!sub) + return sub; + + for (i = 0; i < n; ++i) + sub->graph_scc[i] = scc_graph->graph_scc[pos[i]]; + + for (i = 0; i < n; ++i) + scc_graph->pos[pos[i]] = i; + + data.scc_graph = scc_graph; + data.sub = sub; + for (i = 0; i < n; ++i) { + data.src = pos[i]; + if (isl_hash_table_foreach(ctx, scc_graph->edge_table[pos[i]], + ©_edge, &data) < 0) + return isl_scc_graph_free(sub); + } + + sub = isl_scc_graph_add_reverse_edges(sub); + + return sub; +} + +/* Return a union of universe domains corresponding to the nodes + * in the SCC with local index "pos". + */ +static __isl_give isl_union_set *isl_scc_graph_extract_local_scc( + struct isl_scc_graph *scc_graph, int pos) +{ + return isl_sched_graph_extract_scc(scc_graph->ctx, scc_graph->graph, + scc_graph->graph_scc[pos]); +} + +/* Construct a filter corresponding to a sequence of "n" local SCC indices + * determined by successive calls to "el", + * add this filter to "list" and + * return the result. + */ +static __isl_give isl_union_set_list *add_scc_seq( + struct isl_scc_graph *scc_graph, + int (*el)(int i, void *user), void *user, int n, + __isl_take isl_union_set_list *list) +{ + int i; + isl_union_set *dom; + + dom = isl_union_set_empty_ctx(scc_graph->ctx); + for (i = 0; i < n; ++i) + dom = isl_union_set_union(dom, + isl_scc_graph_extract_local_scc(scc_graph, el(i, user))); + + return isl_union_set_list_add(list, dom); +} + +/* add_scc_seq callback that, on successive calls, returns a sequence + * of local SCC indices starting at "first". + */ +static int offset(int i, void *user) +{ + int *first = user; + + return *first + i; +} + +/* Construct a filter corresponding to a sequence of "n" local SCC indices + * starting at "first", add this filter to "list" and return the result. + */ +static __isl_give isl_union_set_list *isl_scc_graph_add_scc_seq( + struct isl_scc_graph *scc_graph, int first, int n, + __isl_take isl_union_set_list *list) +{ + return add_scc_seq(scc_graph, &offset, &first, n, list); +} + +/* add_scc_seq callback that, on successive calls, returns the sequence + * of local SCC indices in "seq". + */ +static int at(int i, void *user) +{ + int *seq = user; + + return seq[i]; +} + +/* Construct a filter corresponding to the sequence of "n" local SCC indices + * stored in "seq", add this filter to "list" and return the result. + */ +static __isl_give isl_union_set_list *isl_scc_graph_add_scc_indirect_seq( + struct isl_scc_graph *scc_graph, int *seq, int n, + __isl_take isl_union_set_list *list) +{ + return add_scc_seq(scc_graph, &at, seq, n, list); +} + +/* Extract out a list of filters for a sequence node that splits + * the graph along the SCC with local index "pos". + * + * The list contains (at most) three elements, + * the SCCs before "pos" (in the topological order), + * "pos" itself, and + * the SCCs after "pos". + */ +static __isl_give isl_union_set_list *extract_split_scc( + struct isl_scc_graph *scc_graph, int pos) +{ + isl_union_set *dom; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(scc_graph->ctx, 3); + if (pos > 0) + filters = isl_scc_graph_add_scc_seq(scc_graph, 0, pos, filters); + dom = isl_scc_graph_extract_local_scc(scc_graph, pos); + filters = isl_union_set_list_add(filters, dom); + if (pos + 1 < scc_graph->n) + filters = isl_scc_graph_add_scc_seq(scc_graph, + pos + 1, scc_graph->n - (pos + 1), filters); + return filters; +} + +/* Call isl_schedule_node_compute_finish_band on the cluster + * corresponding to the SCC with local index "pos". + * + * First obtain the corresponding SCC index in scc_graph->graph and + * then obtain the corresponding cluster. + */ +static __isl_give isl_schedule_node *isl_scc_graph_finish_band( + struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node, + int pos) +{ + struct isl_clustering *c = scc_graph->c; + int cluster; + + cluster = c->scc_cluster[scc_graph->graph_scc[pos]]; + return isl_schedule_node_compute_finish_band(node, + &c->cluster[cluster], 0); +} + +/* Given that the SCCs in "scc_graph" form a chain, + * call isl_schedule_node_compute_finish_band on each of the clusters + * in scc_graph->c and update "node" to arrange for them to be executed + * in topological order. + */ +static __isl_give isl_schedule_node *isl_scc_graph_chain( + struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node) +{ + int i; + isl_union_set *dom; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(scc_graph->ctx, scc_graph->n); + for (i = 0; i < scc_graph->n; ++i) { + dom = isl_scc_graph_extract_local_scc(scc_graph, i); + filters = isl_union_set_list_add(filters, dom); + } + + node = isl_schedule_node_insert_sequence(node, filters); + + for (i = 0; i < scc_graph->n; ++i) { + node = isl_schedule_node_grandchild(node, i, 0); + node = isl_scc_graph_finish_band(scc_graph, node, i); + node = isl_schedule_node_grandparent(node); + } + + return node; +} + +/* Recursively call isl_scc_graph_decompose on a subgraph + * consisting of the "n" SCCs with local indices in "pos". + * + * If this component contains only a single SCC, + * then there is no need for a further recursion and + * isl_schedule_node_compute_finish_band can be called directly. + */ +static __isl_give isl_schedule_node *recurse(struct isl_scc_graph *scc_graph, + int *pos, int n, __isl_take isl_schedule_node *node) +{ + struct isl_scc_graph *sub; + + if (n == 1) + return isl_scc_graph_finish_band(scc_graph, node, pos[0]); + + sub = isl_scc_graph_sub(scc_graph, pos, n); + if (!sub) + return isl_schedule_node_free(node); + node = isl_scc_graph_decompose(sub, node); + isl_scc_graph_free(sub); + + return node; +} + +/* Initialize the component field of "scc_graph". + * Initially, each SCC belongs to its own single-element component. + * + * Note that the SCC on which isl_scc_graph_decompose performs a split + * also needs to be assigned a component because the components + * are also used in copy_edge to extract a subgraph. + */ +static void isl_scc_graph_init_component(struct isl_scc_graph *scc_graph) +{ + int i; + + for (i = 0; i < scc_graph->n; ++i) + scc_graph->component[i] = i; +} + +/* Set the component of "a" to be the same as that of "b" and + * return the original component of "a". + */ +static int assign(int *component, int a, int b) +{ + int t; + + t = component[a]; + component[a] = component[b]; + return t; +} + +/* Merge the components containing the SCCs with indices "a" and "b". + * + * If "a" and "b" already belong to the same component, then nothing + * needs to be done. + * Otherwise, make sure both point to the same component. + * In particular, use the SCC in the component entries with the smallest index. + * If the other SCC was the first of its component then the entire + * component now (eventually) points to the other component. + * Otherwise, the earlier parts of the component still need + * to be merged with the other component. + * + * At each stage, either a or b is replaced by either a or b itself, + * in which case the merging terminates because a and b already + * point to the same component, or an SCC index with a smaller value. + * This ensures the merging terminates at some point. + */ +static void isl_scc_graph_merge_src_dst(struct isl_scc_graph *scc_graph, + int a, int b) +{ + int *component = scc_graph->component; + + while (component[a] != component[b]) { + if (component[a] < component[b]) + b = assign(component, b, a); + else + a = assign(component, a, b); + } +} + +/* Internal data structure for isl_scc_graph_merge_components. + * + * "scc_graph" is the SCC graph containing the edges. + * "src" is the local index of the source SCC. + * "end" is the local index beyond the sequence being considered. + */ +struct isl_merge_src_dst_data { + struct isl_scc_graph *scc_graph; + int src; + int end; +}; + +/* isl_hash_table_foreach callback for merging the components + * of data->src and the node represented by "entry", provided + * it is within the sequence being considered. + */ +static isl_stat merge_src_dst(void **entry, void *user) +{ + struct isl_merge_src_dst_data *data = user; + int dst; + + dst = isl_scc_graph_local_index(data->scc_graph, *entry); + if (dst >= data->end) + return isl_stat_ok; + + isl_scc_graph_merge_src_dst(data->scc_graph, data->src, dst); + + return isl_stat_ok; +} + +/* Merge components of the "n" SCCs starting at "first" that are connected + * by an edge. + */ +static isl_stat isl_scc_graph_merge_components(struct isl_scc_graph *scc_graph, + int first, int n) +{ + int i; + struct isl_merge_src_dst_data data; + isl_ctx *ctx = scc_graph->ctx; + + data.scc_graph = scc_graph; + data.end = first + n; + for (i = 0; i < n; ++i) { + data.src = first + i; + if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src], + &merge_src_dst, &data) < 0) + return isl_stat_error; + } + + return isl_stat_ok; +} + +/* Sort the "n" local SCC indices starting at "first" according + * to component, store them in scc_graph->sorted and + * return the number of components. + * The sizes of the components are stored in scc_graph->size. + * Only positions starting at "first" are used within + * scc_graph->sorted and scc_graph->size. + * + * The representation of the components is first normalized. + * The normalization ensures that each SCC in a component + * points to the first SCC in the component, whereas + * before this function is called, some SCCs may only point + * to some other SCC in the component with a smaller index. + * + * Internally, the sizes of the components are first stored + * at indices corresponding to the first SCC in the component. + * They are subsequently moved into consecutive positions + * while reordering the local indices. + * This reordering is performed by first determining the position + * of the first SCC in each component and + * then putting the "n" local indices in the right position + * according to the component, preserving the topological order + * within each component. + */ +static int isl_scc_graph_sort_components(struct isl_scc_graph *scc_graph, + int first, int n) +{ + int i, j; + int sum; + int *component = scc_graph->component; + int *size = scc_graph->size; + int *pos = scc_graph->pos; + int *sorted = scc_graph->sorted; + int n_component; + + n_component = 0; + for (i = 0; i < n; ++i) { + size[first + i] = 0; + if (component[first + i] == first + i) + n_component++; + else + component[first + i] = component[component[first + i]]; + size[component[first + i]]++; + } + + sum = first; + i = 0; + for (j = 0; j < n_component; ++j) { + while (size[first + i] == 0) + ++i; + pos[first + i] = sum; + sum += size[first + i]; + size[first + j] = size[first + i++]; + } + for (i = 0; i < n; ++i) + sorted[pos[component[first + i]]++] = first + i; + + return n_component; +} + +/* Extract out a list of filters for a set node that splits up + * the graph into "n_component" components. + * "first" is the initial position in "scc_graph" where information + * about the components is stored. + * In particular, the first "n_component" entries of scc_graph->size + * at this position contain the number of SCCs in each component. + * The entries of scc_graph->sorted starting at "first" + * contain the local indices of the SCC in those components. + */ +static __isl_give isl_union_set_list *extract_components( + struct isl_scc_graph *scc_graph, int first, int n_component) +{ + int i; + int sum; + int *size = scc_graph->size; + int *sorted = scc_graph->sorted; + isl_ctx *ctx = scc_graph->ctx; + isl_union_set_list *filters; + + filters = isl_union_set_list_alloc(ctx, n_component); + sum = first; + for (i = 0; i < n_component; ++i) { + int n; + + n = size[first + i]; + filters = isl_scc_graph_add_scc_indirect_seq(scc_graph, + &sorted[sum], n, filters); + sum += n; + } + + return filters; +} + +/* Detect components in the subgraph consisting of the "n" SCCs + * with local index starting at "first" and further decompose them, + * calling isl_schedule_node_compute_finish_band on each + * of the corresponding clusters. + * + * If there is only one SCC, then isl_schedule_node_compute_finish_band + * can be called directly. + * Otherwise, determine the components and rearrange the local indices + * according to component, but preserving the topological order within + * each component, in scc_graph->sorted. The sizes of the components + * are stored in scc_graph->size. + * If there is only one component, it can be further decomposed + * directly by a call to recurse(). + * Otherwise, introduce a set node separating the components and + * call recurse() on each component separately. + */ +static __isl_give isl_schedule_node *detect_components( + struct isl_scc_graph *scc_graph, int first, int n, + __isl_take isl_schedule_node *node) +{ + int i; + int *size = scc_graph->size; + int *sorted = scc_graph->sorted; + int n_component; + int sum; + isl_union_set_list *filters; + + if (n == 1) + return isl_scc_graph_finish_band(scc_graph, node, first); + + if (isl_scc_graph_merge_components(scc_graph, first, n) < 0) + return isl_schedule_node_free(node); + + n_component = isl_scc_graph_sort_components(scc_graph, first, n); + if (n_component == 1) + return recurse(scc_graph, &sorted[first], n, node); + + filters = extract_components(scc_graph, first, n_component); + node = isl_schedule_node_insert_set(node, filters); + + sum = first; + for (i = 0; i < n_component; ++i) { + int n; + + n = size[first + i]; + node = isl_schedule_node_grandchild(node, i, 0); + node = recurse(scc_graph, &sorted[sum], n, node); + node = isl_schedule_node_grandparent(node); + sum += n; + } + + return node; +} + +/* Given a sequence node "node", where the filter at position "child" + * represents the "n" SCCs with local index starting at "first", + * detect components in this subgraph and further decompose them, + * calling isl_schedule_node_compute_finish_band on each + * of the corresponding clusters. + */ +static __isl_give isl_schedule_node *detect_components_at( + struct isl_scc_graph *scc_graph, int first, int n, + __isl_take isl_schedule_node *node, int child) +{ + node = isl_schedule_node_grandchild(node, child, 0); + node = detect_components(scc_graph, first, n, node); + node = isl_schedule_node_grandparent(node); + + return node; +} + +/* Return the local index of an SCC on which to split "scc_graph". + * Return scc_graph->n if no suitable split SCC can be found. + * + * In particular, look for an SCC that is involved in the largest number + * of edges. Splitting the graph on such an SCC has the highest chance + * of exposing independent SCCs in the remaining part(s). + * There is no point in splitting a chain of nodes, + * so return scc_graph->n if the entire graph forms a chain. + */ +static int best_split(struct isl_scc_graph *scc_graph) +{ + int i; + int split = scc_graph->n; + int split_score = -1; + + for (i = 0; i < scc_graph->n; ++i) { + int n_fwd, n_bwd; + + n_fwd = scc_graph->edge_table[i]->n; + n_bwd = scc_graph->reverse_edge_table[i]->n; + if (n_fwd <= 1 && n_bwd <= 1) + continue; + if (split_score >= n_fwd + n_bwd) + continue; + split = i; + split_score = n_fwd + n_bwd; + } + + return split; +} + +/* Call isl_schedule_node_compute_finish_band on each of the clusters + * in scc_graph->c and update "node" to arrange for them to be executed + * in an order possibly involving set nodes that generalizes + * the topological order determined by the scc fields of the nodes + * in scc_graph->graph. + * + * First try and find a suitable SCC on which to split the graph. + * If no such SCC can be found then the graph forms a chain and + * it is handled as such. + * Otherwise, break up the graph into (at most) three parts, + * the SCCs before the selected SCC (in the topological order), + * the selected SCC itself, and + * the SCCs after the selected SCC. + * The first and last part (if they exist) are decomposed recursively and + * the three parts are combined in a sequence. + * + * Since the outermost node of the recursive pieces may also be a sequence, + * these potential sequence nodes are spliced into the top-level sequence node. + */ +__isl_give isl_schedule_node *isl_scc_graph_decompose( + struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node) +{ + int i; + int split; + isl_union_set_list *filters; + + if (!scc_graph) + return isl_schedule_node_free(node); + + split = best_split(scc_graph); + + if (split == scc_graph->n) + return isl_scc_graph_chain(scc_graph, node); + + filters = extract_split_scc(scc_graph, split); + node = isl_schedule_node_insert_sequence(node, filters); + + isl_scc_graph_init_component(scc_graph); + + i = 0; + if (split > 0) + node = detect_components_at(scc_graph, 0, split, node, i++); + node = isl_schedule_node_grandchild(node, i++, 0); + node = isl_scc_graph_finish_band(scc_graph, node, split); + node = isl_schedule_node_grandparent(node); + if (split + 1 < scc_graph->n) + node = detect_components_at(scc_graph, + split + 1, scc_graph->n - (split + 1), node, i++); + + node = isl_schedule_node_sequence_splice_children(node); + + return node; +} diff --git a/polly/lib/External/isl/isl_scheduler_scc.h b/polly/lib/External/isl/isl_scheduler_scc.h new file mode 100644 index 0000000..e92c5e1 --- /dev/null +++ b/polly/lib/External/isl/isl_scheduler_scc.h @@ -0,0 +1,19 @@ +#ifndef ISL_SCHEDULER_SCC_H +#define ISL_SCHEDULER_SCC_H + +#include + +#include "isl_scheduler.h" +#include "isl_scheduler_clustering.h" + +struct isl_scc_graph; + +struct isl_scc_graph *isl_scc_graph_from_sched_graph(isl_ctx *ctx, + struct isl_sched_graph *graph, struct isl_clustering *c); +__isl_give isl_schedule_node *isl_scc_graph_decompose( + struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node); +struct isl_scc_graph *isl_scc_graph_free(struct isl_scc_graph *scc_graph); + +void isl_scc_graph_dump(struct isl_scc_graph *scc_graph); + +#endif diff --git a/polly/lib/External/isl/isl_set_to_ast_graft_list.c b/polly/lib/External/isl/isl_set_to_ast_graft_list.c index 86206d0..6067821 100644 --- a/polly/lib/External/isl/isl_set_to_ast_graft_list.c +++ b/polly/lib/External/isl/isl_set_to_ast_graft_list.c @@ -9,9 +9,13 @@ #define ISL_VAL isl_ast_graft_list #define ISL_HMAP_SUFFIX set_to_ast_graft_list #define ISL_HMAP isl_set_to_ast_graft_list +#define ISL_HMAP_IS_EQUAL isl_set_to_ast_graft_list_plain_is_equal #define ISL_KEY_IS_EQUAL isl_set_plain_is_equal #define ISL_VAL_IS_EQUAL isl_ast_graft_list_is_identical #define ISL_KEY_PRINT isl_printer_print_set #define ISL_VAL_PRINT isl_printer_print_ast_graft_list +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_KEY_READ isl_stream_read_set +#define ISL_VAL_READ isl_stream_read_ast_graft_list #include diff --git a/polly/lib/External/isl/isl_set_to_ast_graft_list.h b/polly/lib/External/isl/isl_set_to_ast_graft_list.h index 862afaa..cca3cbb 100644 --- a/polly/lib/External/isl/isl_set_to_ast_graft_list.h +++ b/polly/lib/External/isl/isl_set_to_ast_graft_list.h @@ -9,10 +9,14 @@ #define ISL_VAL isl_ast_graft_list #define ISL_HMAP_SUFFIX set_to_ast_graft_list #define ISL_HMAP isl_set_to_ast_graft_list +#define ISL_HMAP_HAVE_READ_FROM_STR +#define ISL_HMAP_IS_EQUAL isl_set_to_ast_graft_list_plain_is_equal #include #undef ISL_KEY #undef ISL_VAL #undef ISL_HMAP_SUFFIX #undef ISL_HMAP +#undef ISL_HMAP_HAVE_READ_FROM_STR +#undef ISL_HMAP_IS_EQUAL #endif diff --git a/polly/lib/External/isl/isl_space.c b/polly/lib/External/isl/isl_space.c index fd67a89..16c7d64 100644 --- a/polly/lib/External/isl/isl_space.c +++ b/polly/lib/External/isl/isl_space.c @@ -390,7 +390,7 @@ static __isl_give isl_space *copy_ids(__isl_take isl_space *dst, return dst; } -__isl_take isl_space *isl_space_dup(__isl_keep isl_space *space) +__isl_give isl_space *isl_space_dup(__isl_keep isl_space *space) { isl_space *dup; if (!space) @@ -476,9 +476,8 @@ __isl_null isl_space *isl_space_free(__isl_take isl_space *space) static int name_ok(isl_ctx *ctx, const char *s) { char *p; - long dummy; - dummy = strtol(s, &p, 0); + strtol(s, &p, 0); if (p != s) isl_die(ctx, isl_error_invalid, "name looks like a number", return 0); @@ -1860,6 +1859,38 @@ __isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space) return space; } +/* Given a space of the form [A -> B] -> C, return the space A. + */ +__isl_give isl_space *isl_space_domain_wrapped_domain( + __isl_take isl_space *space) +{ + return isl_space_factor_domain(isl_space_domain(space)); +} + +/* Given a space of the form [A -> B] -> C, return the space B. + */ +__isl_give isl_space *isl_space_domain_wrapped_range( + __isl_take isl_space *space) +{ + return isl_space_factor_range(isl_space_domain(space)); +} + +/* Given a space of the form A -> [B -> C], return the space B. + */ +__isl_give isl_space *isl_space_range_wrapped_domain( + __isl_take isl_space *space) +{ + return isl_space_factor_domain(isl_space_range(space)); +} + +/* Given a space of the form A -> [B -> C], return the space C. + */ +__isl_give isl_space *isl_space_range_wrapped_range( + __isl_take isl_space *space) +{ + return isl_space_factor_range(isl_space_range(space)); +} + __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space) { isl_ctx *ctx; @@ -3238,7 +3269,7 @@ __isl_give isl_space *isl_space_align_params(__isl_take isl_space *space1, goto error; exp = isl_parameter_alignment_reordering(space1, space2); - exp = isl_reordering_extend_space(exp, space1); + isl_space_free(space1); isl_space_free(space2); space1 = isl_reordering_get_space(exp); isl_reordering_free(exp); diff --git a/polly/lib/External/isl/isl_space_private.h b/polly/lib/External/isl/isl_space_private.h index 140749e..dd656d8 100644 --- a/polly/lib/External/isl/isl_space_private.h +++ b/polly/lib/External/isl/isl_space_private.h @@ -4,6 +4,7 @@ #include #include #include +#include struct isl_name; struct isl_space { @@ -97,4 +98,6 @@ __isl_give isl_space *isl_space_unbind_params_insert_domain( int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2); +__isl_give isl_space *isl_stream_read_space(__isl_keep isl_stream *s); + #endif diff --git a/polly/lib/External/isl/isl_stream.c b/polly/lib/External/isl/isl_stream.c index 1052360..9fffd45 100644 --- a/polly/lib/External/isl/isl_stream.c +++ b/polly/lib/External/isl/isl_stream.c @@ -101,6 +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); } +/* Does the given token have a string representation? + */ +isl_bool isl_token_has_str(struct isl_token *tok) +{ + if (!tok) + return isl_bool_error; + return isl_bool_ok(tok->u.s != NULL); +} + /* 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) @@ -446,15 +455,13 @@ static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line) } if (c != -1) isl_stream_ungetc(s, c); - if (!isdigit(c)) { - tok = isl_token_new(s->ctx, line, col, old_line != line); - if (!tok) - return NULL; - tok->type = (enum isl_token_type) '-'; - return tok; - } + tok = isl_token_new(s->ctx, line, col, old_line != line); + if (!tok) + return NULL; + tok->type = (enum isl_token_type) '-'; + return tok; } - if (c == '-' || isdigit(c)) { + if (isdigit(c)) { int minus = c == '-'; tok = isl_token_new(s->ctx, line, col, old_line != line); if (!tok) @@ -752,7 +759,7 @@ int isl_stream_eat(__isl_keep isl_stream *s, int type) return 0; } isl_stream_error(s, tok, "expecting other token"); - isl_stream_push_token(s, tok); + isl_token_free(tok); return -1; } @@ -847,19 +854,19 @@ static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state) } /* Remove the innermost active YAML element from the stack. - * Return 0 on success and -1 on failure. + * Return isl_stat_ok on success and isl_stat_error on failure. */ -static int pop_state(__isl_keep isl_stream *s) +static isl_stat pop_state(__isl_keep isl_stream *s) { if (!s) - return -1; + return isl_stat_error; if (s->yaml_depth < 1) isl_die(isl_stream_get_ctx(s), isl_error_invalid, - "not in YAML construct", return -1); + "not in YAML construct", return isl_stat_error); s->yaml_depth--; - return 0; + return isl_stat_ok; } /* Set the state of the innermost active YAML element to "state". @@ -892,17 +899,17 @@ static enum isl_yaml_state current_state(__isl_keep isl_stream *s) /* 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. + * that the current element is in flow format. */ -static int set_yaml_indent(__isl_keep isl_stream *s, int indent) +static isl_stat 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); + "not in YAML element", return isl_stat_error); s->yaml_indent[s->yaml_depth - 1] = indent; - return 0; + return isl_stat_ok; } /* Return the indentation of the innermost active YAML element @@ -918,9 +925,9 @@ static int get_yaml_indent(__isl_keep isl_stream *s) } /* 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. + * Return isl_bool_true if successful. + * Return isl_bool_false if we are at the end of the innermost level. + * Return isl_bool_error 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 @@ -956,7 +963,7 @@ static int get_yaml_indent(__isl_keep isl_stream *s) * 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) +isl_bool isl_stream_yaml_next(__isl_keep isl_stream *s) { struct isl_token *tok; enum isl_yaml_state state; @@ -965,93 +972,93 @@ int isl_stream_yaml_next(__isl_keep isl_stream *s) state = current_state(s); if (state == isl_yaml_none) isl_die(s->ctx, isl_error_invalid, - "not in YAML element", return -1); + "not in YAML element", return isl_bool_error); 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; + return isl_bool_false; if (update_state(s, isl_yaml_mapping_key) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; 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; + return isl_bool_error; } if (tok->type == ':') { isl_token_free(tok); if (update_state(s, isl_yaml_mapping_val) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; } isl_stream_error(s, tok, "expecting ':'"); isl_stream_push_token(s, tok); - return -1; + return isl_bool_error; case isl_yaml_mapping_val: if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { if (!isl_stream_eat_if_available(s, ',')) - return 0; + return isl_bool_false; if (update_state(s, isl_yaml_mapping_key) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; } tok = isl_stream_next_token(s); if (!tok) - return 0; + return isl_bool_false; indent = tok->col - 1; isl_stream_push_token(s, tok); if (indent < get_yaml_indent(s)) - return 0; + return isl_bool_false; if (update_state(s, isl_yaml_mapping_key) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; case isl_yaml_sequence_start: if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { if (isl_stream_next_token_is(s, ']')) - return 0; + return isl_bool_false; if (update_state(s, isl_yaml_sequence) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; } tok = isl_stream_next_token(s); if (!tok) { if (s->eof) isl_stream_error(s, NULL, "unexpected EOF"); - return -1; + return isl_bool_error; } if (tok->type == '-') { isl_token_free(tok); if (update_state(s, isl_yaml_sequence) < 0) - return -1; - return 1; + return isl_bool_error; + return isl_bool_true; } isl_stream_error(s, tok, "expecting '-'"); isl_stream_push_token(s, tok); - return 0; + return isl_bool_false; case isl_yaml_sequence: if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) - return isl_stream_eat_if_available(s, ','); + return isl_bool_ok(isl_stream_eat_if_available(s, ',')); tok = isl_stream_next_token(s); if (!tok) - return 0; + return isl_bool_false; indent = tok->col - 1; if (indent < get_yaml_indent(s) || tok->type != '-') { isl_stream_push_token(s, tok); - return 0; + return isl_bool_false; } isl_token_free(tok); - return 1; + return isl_bool_true; default: isl_die(s->ctx, isl_error_internal, - "unexpected state", return 0); + "unexpected state", return isl_bool_error); } } /* Start reading a YAML mapping. - * Return 0 on success and -1 on error. + * Return isl_stat_ok on success and isl_stat_error 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 @@ -1060,19 +1067,19 @@ int isl_stream_yaml_next(__isl_keep isl_stream *s) * 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) +isl_stat 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; + return isl_stat_error; tok = isl_stream_next_token(s); if (!tok) { if (s->eof) isl_stream_error(s, NULL, "unexpected EOF"); - return -1; + return isl_stat_error; } if (isl_token_get_type(tok) == '{') { isl_token_free(tok); @@ -1085,21 +1092,21 @@ int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s) } /* Finish reading a YAML mapping. - * Return 0 on success and -1 on error. + * Return isl_stat_ok on success and isl_stat_error 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) +isl_stat 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 isl_stat_error; return pop_state(s); } @@ -1112,13 +1119,13 @@ int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s) if (indent >= get_yaml_indent(s)) isl_die(isl_stream_get_ctx(s), isl_error_invalid, - "mapping not finished", return -1); + "mapping not finished", return isl_stat_error); return pop_state(s); } /* Start reading a YAML sequence. - * Return 0 on success and -1 on error. + * Return isl_stat_ok on success and isl_stat_error 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 @@ -1129,19 +1136,19 @@ int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s) * 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) +isl_stat 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; + return isl_stat_error; tok = isl_stream_next_token(s); if (!tok) { if (s->eof) isl_stream_error(s, NULL, "unexpected EOF"); - return -1; + return isl_stat_error; } if (isl_token_get_type(tok) == '[') { isl_token_free(tok); @@ -1154,7 +1161,7 @@ int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s) } /* Finish reading a YAML sequence. - * Return 0 on success and -1 on error. + * Return isl_stat_ok on success and isl_stat_error on error. * * If the sequence started with a '[', then we expect a ']' to close * the sequence. @@ -1162,7 +1169,7 @@ int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s) * 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) +isl_stat isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) { struct isl_token *tok; int indent; @@ -1170,7 +1177,7 @@ int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) { if (isl_stream_eat(s, ']') < 0) - return -1; + return isl_stat_error; return pop_state(s); } @@ -1184,7 +1191,7 @@ int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s) if (indent >= get_yaml_indent(s) && dash) isl_die(isl_stream_get_ctx(s), isl_error_invalid, - "sequence not finished", return -1); + "sequence not finished", return isl_stat_error); return pop_state(s); } diff --git a/polly/lib/External/isl/isl_stream_read_pw_with_params_templ.c b/polly/lib/External/isl/isl_stream_read_pw_with_params_templ.c new file mode 100644 index 0000000..0e88998 --- /dev/null +++ b/polly/lib/External/isl/isl_stream_read_pw_with_params_templ.c @@ -0,0 +1,30 @@ +/* + * Copyright 2011 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#undef TYPE +#define TYPE CAT(isl_pw_,BASE) + +/* Read an object of type "TYPE" from "s" with parameter domain "dom". + * "v" contains a description of the identifiers parsed so far. + */ +static __isl_give TYPE *FN(isl_stream_read_with_params_pw,BASE)( + __isl_keep isl_stream *s, __isl_keep isl_set *dom, struct vars *v) +{ + TYPE *obj; + + obj = FN(read_conditional,BASE)(s, isl_set_copy(dom), v); + + while (isl_stream_eat_if_available(s, ';')) { + TYPE *obj2; + + obj2 = FN(read_conditional,BASE)(s, isl_set_copy(dom), v); + obj = FN(TYPE,union_add)(obj, obj2); + } + + return obj; +} diff --git a/polly/lib/External/isl/isl_stream_read_with_params_templ.c b/polly/lib/External/isl/isl_stream_read_with_params_templ.c new file mode 100644 index 0000000..59111c6 --- /dev/null +++ b/polly/lib/External/isl/isl_stream_read_with_params_templ.c @@ -0,0 +1,52 @@ +/* + * Copyright 2011 Sven Verdoolaege + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege. + */ + +#define xCAT(A,B) A ## B +#define CAT(A,B) xCAT(A,B) +#undef TYPE +#define TYPE CAT(isl_,TYPE_BASE) + +/* Read an object of type "TYPE" from "s". + * + * In particular, first read the parameters and the opening brace. + * Then read the body that is specific to the object type. + * Finally, read the closing brace. + */ +__isl_give TYPE *FN(isl_stream_read,TYPE_BASE)(__isl_keep isl_stream *s) +{ + struct vars *v; + isl_set *dom; + TYPE *obj = NULL; + + 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_stream_eat(s, '{')) + goto error; + + obj = FN(isl_stream_read_with_params,TYPE_BASE)(s, dom, v); + + if (isl_stream_eat(s, '}')) + goto error; + + vars_free(v); + isl_set_free(dom); + return obj; +error: + vars_free(v); + isl_set_free(dom); + FN(TYPE,free)(obj); + return NULL; +} diff --git a/polly/lib/External/isl/isl_stride.c b/polly/lib/External/isl/isl_stride.c index 2d1c027..df5cacc 100644 --- a/polly/lib/External/isl/isl_stride.c +++ b/polly/lib/External/isl/isl_stride.c @@ -143,13 +143,9 @@ struct isl_detect_stride_data { static isl_stat set_stride(struct isl_detect_stride_data *data, __isl_take isl_val *stride, __isl_take isl_aff *offset) { - int pos; - if (!stride || !offset) goto error; - pos = data->pos; - if (data->found) { isl_val *stride2, *a, *b, *g; isl_aff *offset2; diff --git a/polly/lib/External/isl/isl_tab.c b/polly/lib/External/isl/isl_tab.c index 4152735..5f528f9 100644 --- a/polly/lib/External/isl/isl_tab.c +++ b/polly/lib/External/isl/isl_tab.c @@ -1255,9 +1255,9 @@ static void check_table(struct isl_tab *tab) * the sample value will also be non-negative. * * If "var" is manifestly unbounded wrt positive values, we are done. - * Otherwise, we pivot the variable up to a row if needed - * Then we continue pivoting down until either - * - no more down pivots can be performed + * Otherwise, we pivot the variable up to a row if needed. + * Then we continue pivoting up until either + * - no more up pivots can be performed * - the sample value is positive * - the variable is pivoted into a manifestly unbounded column */ diff --git a/polly/lib/External/isl/isl_tab.h b/polly/lib/External/isl/isl_tab.h index b580245..a7df7ab 100644 --- a/polly/lib/External/isl/isl_tab.h +++ b/polly/lib/External/isl/isl_tab.h @@ -10,6 +10,7 @@ #ifndef ISL_TAB_H #define ISL_TAB_H +#include "isl_int.h" #include #include #include diff --git a/polly/lib/External/isl/isl_test.c b/polly/lib/External/isl/isl_test.c index 2d09650..7048302 100644 --- a/polly/lib/External/isl/isl_test.c +++ b/polly/lib/External/isl/isl_test.c @@ -3,6 +3,7 @@ * Copyright 2010 INRIA Saclay * Copyright 2012-2013 Ecole Normale Superieure * Copyright 2014 INRIA Rocquencourt + * Copyright 2022 Cerebras Systems * * Use of this software is governed by the MIT license * @@ -13,6 +14,7 @@ * 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 + * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA */ #include @@ -165,6 +167,7 @@ static const char *reparse_pw_multi_aff_tests[] = { "{ [x, x] -> [x % 4] }", "{ [x, x + 1] -> [x % 4] : x mod 3 = 1 }", "{ [x, x mod 2] -> [x % 4] }", + "{ [a] -> [a//2] : exists (e0: 8*floor((-a + e0)/8) <= -8 - a + 8e0) }", }; #undef BASE @@ -441,6 +444,34 @@ struct { "{ [x, floor(x/4)] }" }, { "{ [10//4] }", "{ [2] }" }, + { "{ [-1//4] }", + "{ [-1] }" }, + { "{ [0-1//4] }", + "{ [0] }" }, + { "{ [- 1//4] }", + "{ [-1] }" }, + { "{ [0 - 1//4] }", + "{ [0] }" }, + { "{ [0--1//4] }", + "{ [1] }" }, + { "{ [0 - -1//4] }", + "{ [1] }" }, + { "{ [-2^2:2^2-1] }", + "{ [-4:3] }" }, + { "{ [2*-2] }", + "{ [-4] }" }, + { "{ [i,i*-2] }", + "{ [i,-2i] }" }, + { "[a, b, c, d] -> { [max(a,b,c,d)] }", + "[a, b, c, d] -> { [a] : b < a and c < a and d < a; " + "[b] : b >= a and c < b and d < b; " + "[c] : c >= a and c >= b and d < c; " + "[d] : d >= a and d >= b and d >= c }" }, + { "[a, b, c, d] -> { [min(a,b,c,d)] }", + "[a, b, c, d] -> { [a] : b >= a and c >= a and d >= a; " + "[b] : b < a and c >= b and d >= b; " + "[c] : c < b and c < a and d >= c; " + "[d] : d < c and d < b and d < a }" }, }; int test_parse(struct isl_ctx *ctx) @@ -2377,6 +2408,7 @@ struct { { 0, "{ [0:1, 0:1]; [0, 2:3] }" }, { 1, "{ [a] : (a = 0 or ((1 + a) mod 2 = 0 and 0 < a <= 15) or " "((a) mod 2 = 0 and 0 < a <= 15)) }" }, + { 1, "{ rat: [0:2]; rat: [1:3] }" }, }; /* A specialized coalescing test case that would result @@ -2419,7 +2451,7 @@ static int test_coalesce_special(struct isl_ctx *ctx) } /* Check that the union of the basic sets described by "str1" and "str2" - * can be coalesced. + * can be coalesced and that the result is equal to the union. * The explicit call to isl_basic_set_union prevents the implicit * equality constraints in the basic maps from being detected prior * to the call to isl_set_coalesce, at least at the point @@ -2429,13 +2461,28 @@ static isl_stat test_coalesce_union(isl_ctx *ctx, const char *str1, const char *str2) { isl_basic_set *bset1, *bset2; - isl_set *set; + isl_set *set, *set2; + isl_bool equal; bset1 = isl_basic_set_read_from_str(ctx, str1); bset2 = isl_basic_set_read_from_str(ctx, str2); set = isl_basic_set_union(bset1, bset2); set = isl_set_coalesce(set); + + bset1 = isl_basic_set_read_from_str(ctx, str1); + bset2 = isl_basic_set_read_from_str(ctx, str2); + set2 = isl_basic_set_union(bset1, bset2); + + equal = isl_set_is_equal(set, set2); isl_set_free(set); + isl_set_free(set2); + + if (equal < 0) + return isl_stat_error; + if (!equal) + isl_die(ctx, isl_error_unknown, + "coalesced set not equal to input", + return isl_stat_error); return isl_stat_non_null(set); } @@ -2585,6 +2632,25 @@ static isl_stat test_coalesce_special7(isl_ctx *ctx) return test_coalesce_union(ctx, str1, str2); } +/* A specialized coalescing test case that would result in a disjunct + * getting dropped in an earlier version of isl. Use test_coalesce_union with + * an explicit call to isl_basic_set_union to prevent the implicit + * equality constraints in the basic maps from being detected prior + * to the call to isl_set_coalesce, at least at the point + * where this test case was introduced. + */ +static isl_stat test_coalesce_special8(isl_ctx *ctx) +{ + const char *str1; + const char *str2; + + str1 = "{ [a, b, c] : 2c <= -a and b >= -a and b <= 5 and " + "6c > -7a and 11c >= -5a - b and a <= 3 }"; + str2 = "{ [a, b, c] : 6c > -7a and b >= -a and b <= 5 and " + "11c >= -5a - b and a >= 4 and 2b <= a and 2c <= -a }"; + return test_coalesce_union(ctx, str1, str2); +} + /* 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. @@ -2616,7 +2682,8 @@ static int test_coalesce(struct isl_ctx *ctx) return -1; if (test_coalesce_special7(ctx) < 0) return -1; - + if (test_coalesce_special8(ctx) < 0) + return -1; return 0; } @@ -3725,6 +3792,8 @@ struct { { "{ [i] -> ([(i)/2]) }", "{ [k] : exists a : k = 2a+1 }", "{ [i] -> -1/2 + 1/2 * i }" }, { "{ [i] -> i^2 : i != 0 }", "{ [i] : i != 0 }", "{ [i] -> i^2 }" }, + { "{ [i] -> i^2 : i > 0; [i] -> i^2 : i < 0 }", "{ [i] : i != 0 }", + "{ [i] -> i^2 }" }, }; /* Perform some basic isl_pw_qpolynomial_gist tests. @@ -8178,12 +8247,38 @@ static int test_union_map(isl_ctx *ctx) return 0; } +#undef BASE +#define BASE union_pw_qpolynomial +#include "isl_test_plain_equal_templ.c" + +/* Check that the result of applying "fn" to "a" and "b" + * in (obviously) equal to "res". + */ +static isl_stat test_union_pw_op(isl_ctx *ctx, const char *a, const char *b, + __isl_give isl_union_pw_qpolynomial *(*fn)( + __isl_take isl_union_pw_qpolynomial *upwqp1, + __isl_take isl_union_pw_qpolynomial *upwqp2), + const char *res) +{ + isl_stat r; + isl_union_pw_qpolynomial *upwqp1, *upwqp2; + + upwqp1 = isl_union_pw_qpolynomial_read_from_str(ctx, a); + upwqp2 = isl_union_pw_qpolynomial_read_from_str(ctx, b); + upwqp1 = fn(upwqp1, upwqp2); + r = union_pw_qpolynomial_check_plain_equal(upwqp1, res); + isl_union_pw_qpolynomial_free(upwqp1); + + return r; +} + int test_union_pw(isl_ctx *ctx) { int equal; const char *str; isl_union_set *uset; isl_union_pw_qpolynomial *upwqp1, *upwqp2; + const char *a, *b; str = "{ [x] -> x^2 }"; upwqp1 = isl_union_pw_qpolynomial_read_from_str(ctx, str); @@ -8199,6 +8294,25 @@ int test_union_pw(isl_ctx *ctx) if (!equal) isl_die(ctx, isl_error_unknown, "unexpected result", return -1); + a = "{ A[x] -> x^2 : x >= 0; B[x] -> x }"; + b = "{ A[x] -> x }"; + str = "{ A[x] -> x^2 + x : x >= 0; A[x] -> x : x < 0; B[x] -> x }"; + if (test_union_pw_op(ctx, a, b, &isl_union_pw_qpolynomial_add, str) < 0) + return -1; + str = "{ A[x] -> x^2 - x : x >= 0; A[x] -> -x : x < 0; B[x] -> x }"; + if (test_union_pw_op(ctx, a, b, &isl_union_pw_qpolynomial_sub, str) < 0) + return -1; + + str = "{ A[x] -> 0 }"; + a = "{ A[x] -> 1 }"; + b = "{ A[x] -> -1 }"; + if (test_union_pw_op(ctx, a, b, &isl_union_pw_qpolynomial_add, str) < 0) + return -1; + a = "{ A[x] -> 1 }"; + b = "{ A[x] -> 1 }"; + if (test_union_pw_op(ctx, a, b, &isl_union_pw_qpolynomial_sub, str) < 0) + return -1; + return 0; } @@ -8552,6 +8666,7 @@ struct { { "{ [i] -> [i] : i mod 2 = 0 }", "{ [4] }", "4" }, { "{ [i] -> [i] : i mod 2 = 0 }", "{ [3] }", "NaN" }, { "{ [i] -> [i] : i mod 2 = 0 }", "{ [x] : false }", "NaN" }, + { "[m, n] -> { [2m + 3n] }", "[n=1, m=10] -> { : }", "23" }, }; /* Perform basic isl_pw_aff_eval tests. @@ -8807,25 +8922,6 @@ static int test_empty_projection(isl_ctx *ctx) return 0; } -int test_fixed_power(isl_ctx *ctx) -{ - const char *str; - isl_map *map; - isl_val *exp; - int equal; - - str = "{ [i] -> [i + 1] }"; - map = isl_map_read_from_str(ctx, str); - exp = isl_val_int_from_si(ctx, 23); - map = isl_map_fixed_power_val(map, exp); - equal = map_check_equal(map, "{ [i] -> [i + 23] }"); - isl_map_free(map); - if (equal < 0) - return -1; - - return 0; -} - int test_slice(isl_ctx *ctx) { const char *str; @@ -9592,14 +9688,58 @@ static __isl_give isl_ast_node *after_for(__isl_take isl_ast_node *node, return node; } +/* This function is called after node in the AST generated + * from test_ast_gen1. + * + * Increment the count in "user" if this is a for node and + * return true to indicate that descendant should also be visited. + */ +static isl_bool count_for(__isl_keep isl_ast_node *node, void *user) +{ + int *count = user; + + if (isl_ast_node_get_type(node) == isl_ast_node_for) + ++*count; + + return isl_bool_true; +} + +/* If "node" is a block node, then replace it by its first child. + */ +static __isl_give isl_ast_node *select_first(__isl_take isl_ast_node *node, + void *user) +{ + isl_ast_node_list *children; + isl_ast_node *child; + + if (isl_ast_node_get_type(node) != isl_ast_node_block) + return node; + + children = isl_ast_node_block_get_children(node); + child = isl_ast_node_list_get_at(children, 0); + isl_ast_node_list_free(children); + isl_ast_node_free(node); + + return child; +} + /* Check that the before_each_for and after_each_for callbacks * are called for each for loop in the generated code, * that they are called in the right order and that the isl_id * returned from the before_each_for callback is attached to * the isl_ast_node passed to the corresponding after_each_for call. + * + * Additionally, check the basic functionality of + * isl_ast_node_foreach_descendant_top_down by counting the number + * of for loops in the resulting AST, + * as well as that of isl_ast_node_map_descendant_bottom_up + * by replacing the block node by its first child and + * counting the number of for loops again. */ -static int test_ast_gen1(isl_ctx *ctx) +static isl_stat test_ast_gen1(isl_ctx *ctx) { + int count = 0; + int modified_count = 0; const char *str; isl_set *set; isl_union_map *schedule; @@ -9623,16 +9763,33 @@ static int test_ast_gen1(isl_ctx *ctx) &after_for, &data); tree = isl_ast_build_node_from_schedule_map(build, schedule); isl_ast_build_free(build); + + if (isl_ast_node_foreach_descendant_top_down(tree, + &count_for, &count) < 0) + tree = isl_ast_node_free(tree); + + tree = isl_ast_node_map_descendant_bottom_up(tree, &select_first, NULL); + + if (isl_ast_node_foreach_descendant_top_down(tree, &count_for, + &modified_count) < 0) + tree = isl_ast_node_free(tree); + if (!tree) - return -1; + return isl_stat_error; isl_ast_node_free(tree); - if (data.before != 3 || data.after != 3) + if (data.before != 3 || data.after != 3 || count != 3) isl_die(ctx, isl_error_unknown, - "unexpected number of for nodes", return -1); + "unexpected number of for nodes", + return isl_stat_error); - return 0; + if (modified_count != 2) + isl_die(ctx, isl_error_unknown, + "unexpected number of for nodes after changes", + return isl_stat_error); + + return isl_stat_ok; } /* Check that the AST generator handles domains that are integrally disjoint @@ -10270,8 +10427,7 @@ static int test_schedule_tree_prefix(isl_ctx *ctx) filters = isl_union_set_list_add(filters, uset); node = isl_schedule_node_insert_sequence(node, filters); - node = isl_schedule_node_child(node, 0); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, 0, 0); mupa = isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node); str = "([] : { S1[i,j] : i > j })"; mupa2 = isl_multi_union_pw_aff_read_from_str(ctx, str); @@ -10386,8 +10542,7 @@ static int test_schedule_tree_group_2(isl_ctx *ctx) uset = isl_union_set_read_from_str(ctx, str); filters = isl_union_set_list_add(filters, uset); node = isl_schedule_node_insert_sequence(node, filters); - node = isl_schedule_node_child(node, 1); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, 1, 0); str = "{ S2[i,j] }"; uset = isl_union_set_read_from_str(ctx, str); filters = isl_union_set_list_from_union_set(uset); @@ -10402,12 +10557,10 @@ static int test_schedule_tree_group_2(isl_ctx *ctx) umap1 = isl_union_map_intersect_domain(umap1, uset); isl_schedule_free(schedule); - node = isl_schedule_node_parent(node); - node = isl_schedule_node_parent(node); + node = isl_schedule_node_grandparent(node); id = isl_id_alloc(ctx, "group1", NULL); node = isl_schedule_node_group(node, id); - node = isl_schedule_node_child(node, 1); - node = isl_schedule_node_child(node, 0); + node = isl_schedule_node_grandchild(node, 1, 0); id = isl_id_alloc(ctx, "group2", NULL); node = isl_schedule_node_group(node, id); @@ -10809,7 +10962,6 @@ struct { { "residue class", &test_residue_class }, { "div", &test_div }, { "slice", &test_slice }, - { "fixed power", &test_fixed_power }, { "sample", &test_sample }, { "empty projection", &test_empty_projection }, { "output", &test_output }, diff --git a/polly/lib/External/isl/isl_test2.cc b/polly/lib/External/isl/isl_test2.cc index 7b64d6f..54e7ee5 100644 --- a/polly/lib/External/isl/isl_test2.cc +++ b/polly/lib/External/isl/isl_test2.cc @@ -1,3 +1,22 @@ +/* + * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2010 INRIA Saclay + * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2014 INRIA Rocquencourt + * Copyright 2021-2022 Cerebras Systems + * + * Use of this software is governed by the MIT license + * + * Written by Sven Verdoolaege, K.U.Leuven, Departement + * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium + * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, + * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France + * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, + * B.P. 105 - 78153 Le Chesnay, France + * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA + */ + #include #include @@ -28,6 +47,30 @@ static binary_fn const arg(const binary_fn &fn) return fn; } +/* A ternary isl function that appears in the C++ bindings + * as a binary method in a class T, taking extra arguments + * of type A1 and A2 and returning an object of type R. + */ +template +using ternary_fn = R (T::*)(A1, A2) const; + +/* A function for selecting an overload of a pointer to a binary C++ method + * based on the (first) argument type(s). + * The object type and the return type are meant to be deduced. + */ +template +static ternary_fn const arg(const ternary_fn &fn) +{ + return fn; +} + +/* A description of the input and the output of a unary operation. + */ +struct unary { + const char *arg; + const char *res; +}; + /* A description of the inputs and the output of a binary operation. */ struct binary { @@ -36,6 +79,15 @@ struct binary { const char *res; }; +/* A description of the inputs and the output of a ternary operation. + */ +struct ternary { + const char *arg1; + const char *arg2; + const char *arg3; + const char *res; +}; + /* A template function for checking whether two objects * of the same (isl) type are (obviously) equal. * The spelling depends on the isl type and @@ -61,6 +113,31 @@ static bool is_equal(const T &a, const T &b) isl::exception::throw_error(isl_error_invalid, msg, __FILE__, __LINE__) /* Run a sequence of tests of method "fn" with stringification "name" and + * with input and output described by "test", + * throwing an exception when an unexpected result is produced. + */ +template +static void test(isl::ctx ctx, R (T::*fn)() const, const std::string &name, + const std::vector &tests) +{ + for (const auto &test : tests) { + T obj(ctx, test.arg); + R expected(ctx, test.res); + const auto &res = (obj.*fn)(); + std::ostringstream ss; + + if (is_equal(expected, res)) + continue; + + ss << name << "(" << test.arg << ") =\n" + << res << "\n" + << "expecting:\n" + << expected; + THROW_INVALID(ss.str().c_str()); + } +} + +/* Run a sequence of tests of method "fn" with stringification "name" and * with inputs and output described by "test", * throwing an exception when an unexpected result is produced. */ @@ -86,11 +163,69 @@ static void test(isl::ctx ctx, R (T::*fn)(A1) const, const std::string &name, } } +/* Run a sequence of tests of method "fn" with stringification "name" and + * with inputs and output described by "test", + * throwing an exception when an unexpected result is produced. + */ +template +static void test(isl::ctx ctx, R (T::*fn)(A1, A2) const, + const std::string &name, const std::vector &tests) +{ + for (const auto &test : tests) { + T obj(ctx, test.arg1); + A1 arg1(ctx, test.arg2); + A2 arg2(ctx, test.arg3); + R expected(ctx, test.res); + const auto &res = (obj.*fn)(arg1, arg2); + std::ostringstream ss; + + if (is_equal(expected, res)) + continue; + + ss << name << "(" << test.arg1 << ", " << test.arg2 << ", " + << test.arg3 << ") =\n" + << res << "\n" + << "expecting:\n" + << expected; + THROW_INVALID(ss.str().c_str()); + } +} + /* A helper macro that calls test with as implicit initial argument "ctx" and * as extra argument a stringification of "FN". */ #define C(FN, ...) test(ctx, FN, #FN, __VA_ARGS__) +/* Perform some basic isl::space tests. + */ +static void test_space(isl::ctx ctx) +{ + C(&isl::space::domain, { + { "{ A[] -> B[] }", "{ A[] }" }, + { "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ A[C[] -> D[]] }" }, + }); + + C(&isl::space::range, { + { "{ A[] -> B[] }", "{ B[] }" }, + { "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ B[E[] -> F[]] }" }, + }); + + C(&isl::space::params, { + { "{ A[] -> B[] }", "{ : }" }, + { "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ : }" }, + }); +} + +/* Perform some basic conversion tests. + */ +static void test_conversion(isl::ctx ctx) +{ + C(&isl::multi_pw_aff::as_set, { + { "[n] -> { [] : n >= 0 } ", + "[n] -> { [] : n >= 0 } " }, + }); +} + /* Perform some basic preimage tests. */ static void test_preimage(isl::ctx ctx) @@ -157,11 +292,128 @@ static void test_preimage(isl::ctx ctx) }); } +/* Perform some basic fixed power tests. + */ +static void test_fixed_power(isl::ctx ctx) +{ + C(arg(&isl::map::fixed_power), { + { "{ [i] -> [i + 1] }", "23", + "{ [i] -> [i + 23] }" }, + { "{ [a = 0:1, b = 0:15, c = 0:1, d = 0:1, 0] -> [a, b, c, d, 1]; " + "[a = 0:1, b = 0:15, c = 0:1, 0, 1] -> [a, b, c, 1, 0]; " + "[a = 0:1, b = 0:15, 0, 1, 1] -> [a, b, 1, 0, 0]; " + "[a = 0:1, b = 0:14, 1, 1, 1] -> [a, 1 + b, 0, 0, 0]; " + "[0, 15, 1, 1, 1] -> [1, 0, 0, 0, 0] }", + "128", + "{ [0, b = 0:15, c = 0:1, d = 0:1, e = 0:1] -> [1, b, c, d, e] }" }, + }); +} + +/* Perform some basic intersection tests. + */ +static void test_intersect(isl::ctx ctx) +{ + C(&isl::union_map::intersect_domain_wrapped_domain, { + { "{ [A[x] -> B[y]] -> C[z]; [D[x] -> A[y]] -> E[z] }", + "{ A[0] }", + "{ [A[0] -> B[y]] -> C[z] }" }, + { "{ C[z] -> [A[x] -> B[y]]; E[z] -> [D[x] -> A[y]] }", + "{ A[0] }", + "{ }" }, + }); + + C(&isl::union_map::intersect_range_wrapped_domain, { + { "{ [A[x] -> B[y]] -> C[z]; [D[x] -> A[y]] -> E[z] }", + "{ A[0] }", + "{ }" }, + { "{ C[z] -> [A[x] -> B[y]]; E[z] -> [D[x] -> A[y]] }", + "{ A[0] }", + "{ C[z] -> [A[0] -> B[y]] }" }, + }); +} + +/* Perform some basic gist tests. + */ +static void test_gist(isl::ctx ctx) +{ + C(&isl::pw_aff::gist_params, { + { "[N] -> { D[x] -> [x] : N >= 0; D[x] -> [0] : N < 0 }", + "[N] -> { : N >= 0 }", + "[N] -> { D[x] -> [x] }" }, + }); +} + +/* Perform tests that project out parameters. + */ +static void test_project(isl::ctx ctx) +{ + C(arg(&isl::union_map::project_out_param), { + { "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }", "N", + "{ D[i] -> A[0:]; D[i] -> B[i] }" }, + { "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }", "M", + "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }" }, + }); + + C(arg(&isl::union_map::project_out_param), { + { "[M, N, O] -> { D[i] -> A[j] : i <= j < M, N, O }", "(M, N)", + "[O] -> { D[i] -> A[j] : i <= j < O }" }, + }); +} + +/* Perform some basic scaling tests. + */ +static void test_scale(isl::ctx ctx) +{ + C(arg(&isl::pw_multi_aff::scale), { + { "{ A[a] -> B[a, a + 1, a - 1] : a >= 0 }", "{ B[2, 7, 0] }", + "{ A[a] -> B[2a, 7a + 7, 0] : a >= 0 }" }, + }); + C(arg(&isl::pw_multi_aff::scale), { + { "{ A[a] -> B[1, a - 1] : a >= 0 }", "{ B[1/2, 7] }", + "{ A[a] -> B[1/2, 7a - 7] : a >= 0 }" }, + }); + + C(arg(&isl::pw_multi_aff::scale_down), { + { "{ A[a] -> B[a, a + 1] : a >= 0 }", "{ B[2, 7] }", + "{ A[a] -> B[a/2, (a + 1)/7] : a >= 0 }" }, + }); + C(arg(&isl::pw_multi_aff::scale_down), { + { "{ A[a] -> B[a, a - 1] : a >= 0 }", "{ B[2, 1/7] }", + "{ A[a] -> B[a/2, 7a - 7] : a >= 0 }" }, + }); +} + +/* Perform some basic isl::id_to_id tests. + */ +static void test_id_to_id(isl::ctx ctx) +{ + C((arg(&isl::id_to_id::set)), { + { "{ }", "a", "b", + "{ a: b }" }, + { "{ a: b }", "a", "b", + "{ a: b }" }, + { "{ a: c }", "a", "b", + "{ a: b }" }, + { "{ a: b }", "b", "a", + "{ a: b, b: a }" }, + { "{ a: b }", "b", "a", + "{ b: a, a: b }" }, + }); +} + /* The list of tests to perform. */ static std::vector> tests = { + { "space", &test_space }, + { "conversion", &test_conversion }, { "preimage", &test_preimage }, + { "fixed power", &test_fixed_power }, + { "intersect", &test_intersect }, + { "gist", &test_gist }, + { "project out parameters", &test_project }, + { "scale", &test_scale }, + { "id-to-id", &test_id_to_id }, }; /* Perform some basic checks by means of the C++ bindings. diff --git a/polly/lib/External/isl/isl_test_cpp.cc b/polly/lib/External/isl/isl_test_cpp.cc index d606a21..01308d1 100644 --- a/polly/lib/External/isl/isl_test_cpp.cc +++ b/polly/lib/External/isl/isl_test_cpp.cc @@ -12,6 +12,8 @@ #include #include +#include + #include #include @@ -114,6 +116,38 @@ static void test_foreach(isl::ctx ctx) assert(caught); } +/* Test the functionality of "foreach_scc" functions. + * + * In particular, test it on a list of elements that can be completely sorted + * but where two of the elements ("a" and "b") are incomparable. + */ +static void test_foreach_scc(isl::ctx ctx) +{ + isl::multi_pw_aff id; + isl::id_list list(ctx, 3); + isl::id_list sorted(ctx, 3); + std::map data = { + { "a", isl::map(ctx, "{ [0] -> [1] }") }, + { "b", isl::map(ctx, "{ [1] -> [0] }") }, + { "c", isl::map(ctx, "{ [i = 0:1] -> [i] }") }, + }; + + for (const auto &kvp: data) + list = list.add(kvp.first); + id = data.at("a").space().domain().identity_multi_pw_aff_on_domain(); + list.foreach_scc([&data, &id] (isl::id a, isl::id b) { + auto map = data.at(b.name()).apply_domain(data.at(a.name())); + return !map.lex_ge_at(id).is_empty(); + }, [&sorted] (isl::id_list scc) { + assert(scc.size() == 1); + sorted = sorted.concat(scc); + }); + assert(sorted.size() == 3); + assert(sorted.at(0).name() == "b"); + assert(sorted.at(1).name() == "c"); + assert(sorted.at(2).name() == "a"); +} + /* Test the functionality of "every" functions. * * In particular, test the generic functionality and @@ -313,6 +347,7 @@ static void test_typed(isl::ctx ctx) * - Different parameter types * - Different return types * - Foreach functions + * - Foreach SCC function * - Exceptions * - Spaces * - Schedule trees @@ -331,6 +366,7 @@ int main() test_parameters(ctx); test_return(ctx); test_foreach(ctx); + test_foreach_scc(ctx); test_every(ctx); test_exception(ctx); test_space(ctx); diff --git a/polly/lib/External/isl/isl_test_cpp17-checked.cc b/polly/lib/External/isl/isl_test_cpp17-checked.cc new file mode 100644 index 0000000..3c21398 --- /dev/null +++ b/polly/lib/External/isl/isl_test_cpp17-checked.cc @@ -0,0 +1,41 @@ +#include + +#include +#include + +#include +#include + +/* Select the "checked" interface. + */ +namespace isl { using namespace checked; } + +/* Print an error message and abort. + */ +static void die_impl(const char *file, int line, const char *message) +{ + std::cerr << file << ":" << line << ": " << message << "\n"; + exit(EXIT_FAILURE); +} + +#define die(msg) die_impl(__FILE__, __LINE__, msg) + +#include "isl_test_cpp17-generic.cc" + +/* Test the C++17 specific features of the isl checked C++ interface + * + * In particular, test + * - id::try_user + */ +int main() +{ + isl_ctx *ctx = isl_ctx_alloc(); + + isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); + + test_try_user(ctx); + + isl_ctx_free(ctx); + + return EXIT_SUCCESS; +} diff --git a/polly/lib/External/isl/isl_test_cpp17-generic.cc b/polly/lib/External/isl/isl_test_cpp17-generic.cc new file mode 100644 index 0000000..c6b4bab --- /dev/null +++ b/polly/lib/External/isl/isl_test_cpp17-generic.cc @@ -0,0 +1,68 @@ +/* A class that sets a boolean when an object of the class gets destroyed. + */ +struct S { + S(bool *freed) : freed(freed) {} + ~S(); + + bool *freed; +}; + +/* S destructor. + * + * Set the boolean, a pointer to which was passed to the constructor. + */ +S::~S() +{ + *freed = true; +} + +/* Construct an isl::id with an S object attached that sets *freed + * when it gets destroyed. + */ +static isl::id construct_id(isl::ctx ctx, bool *freed) +{ + auto s = std::make_shared(freed); + isl::id id(ctx, "S", s); + return id; +} + +/* Test id::try_user. + * + * In particular, check that the object attached to an identifier + * can be retrieved again, that trying to retrieve an object of the wrong type + * or trying to retrieve an object when no object was attached fails. + * Furthermore, check that the object attached to an identifier + * gets properly freed. + */ +static void test_try_user(isl::ctx ctx) +{ + isl::id id(ctx, "test", 5); + isl::id id2(ctx, "test2"); + + auto maybe_int = id.try_user(); + auto maybe_s = id.try_user>(); + auto maybe_int2 = id2.try_user(); + + if (!maybe_int) + die("integer cannot be retrieved from isl::id"); + if (maybe_int.value() != 5) + die("wrong integer retrieved from isl::id"); + if (maybe_s) + die("structure unexpectedly retrieved from isl::id"); + if (maybe_int2) + die("integer unexpectedly retrieved from isl::id"); + + bool freed = false; + { + isl::id id = construct_id(ctx, &freed); + if (freed) + die("data structure freed prematurely"); + auto maybe_s = id.try_user>(); + if (!maybe_s) + die("structure cannot be retrieved from isl::id"); + if (maybe_s.value()->freed != &freed) + die("invalid structure retrieved from isl::id"); + } + if (!freed) + die("data structure not freed"); +} diff --git a/polly/lib/External/isl/isl_test_cpp17.cc b/polly/lib/External/isl/isl_test_cpp17.cc new file mode 100644 index 0000000..5765a1f --- /dev/null +++ b/polly/lib/External/isl/isl_test_cpp17.cc @@ -0,0 +1,78 @@ +#include + +#include +#include + +#include +#include + +/* Throw a runtime exception. + */ +static void die_impl(const char *file, int line, const char *message) +{ + std::ostringstream ss; + ss << file << ":" << line << ": " << message; + throw std::runtime_error(ss.str()); +} + +#define die(msg) die_impl(__FILE__, __LINE__, msg) + +#include "isl_test_cpp17-generic.cc" + +/* Check that an isl::exception_invalid gets thrown by "fn". + */ +static void check_invalid(const std::function &fn) +{ + bool caught = false; + try { + fn(); + } catch (const isl::exception_invalid &e) { + caught = true; + } + if (!caught) + die("no invalid exception was generated"); +} + +/* Test id::user. + * + * In particular, check that the object attached to an identifier + * can be retrieved again and that retrieving an object of the wrong type + * or retrieving an object when no object was attached results in an exception. + */ +static void test_user(isl::ctx ctx) +{ + isl::id id(ctx, "test", 5); + isl::id id2(ctx, "test2"); + isl::id id3(ctx, "test3", std::string("s")); + + auto int_user = id.user(); + if (int_user != 5) + die("wrong integer retrieved from isl::id"); + auto s_user = id3.user(); + if (s_user != "s") + die("wrong string retrieved from isl::id"); + check_invalid([&id] () { id.user(); }); + check_invalid([&id2] () { id2.user(); }); + check_invalid([&id2] () { id2.user(); }); + check_invalid([&id3] () { id3.user(); }); +} + +/* Test the C++17 specific features of the (unchecked) isl C++ interface + * + * In particular, test + * - id::try_user + * - id::user + */ +int main() +{ + isl_ctx *ctx = isl_ctx_alloc(); + + isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); + + test_try_user(ctx); + test_user(ctx); + + isl_ctx_free(ctx); + + return EXIT_SUCCESS; +} diff --git a/polly/lib/External/isl/isl_test_python.py b/polly/lib/External/isl/isl_test_python.py index 443f5a1..3894ad1 100755 --- a/polly/lib/External/isl/isl_test_python.py +++ b/polly/lib/External/isl/isl_test_python.py @@ -159,6 +159,27 @@ def test_return(): test_return_bool() test_return_string() +# A class that is used to test isl.id.user. +# +class S: + def __init__(self): + self.value = 42 + +# Test isl.id.user. +# +# In particular, check that the object attached to an identifier +# can be retrieved again. +# +def test_user(): + id = isl.id("test", 5) + id2 = isl.id("test2") + id3 = isl.id("S", S()) + assert id.user() == 5, f"unexpected user object {id.user()}" + assert id2.user() is None, f"unexpected user object {id2.user()}" + s = id3.user() + assert isinstance(s, S), f"unexpected user object {s}" + assert s.value == 42, f"unexpected user object {s}" + # Test that foreach functions are modeled correctly. # # Verify that closures are correctly called as callback of a 'foreach' @@ -192,6 +213,36 @@ def test_foreach(): caught = True assert(caught) +# Test the functionality of "foreach_scc" functions. +# +# In particular, test it on a list of elements that can be completely sorted +# but where two of the elements ("a" and "b") are incomparable. +# +def test_foreach_scc(): + list = isl.id_list(3) + sorted = [isl.id_list(3)] + data = { + 'a' : isl.map("{ [0] -> [1] }"), + 'b' : isl.map("{ [1] -> [0] }"), + 'c' : isl.map("{ [i = 0:1] -> [i] }"), + } + for k, v in data.items(): + list = list.add(k) + id = data['a'].space().domain().identity_multi_pw_aff_on_domain() + def follows(a, b): + map = data[b.name()].apply_domain(data[a.name()]) + return not map.lex_ge_at(id).is_empty() + + def add_single(scc): + assert(scc.size() == 1) + sorted[0] = sorted[0].concat(scc) + + list.foreach_scc(follows, add_single) + assert(sorted[0].size() == 3) + assert(sorted[0].at(0).name() == "b") + assert(sorted[0].at(1).name() == "c") + assert(sorted[0].at(2).name() == "a") + # Test the functionality of "every" functions. # # In particular, test the generic functionality and @@ -431,7 +482,9 @@ def test_ast_build_expr(): # - Object construction # - Different parameter types # - Different return types +# - isl.id.user # - Foreach functions +# - Foreach SCC function # - Every functions # - Spaces # - Schedule trees @@ -441,7 +494,9 @@ def test_ast_build_expr(): test_constructors() test_parameters() test_return() +test_user() test_foreach() +test_foreach_scc() test_every() test_space() test_schedule_tree() diff --git a/polly/lib/External/isl/isl_type_check_match_range_multi_val.c b/polly/lib/External/isl/isl_type_check_match_range_multi_val.c new file mode 100644 index 0000000..3b60e4d --- /dev/null +++ b/polly/lib/External/isl/isl_type_check_match_range_multi_val.c @@ -0,0 +1,32 @@ +#define xFN(TYPE,NAME) TYPE ## _ ## NAME +#define FN(TYPE,NAME) xFN(TYPE,NAME) + +/* Does the range space of "obj" match the space of "mv" (ignoring parameters)? + */ +static isl_bool FN(TYPE,match_range_multi_val)(__isl_keep TYPE *obj, + __isl_keep isl_multi_val *mv) +{ + isl_space *space, *mv_space; + + space = FN(TYPE,peek_space)(obj); + mv_space = isl_multi_val_peek_space(mv); + return isl_space_tuple_is_equal(space, isl_dim_out, + mv_space, isl_dim_set); +} + +/* Check that the range space of "obj" matches the space of "mv" + * (ignoring parameters). + */ +static isl_stat FN(TYPE,check_match_range_multi_val)(__isl_keep TYPE *obj, + __isl_keep isl_multi_val *mv) +{ + isl_bool equal; + + equal = FN(TYPE,match_range_multi_val)(obj, mv); + if (equal < 0) + return isl_stat_error; + if (!equal) + isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid, + "spaces don't match", return isl_stat_error); + return isl_stat_ok; +} diff --git a/polly/lib/External/isl/isl_union_map.c b/polly/lib/External/isl/isl_union_map.c index 2ea129b..eaafe18 100644 --- a/polly/lib/External/isl/isl_union_map.c +++ b/polly/lib/External/isl/isl_union_map.c @@ -208,6 +208,18 @@ int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap, return isl_space_find_dim_by_name(umap->dim, type, name); } +/* Return the position of the parameter with id "id" in "umap". + * Return -1 if no such dimension can be found. + */ +static int isl_union_map_find_dim_by_id(__isl_keep isl_union_map *umap, + enum isl_dim_type type, __isl_keep isl_id *id) +{ + isl_space *space; + + space = isl_union_map_peek_space(umap); + return isl_space_find_dim_by_id(space, type, id); +} + __isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset) { return isl_union_map_get_space(uset); @@ -285,12 +297,11 @@ __isl_give isl_union_map *isl_union_map_align_params( __isl_take isl_union_map *umap, __isl_take isl_space *model) { struct isl_union_align data = { NULL, NULL }; + isl_space *space; isl_bool equal_params; - if (!umap || !model) - goto error; - - equal_params = isl_space_has_equal_params(umap->dim, model); + space = isl_union_map_peek_space(umap); + equal_params = isl_space_has_equal_params(space, model); if (equal_params < 0) goto error; if (equal_params) { @@ -298,13 +309,13 @@ __isl_give isl_union_map *isl_union_map_align_params( return umap; } - data.exp = isl_parameter_alignment_reordering(umap->dim, model); + data.exp = isl_parameter_alignment_reordering(space, model); if (!data.exp) goto error; data.res = isl_union_map_alloc(isl_reordering_get_space(data.exp), umap->table.n); - if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, + if (isl_hash_table_foreach(isl_union_map_get_ctx(umap), &umap->table, &align_entry, &data) < 0) goto error; @@ -1641,6 +1652,40 @@ error: return NULL; } +/* Intersect each map in "umap" in a space [A -> B] -> C + * with the corresponding set in "domain" in the space A and + * collect the results. + */ +__isl_give isl_union_map * +isl_union_map_intersect_domain_wrapped_domain_union_set( + __isl_take isl_union_map *umap, __isl_take isl_union_set *domain) +{ + struct isl_bin_op_control control = { + .filter = &isl_map_domain_is_wrapping, + .match_space = &isl_space_domain_wrapped_domain, + .fn_map = &isl_map_intersect_domain_wrapped_domain, + }; + + return gen_bin_op(umap, domain, &control); +} + +/* Intersect each map in "umap" in a space A -> [B -> C] + * with the corresponding set in "domain" in the space B and + * collect the results. + */ +__isl_give isl_union_map * +isl_union_map_intersect_range_wrapped_domain_union_set( + __isl_take isl_union_map *umap, __isl_take isl_union_set *domain) +{ + struct isl_bin_op_control control = { + .filter = &isl_map_range_is_wrapping, + .match_space = &isl_space_range_wrapped_domain, + .fn_map = &isl_map_intersect_range_wrapped_domain, + }; + + return gen_bin_op(umap, domain, &control); +} + __isl_give isl_union_map *isl_union_map_apply_range( __isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2) { @@ -3985,6 +4030,7 @@ __isl_give isl_union_map *isl_union_map_project_out( #undef TYPE #define TYPE isl_union_map #include "isl_project_out_all_params_templ.c" +#include "isl_project_out_param_templ.c" /* Turn the "n" dimensions of type "type", starting at "first" * into existentially quantified variables. diff --git a/polly/lib/External/isl/isl_union_print_templ.c b/polly/lib/External/isl/isl_union_print_templ.c new file mode 100644 index 0000000..3995a12 --- /dev/null +++ b/polly/lib/External/isl/isl_union_print_templ.c @@ -0,0 +1,69 @@ +/* + * Copyright 2010 INRIA Saclay + * + * 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 + */ + +#include "isl_union_macro.h" + +/* Print "pw" in a sequence of "PART" objects delimited by semicolons. + * Each "PART" object itself is also printed as a 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 isl_stat FN(print_body_wrap,BASE)(__isl_take PART *pw, + 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 = FN(print_body,BASE)(data->p, pw); + FN(PART,free)(pw); + + return isl_stat_non_null(data->p); +} + +/* Print the body of "u" (everything except the parameter declarations) + * to "p" in isl format. + */ +static __isl_give isl_printer *FN(print_body_union,BASE)( + __isl_take isl_printer *p, __isl_keep UNION *u) +{ + struct isl_union_print_data data; + + p = isl_printer_print_str(p, s_open_set[0]); + data.p = p; + data.first = 1; + if (FN(FN(UNION,foreach),BASE)(u, &FN(print_body_wrap,BASE), &data) < 0) + data.p = isl_printer_free(data.p); + p = data.p; + p = isl_printer_print_str(p, s_close_set[0]); + + return p; +} + +/* Print the "UNION" object "u" to "p" in isl format. + */ +static __isl_give isl_printer *FN(FN(print_union,BASE),isl)( + __isl_take isl_printer *p, __isl_keep UNION *u) +{ + struct isl_print_space_data space_data = { 0 }; + isl_space *space; + + space = FN(UNION,get_space)(u); + p = print_param_tuple(p, space, &space_data); + isl_space_free(space); + + p = FN(print_body_union,BASE)(p, u); + + return p; +} diff --git a/polly/lib/External/isl/isl_union_single.c b/polly/lib/External/isl/isl_union_single.c index e84706c..cf56342 100644 --- a/polly/lib/External/isl/isl_union_single.c +++ b/polly/lib/External/isl/isl_union_single.c @@ -133,9 +133,9 @@ static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u, if (!u || !part_entry) return FN(UNION,free)(u); + FN(PART,free)(part_entry->data); ctx = FN(UNION,get_ctx)(u); isl_hash_table_remove(ctx, &u->table, part_entry); - FN(PART,free)(part_entry->data); return u; } diff --git a/polly/lib/External/isl/isl_union_sub_templ.c b/polly/lib/External/isl/isl_union_sub_templ.c new file mode 100644 index 0000000..0def716 --- /dev/null +++ b/polly/lib/External/isl/isl_union_sub_templ.c @@ -0,0 +1,27 @@ +/* + * Copyright 2010 INRIA Saclay + * + * 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 + */ + +#include "isl_union_macro.h" + +/* Subtract "u2" from "u1" and return the result. + * + * If the base expressions have a default zero value, then + * reuse isl_union_*_add to ensure the result + * is computed on the union of the domains of "u1" and "u2". + * Otherwise, compute the result directly on their shared domain. + */ +__isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2) +{ +#if DEFAULT_IS_ZERO + return FN(UNION,add)(u1, FN(UNION,neg)(u2)); +#else + return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub)); +#endif +} diff --git a/polly/lib/External/isl/isl_union_templ.c b/polly/lib/External/isl/isl_union_templ.c index d16ccd9..875f814 100644 --- a/polly/lib/External/isl/isl_union_templ.c +++ b/polly/lib/External/isl/isl_union_templ.c @@ -201,9 +201,7 @@ static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u, goto error; entry->data = FN(PART,union_add_)(entry->data, FN(PART,copy)(part)); - if (!entry->data) - goto error; - empty = FN(PART,IS_ZERO)(part); + empty = FN(PART,IS_ZERO)(entry->data); if (empty < 0) goto error; if (empty) @@ -455,13 +453,12 @@ error: __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u, __isl_take isl_space *model) { + isl_space *space; isl_bool equal_params; isl_reordering *r; - if (!u || !model) - goto error; - - equal_params = isl_space_has_equal_params(u->space, model); + space = FN(UNION,peek_space)(u); + equal_params = isl_space_has_equal_params(space, model); if (equal_params < 0) goto error; if (equal_params) { @@ -469,7 +466,7 @@ __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u, return u; } - r = isl_parameter_alignment_reordering(u->space, model); + r = isl_parameter_alignment_reordering(space, model); isl_space_free(model); return FN(UNION,realign_domain)(u, r); @@ -524,6 +521,20 @@ error: return NULL; } +#if !DEFAULT_IS_ZERO + +/* Compute the sum of "u1" and "u2" 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 UNION *FN(UNION,union_add)(__isl_take UNION *u1, + __isl_take UNION *u2) +{ + return FN(UNION,union_add_)(u1, u2); +} + +#endif + __isl_give UNION *FN(FN(UNION,from),BASE)(__isl_take PART *part) { isl_space *space; @@ -650,15 +661,6 @@ __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2) #endif } -#ifndef NO_SUB -/* Subtract "u2" from "u1" and return the result. - */ -__isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2) -{ - return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub)); -} -#endif - S(UNION,any_set_data) { isl_set *set; __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*); diff --git a/polly/lib/External/isl/isl_val.c b/polly/lib/External/isl/isl_val.c index 3744aa7..8b77622 100644 --- a/polly/lib/External/isl/isl_val.c +++ b/polly/lib/External/isl/isl_val.c @@ -1577,6 +1577,8 @@ __isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls) #include #include #include +#include +#include #include #include #include @@ -1594,34 +1596,6 @@ isl_bool isl_multi_val_is_zero(__isl_keep isl_multi_val *mv) return isl_multi_val_every(mv, &isl_val_is_zero); } -/* Apply "fn" to each of the elements of "mv" with as second argument "v". - */ -static __isl_give isl_multi_val *isl_multi_val_fn_val( - __isl_take isl_multi_val *mv, - __isl_give isl_val *(*fn)(__isl_take isl_val *v1, - __isl_take isl_val *v2), - __isl_take isl_val *v) -{ - int i; - - mv = isl_multi_val_cow(mv); - if (!mv || !v) - goto error; - - for (i = 0; i < mv->n; ++i) { - mv->u.p[i] = fn(mv->u.p[i], isl_val_copy(v)); - if (!mv->u.p[i]) - goto error; - } - - isl_val_free(v); - return mv; -error: - isl_val_free(v); - isl_multi_val_free(mv); - return NULL; -} - /* Add "v" to each of the elements of "mv". */ __isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv, diff --git a/polly/lib/External/isl/isl_vec.c b/polly/lib/External/isl/isl_vec.c index 7d0ea18..323015b 100644 --- a/polly/lib/External/isl/isl_vec.c +++ b/polly/lib/External/isl/isl_vec.c @@ -1,5 +1,6 @@ /* * Copyright 2008-2009 Katholieke Universiteit Leuven + * Copyright 2011 Sven Verdoolaege * Copyright 2013 Ecole Normale Superieure * * Use of this software is governed by the MIT license @@ -653,3 +654,32 @@ __isl_give isl_vec *isl_vec_move_els(__isl_take isl_vec *vec, isl_vec_free(vec); return res; } + +/* Reorder the elements of "vec" starting at "offset" based + * on the given reordering. + */ +__isl_give isl_vec *isl_vec_reorder(__isl_take isl_vec *vec, + unsigned offset, __isl_take isl_reordering *r) +{ + isl_vec *res; + int i; + + if (!vec || !r) + goto error; + + res = isl_vec_alloc(vec->ctx, offset + r->dst_len); + if (!res) + goto error; + isl_seq_cpy(res->el, vec->el, offset); + isl_seq_clr(res->el + offset, res->size - offset); + for (i = 0; i < r->src_len; ++i) + isl_int_set(res->el[offset + r->pos[i]], vec->el[offset + i]); + + isl_reordering_free(r); + isl_vec_free(vec); + return res; +error: + isl_vec_free(vec); + isl_reordering_free(r); + return NULL; +} diff --git a/polly/lib/External/isl/isl_vec_private.h b/polly/lib/External/isl/isl_vec_private.h index 49bcef8..a46f56f 100644 --- a/polly/lib/External/isl/isl_vec_private.h +++ b/polly/lib/External/isl/isl_vec_private.h @@ -4,6 +4,8 @@ #include #include +#include "isl_reordering.h" + struct isl_vec { int ref; @@ -26,5 +28,7 @@ isl_bool isl_vec_is_zero(__isl_keep isl_vec *vec); __isl_give isl_vec *isl_vec_expand(__isl_take isl_vec *vec, int pos, int n, int *exp, int expanded); +__isl_give isl_vec *isl_vec_reorder(__isl_take isl_vec *vec, + unsigned offset, __isl_take isl_reordering *r); #endif diff --git a/polly/lib/External/isl/pip.c b/polly/lib/External/isl/pip.c index 9e6c1ec..e968ca7 100644 --- a/polly/lib/External/isl/pip.c +++ b/polly/lib/External/isl/pip.c @@ -12,7 +12,6 @@ #include #include #include -#include "isl_tab.h" #include "isl_sample.h" #include "isl_scan.h" #include @@ -112,7 +111,7 @@ static __isl_give isl_basic_set *move_parameters(__isl_take isl_basic_set *bset, nparam = isl_basic_set_dim(context, isl_dim_param); nparam_bset = isl_basic_set_dim(bset, isl_dim_param); - if (nparam < 0 | nparam_bset < 0) + if (nparam < 0 || nparam_bset < 0) return isl_basic_set_free(bset); if (nparam == nparam_bset) return bset; diff --git a/polly/lib/External/isl/python/isl.py.top b/polly/lib/External/isl/python/isl.py.top index 5c858c9..d041315 100644 --- a/polly/lib/External/isl/python/isl.py.top +++ b/polly/lib/External/isl/python/isl.py.top @@ -33,5 +33,17 @@ class Context: Context.defaultInstance = Context() return Context.defaultInstance + @CFUNCTYPE(None, py_object) + def free_user(user): + pythonapi.Py_DecRef(py_object(user)) + isl.isl_ctx_alloc.restype = c_void_p isl.isl_ctx_free.argtypes = [Context] +isl.isl_id_alloc.restype = c_void_p +isl.isl_id_alloc.argtypes = [Context, c_char_p, py_object] +isl.isl_id_set_free_user.restype = c_void_p +isl.isl_id_set_free_user.argtypes = [c_void_p, c_void_p] +isl.isl_id_get_free_user.restype = c_void_p +isl.isl_id_get_free_user.argtypes = [c_void_p] +isl.isl_id_get_user.restype = py_object +isl.isl_id_get_user.argtypes = [c_void_p] diff --git a/polly/lib/External/isl/test_inputs/schedule/fork1.sc b/polly/lib/External/isl/test_inputs/schedule/fork1.sc new file mode 100644 index 0000000..8ae3240 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork1.sc @@ -0,0 +1,5 @@ +# Check the decomposition of the topological sort. +# This decomposition is only performed by the incremental scheduler. +# OPTIONS: --no-schedule-whole-component +domain: { A[]; B[]; C[] } +validity: { A[] -> C[]; B[] -> C[] } diff --git a/polly/lib/External/isl/test_inputs/schedule/fork1.st b/polly/lib/External/isl/test_inputs/schedule/fork1.st new file mode 100644 index 0000000..00f0b74 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork1.st @@ -0,0 +1,9 @@ +domain: "{ B[]; C[]; A[] }" +child: + sequence: + - filter: "{ B[]; A[] }" + child: + set: + - filter: "{ A[] }" + - filter: "{ B[] }" + - filter: "{ C[] }" diff --git a/polly/lib/External/isl/test_inputs/schedule/fork2.sc b/polly/lib/External/isl/test_inputs/schedule/fork2.sc new file mode 100644 index 0000000..2c7d8d0 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork2.sc @@ -0,0 +1,5 @@ +# Check the decomposition of the topological sort. +# This decomposition is only performed by the incremental scheduler. +# OPTIONS: --no-schedule-whole-component +domain: { A[]; B[]; C[] } +validity: { A[] -> B[]; B[] -> C[] } diff --git a/polly/lib/External/isl/test_inputs/schedule/fork2.st b/polly/lib/External/isl/test_inputs/schedule/fork2.st new file mode 100644 index 0000000..884fa8c --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork2.st @@ -0,0 +1,6 @@ +domain: "{ C[]; A[]; B[] }" +child: + sequence: + - filter: "{ A[] }" + - filter: "{ B[] }" + - filter: "{ C[] }" diff --git a/polly/lib/External/isl/test_inputs/schedule/fork3.sc b/polly/lib/External/isl/test_inputs/schedule/fork3.sc new file mode 100644 index 0000000..5d164584 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork3.sc @@ -0,0 +1,7 @@ +# Check the decomposition of the topological sort. +# This decomposition is only performed by the incremental scheduler. +# OPTIONS: --no-schedule-whole-component +domain: { A[]; B[]; C[]; D[]; E[]; F[]; G[] } +validity: + { A[] -> C[]; B[] -> C[]; C[] -> E[]; D[] -> E[]; E[] -> F[]; E[] -> G[]; + A[] -> G[]; B[] -> E[] } diff --git a/polly/lib/External/isl/test_inputs/schedule/fork3.st b/polly/lib/External/isl/test_inputs/schedule/fork3.st new file mode 100644 index 0000000..784e07b --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/fork3.st @@ -0,0 +1,22 @@ +domain: "{ E[]; G[]; F[]; D[]; B[]; C[]; A[] }" +child: + sequence: + - filter: "{ D[]; B[]; C[]; A[] }" + child: + set: + - filter: "{ B[]; C[]; A[] }" + child: + sequence: + - filter: "{ B[]; A[] }" + child: + set: + - filter: "{ A[] }" + - filter: "{ B[] }" + - filter: "{ C[] }" + - filter: "{ D[] }" + - filter: "{ E[] }" + - filter: "{ G[]; F[] }" + child: + set: + - filter: "{ F[] }" + - filter: "{ G[] }" diff --git a/polly/lib/External/isl/test_inputs/schedule/nana.sc b/polly/lib/External/isl/test_inputs/schedule/nana.sc new file mode 100644 index 0000000..b2ffa29 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/nana.sc @@ -0,0 +1,9 @@ +# Check the decomposition of the topological sort. +# This decomposition is only performed by the incremental scheduler. +# OPTIONS: --no-schedule-whole-component +# +# This test case was contributed by Nana CK <1429802329@qq.com>. +domain: { sync[0:64, 0:32]; stB[0:64, 0:64]; stC[0:64, 0:64] } +validity: { stC[j = 0:64, 0:64] -> sync[j, 0]; stB[j = 0:64, 0:64] -> sync[j, 0] } +proximity: { stC[j = 0:64, 0:64] -> sync[j, 0]; stB[j = 0:64, 0:64] -> sync[j, 0] } +coincidence: { stC[j = 0:64, 0:64] -> sync[j, 0]; stB[j = 0:64, 0:64] -> sync[j, 0] } diff --git a/polly/lib/External/isl/test_inputs/schedule/nana.st b/polly/lib/External/isl/test_inputs/schedule/nana.st new file mode 100644 index 0000000..2275dd6 --- /dev/null +++ b/polly/lib/External/isl/test_inputs/schedule/nana.st @@ -0,0 +1,13 @@ +domain: "{ sync[i0, i1] : 0 <= i0 <= 64 and 0 <= i1 <= 32; stB[i0, i1] : 0 <= i0 <= 64 and 0 <= i1 <= 64; stC[i0, i1] : 0 <= i0 <= 64 and 0 <= i1 <= 64 }" +child: + schedule: "[{ sync[i0, i1] -> [(i0)]; stB[i0, i1] -> [(i0)]; stC[i0, i1] -> [(i0)] }, { sync[i0, i1] -> [(64 + i1)]; stB[i0, i1] -> [(i1)]; stC[i0, i1] -> [(i1)] }]" + permutable: 1 + coincident: [ 1, 0 ] + child: + sequence: + - filter: "{ stB[i0, i1]; stC[i0, i1] }" + child: + set: + - filter: "{ stC[i0, i1] }" + - filter: "{ stB[i0, i1] }" + - filter: "{ sync[i0, i1] }" -- 2.7.4