[polly] a749e09 - [Polly] Update ISL to isl-0.25-193-g8621c60c.
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 25 08:47:57 PST 2023
Author: Michael Kruse
Date: 2023-01-25T10:47:37-06:00
New Revision: a749e09e184b2b0b6dde71af01c82dd427b3e3e2
URL: https://github.com/llvm/llvm-project/commit/a749e09e184b2b0b6dde71af01c82dd427b3e3e2
DIFF: https://github.com/llvm/llvm-project/commit/a749e09e184b2b0b6dde71af01c82dd427b3e3e2.diff
LOG: [Polly] Update ISL to isl-0.25-193-g8621c60c.
The bugfix https://reviews.llvm.org/D142308 might already have been
fixed upstream.
Added:
polly/lib/External/isl/isl_ast_node_set_field_templ.c
polly/lib/External/isl/isl_from_range_templ.c
polly/lib/External/isl/isl_hash_private.h
polly/lib/External/isl/isl_ilp_opt_fn_val_templ.c
polly/lib/External/isl/isl_list_read_yaml_templ.c
polly/lib/External/isl/isl_multi_bin_val_templ.c
polly/lib/External/isl/isl_multi_from_tuple_templ.c
polly/lib/External/isl/isl_multi_pw_aff_pullback_templ.c
polly/lib/External/isl/isl_multi_un_op_templ.c
polly/lib/External/isl/isl_project_out_param_templ.c
polly/lib/External/isl/isl_pw_add_disjoint_templ.c
polly/lib/External/isl/isl_pw_fix_templ.c
polly/lib/External/isl/isl_pw_from_range_templ.c
polly/lib/External/isl/isl_pw_print_templ.c
polly/lib/External/isl/isl_pw_scale_templ.c
polly/lib/External/isl/isl_pw_split_dims_templ.c
polly/lib/External/isl/isl_pw_un_op_templ.c
polly/lib/External/isl/isl_read_from_str_templ.c
polly/lib/External/isl/isl_scheduler.h
polly/lib/External/isl/isl_scheduler_clustering.c
polly/lib/External/isl/isl_scheduler_clustering.h
polly/lib/External/isl/isl_scheduler_scc.c
polly/lib/External/isl/isl_scheduler_scc.h
polly/lib/External/isl/isl_stream_read_pw_with_params_templ.c
polly/lib/External/isl/isl_stream_read_with_params_templ.c
polly/lib/External/isl/isl_test_cpp17-checked.cc
polly/lib/External/isl/isl_test_cpp17-generic.cc
polly/lib/External/isl/isl_test_cpp17.cc
polly/lib/External/isl/isl_type_check_match_range_multi_val.c
polly/lib/External/isl/isl_union_print_templ.c
polly/lib/External/isl/isl_union_sub_templ.c
polly/lib/External/isl/test_inputs/schedule/fork1.sc
polly/lib/External/isl/test_inputs/schedule/fork1.st
polly/lib/External/isl/test_inputs/schedule/fork2.sc
polly/lib/External/isl/test_inputs/schedule/fork2.st
polly/lib/External/isl/test_inputs/schedule/fork3.sc
polly/lib/External/isl/test_inputs/schedule/fork3.st
polly/lib/External/isl/test_inputs/schedule/nana.sc
polly/lib/External/isl/test_inputs/schedule/nana.st
Modified:
polly/lib/External/CMakeLists.txt
polly/lib/External/isl/AUTHORS
polly/lib/External/isl/ChangeLog
polly/lib/External/isl/GIT_HEAD_ID
polly/lib/External/isl/all.h
polly/lib/External/isl/basis_reduction_templ.c
polly/lib/External/isl/cpp/cpp-checked.h.top
polly/lib/External/isl/cpp/cpp.h.top
polly/lib/External/isl/doc/isl.bib
polly/lib/External/isl/doc/user.pod
polly/lib/External/isl/extract_key.c
polly/lib/External/isl/flow_cmp.c
polly/lib/External/isl/include/isl/aff.h
polly/lib/External/isl/include/isl/ast.h
polly/lib/External/isl/include/isl/hash.h
polly/lib/External/isl/include/isl/hmap.h
polly/lib/External/isl/include/isl/hmap_templ.c
polly/lib/External/isl/include/isl/id.h
polly/lib/External/isl/include/isl/id_to_ast_expr.h
polly/lib/External/isl/include/isl/id_to_id.h
polly/lib/External/isl/include/isl/id_to_pw_aff.h
polly/lib/External/isl/include/isl/ilp.h
polly/lib/External/isl/include/isl/list.h
polly/lib/External/isl/include/isl/map.h
polly/lib/External/isl/include/isl/map_to_basic_set.h
polly/lib/External/isl/include/isl/polynomial_type.h
polly/lib/External/isl/include/isl/schedule_node.h
polly/lib/External/isl/include/isl/set.h
polly/lib/External/isl/include/isl/space.h
polly/lib/External/isl/include/isl/stream.h
polly/lib/External/isl/include/isl/stride_info.h
polly/lib/External/isl/include/isl/union_map.h
polly/lib/External/isl/interface/configure.ac
polly/lib/External/isl/interface/cpp.cc
polly/lib/External/isl/interface/cpp.h
polly/lib/External/isl/interface/extract_interface.cc
polly/lib/External/isl/interface/generator.cc
polly/lib/External/isl/interface/generator.h
polly/lib/External/isl/interface/plain_cpp.cc
polly/lib/External/isl/interface/plain_cpp.h
polly/lib/External/isl/interface/python.cc
polly/lib/External/isl/interface/python.h
polly/lib/External/isl/interface/template_cpp.cc
polly/lib/External/isl/interface/template_cpp.h
polly/lib/External/isl/isl_aff.c
polly/lib/External/isl/isl_aff_map.c
polly/lib/External/isl/isl_aff_private.h
polly/lib/External/isl/isl_ast.c
polly/lib/External/isl/isl_ast_build.c
polly/lib/External/isl/isl_ast_build_expr.c
polly/lib/External/isl/isl_ast_build_private.h
polly/lib/External/isl/isl_ast_codegen.c
polly/lib/External/isl/isl_ast_graft.c
polly/lib/External/isl/isl_ast_graft_private.h
polly/lib/External/isl/isl_ast_private.h
polly/lib/External/isl/isl_box.c
polly/lib/External/isl/isl_coalesce.c
polly/lib/External/isl/isl_ctx.c
polly/lib/External/isl/isl_dim_map.c
polly/lib/External/isl/isl_flow.c
polly/lib/External/isl/isl_fold.c
polly/lib/External/isl/isl_hash.c
polly/lib/External/isl/isl_id.c
polly/lib/External/isl/isl_id_private.h
polly/lib/External/isl/isl_id_to_ast_expr.c
polly/lib/External/isl/isl_id_to_id.c
polly/lib/External/isl/isl_id_to_pw_aff.c
polly/lib/External/isl/isl_ilp.c
polly/lib/External/isl/isl_input.c
polly/lib/External/isl/isl_int_sioimath.h
polly/lib/External/isl/isl_list_read_templ.c
polly/lib/External/isl/isl_list_templ.c
polly/lib/External/isl/isl_local.c
polly/lib/External/isl/isl_local.h
polly/lib/External/isl/isl_local_space.c
polly/lib/External/isl/isl_local_space_private.h
polly/lib/External/isl/isl_lp.c
polly/lib/External/isl/isl_map.c
polly/lib/External/isl/isl_map_simplify.c
polly/lib/External/isl/isl_map_subtract.c
polly/lib/External/isl/isl_map_to_basic_set.c
polly/lib/External/isl/isl_multi_add_constant_templ.c
polly/lib/External/isl/isl_multi_apply_templ.c
polly/lib/External/isl/isl_multi_arith_templ.c
polly/lib/External/isl/isl_multi_dim_id_templ.c
polly/lib/External/isl/isl_multi_dims.c
polly/lib/External/isl/isl_multi_floor.c
polly/lib/External/isl/isl_multi_move_dims_templ.c
polly/lib/External/isl/isl_multi_read_no_explicit_domain_templ.c
polly/lib/External/isl/isl_multi_templ.c
polly/lib/External/isl/isl_output.c
polly/lib/External/isl/isl_point.c
polly/lib/External/isl/isl_point_private.h
polly/lib/External/isl/isl_polynomial.c
polly/lib/External/isl/isl_polynomial_private.h
polly/lib/External/isl/isl_power_templ.c
polly/lib/External/isl/isl_pw_eval.c
polly/lib/External/isl/isl_pw_insert_dims_templ.c
polly/lib/External/isl/isl_pw_morph_templ.c
polly/lib/External/isl/isl_pw_move_dims_templ.c
polly/lib/External/isl/isl_pw_neg_templ.c
polly/lib/External/isl/isl_pw_pullback_templ.c
polly/lib/External/isl/isl_pw_templ.c
polly/lib/External/isl/isl_pw_union_opt.c
polly/lib/External/isl/isl_reordering.c
polly/lib/External/isl/isl_reordering.h
polly/lib/External/isl/isl_sample.c
polly/lib/External/isl/isl_sample.h
polly/lib/External/isl/isl_schedule_constraints.c
polly/lib/External/isl/isl_schedule_node.c
polly/lib/External/isl/isl_schedule_read.c
polly/lib/External/isl/isl_schedule_tree.c
polly/lib/External/isl/isl_scheduler.c
polly/lib/External/isl/isl_set_to_ast_graft_list.c
polly/lib/External/isl/isl_set_to_ast_graft_list.h
polly/lib/External/isl/isl_space.c
polly/lib/External/isl/isl_space_private.h
polly/lib/External/isl/isl_stream.c
polly/lib/External/isl/isl_stride.c
polly/lib/External/isl/isl_tab.c
polly/lib/External/isl/isl_tab.h
polly/lib/External/isl/isl_test.c
polly/lib/External/isl/isl_test2.cc
polly/lib/External/isl/isl_test_cpp.cc
polly/lib/External/isl/isl_test_python.py
polly/lib/External/isl/isl_union_map.c
polly/lib/External/isl/isl_union_single.c
polly/lib/External/isl/isl_union_templ.c
polly/lib/External/isl/isl_val.c
polly/lib/External/isl/isl_vec.c
polly/lib/External/isl/isl_vec_private.h
polly/lib/External/isl/pip.c
polly/lib/External/isl/python/isl.py.top
Removed:
################################################################################
diff --git a/polly/lib/External/CMakeLists.txt b/polly/lib/External/CMakeLists.txt
index c0a5b32e283f2..8a360e453ce1f 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 c6aa5cdad94ca..4f7c2d6a458a6 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 44acc42630714..49100a82fb326 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 60beb8f894c07..0aad10556c68f 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 dea77ddd02ed6..73b80959f4b50 100644
--- a/polly/lib/External/isl/all.h
+++ b/polly/lib/External/isl/all.h
@@ -1,4 +1,5 @@
#include <isl/id.h>
+#include <isl/id_to_id.h>
#include <isl/space.h>
#include <isl/val.h>
#include <isl/aff.h>
diff --git a/polly/lib/External/isl/basis_reduction_templ.c b/polly/lib/External/isl/basis_reduction_templ.c
index 5c03eab18f358..290da7dc29d71 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 be29b971b9b01..6d62fb11037d2 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 <string>
#include <type_traits>
+#if __cplusplus >= 201703L
+#include <any>
+#include <optional>
+#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<std::any *>(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 15282b129a575..9af6f48d24b87 100644
--- a/polly/lib/External/isl/cpp/cpp.h.top
+++ b/polly/lib/External/isl/cpp/cpp.h.top
@@ -18,6 +18,11 @@
#include <string>
#include <type_traits>
+#if __cplusplus >= 201703L
+#include <any>
+#include <optional>
+#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<std::any *>(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 42074b2b7e22d..51fdcab21c785 100644
--- a/polly/lib/External/isl/doc/isl.bib
+++ b/polly/lib/External/isl/doc/isl.bib
@@ -198,7 +198,7 @@ @article{Woods2003short
@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 @@ @inproceedings{Verdoolaege2014impact
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 1e8d6a92feccf..e0433a032ac86 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<isl> can be obtained either as a tarball
or from the git repository. Both are available from
-L<http://isl.gforge.inria.fr/>.
+L<https://libisl.sourceforge.io/>.
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<isl> will run
fastest with the C<imath-32> option, followed by C<gmp> and C<imath>, the
slowest.
-=item C<--with-gmp-prefix>
+=item C<--with-gmp-prefix=>I<path>
Installation prefix for C<GMP> (architecture-independent files).
-=item C<--with-gmp-exec-prefix>
+=item C<--with-gmp-exec-prefix=>I<path>
Installation prefix for C<GMP> (architecture-dependent files).
@@ -436,12 +436,47 @@ Installation prefix for C<GMP> (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<http://clang.llvm.org/get_started.html>.
+The C<configure> 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<path>
+
+Use the system clang libraries installed in I<path>.
+
+=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<make install>).
+If the compiler that was used to compile the clang libraries
+is
diff erent from the default C++ compiler, then use C<CXX_FOR_BUILD>
+to specify this non-default C++ compiler when running C<isl>'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<isl_id_set_free_user> is called on the user
pointer when the last reference to the C<isl_id> is freed.
+This callback can be retrieved using C<isl_id_get_free_user>.
Note that C<isl_id_get_name> returns a pointer to some internal
data structure, so the result can only be used while the
corresponding C<isl_id> 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<isl_set_pw_multi_aff_on_domain_multi_val> is an alternative name
-for C<isl_pw_multi_aff_multi_val_on_domain>.
+C<isl_set_pw_aff_on_domain_val> is an alternative name
+for C<isl_pw_aff_val_on_domain>.
+Similarly for the pair
+C<isl_set_pw_multi_aff_on_domain_multi_val> and
+C<isl_pw_multi_aff_multi_val_on_domain> and
+for the pair C<isl_set_param_pw_aff_on_domain_id> and
+C<isl_pw_aff_param_on_domain_id>.
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/space.h>
+ __isl_give isl_space *isl_space_read_from_str(
+ isl_ctx *ctx, const char *str);
+
#include <isl/set.h>
__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/val.h>
__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/set.h>
__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/val.h>
- __isl_give isl_printer *isl_printer_print_multi_val(
- __isl_take isl_printer *p,
- __isl_keep isl_multi_val *mv);
-
#include <isl/id.h>
__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/map.h>
__isl_give isl_stride_info *
@@ -4831,6 +4884,8 @@ can be extracted from the returned
C<isl_fixed_box> using the functions described under "Box hull" in
L</"Unary Operations">. Note that the C<isl_fixed_box> object returned by
C<isl_map_get_range_lattice_tile> is always valid.
+The function C<isl_set_get_lattice_tile> 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/local_space.h>
__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<isl_space_domain_wrapped_domain> returns the domain
+of the binary relation wrapped inside the domain of the input.
The function C<isl_set_project_onto_map> 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<isl_union_set_project_out> can only project out
parameters.
#include <isl/union_map.h>
+ __isl_give isl_union_map *
+ isl_union_map_project_out_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/ilp.h>
+ __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/union_set.h>
__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/aff.h>
__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<isl_set_list_from_set> performs the same operation.
C<isl_set_list_clear> removes all elements from a list.
C<isl_set_list_swap> swaps the elements at the specified locations.
C<isl_set_list_reverse> reverses the elements in the list.
+C<isl_set_list_set_set> is an alternative name for C<isl_set_list_set_at>.
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<isl_id_to_ast_expr_try_get> returns a structure
containing two elements, C<valid> and C<value>.
@@ -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/id_to_ast_expr.h>
+ 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<plain_is_equal> rather than C<is_equal>.
+
+Associative arrays can be printed using the following functions.
#include <isl/id_to_ast_expr.h>
__isl_give isl_printer *isl_printer_print_id_to_ast_expr(
__isl_take isl_printer *p,
__isl_keep 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/id_to_ast_expr.h>
+ __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
diff erent 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/schedule_node.h>
__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<node> that has another sequence node
in its child at position C<pos> (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<isl_schedule_node_sequence_splice_child>
+attaches the children of that other sequence
node as children of C<node>, replacing the original child at position
C<pos>.
+C<isl_schedule_node_sequence_splice_children> 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<isl_ast_expr_op_address_of>
+
+The address of its single argument, which is always an array access.
+
=back
#include <isl/ast.h>
@@ -11922,6 +12077,18 @@ subexpressions of C<expr> of type C<isl_ast_expr_id>
by the corresponding expression in C<id2expr>, 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/ast.h>
+ __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<isl_ast_node> and obtained
from the same C<isl_ast_node> using the following functions.
@@ -12693,9 +12860,22 @@ AST generation or a
user defined node created using the following function.
#include <isl/ast.h>
+ __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<isl_ast_node_alloc_user> is an alternative name for
+C<isl_ast_node_user_from_expr>.
+
+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/ast.h>
+ __isl_give isl_ast_node *isl_ast_node_block_from_children(
+ __isl_take isl_ast_node_list *list);
+
#include <isl/ast_build.h>
__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 070c1f6265f39..28fbdfdd30967 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 ca7e3775e4672..e01c0fa628c8a 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 c417be1654245..cf0b5f6107b16 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 570c48a092bf1..786f5b496ab62 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 7ef3d2e03e04d..31cf25cf3bbe9 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 21612217032ef..8d4178fe468f7 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 ceb52bd693733..ba0d7cc6e10a3 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 <isl/ctx.h>
#include <isl/hash.h>
+#include <isl/stream.h>
#define ISL_xCAT(A,B) A ## B
#define ISL_CAT(A,B) ISL_xCAT(A,B)
@@ -322,7 +323,7 @@ __isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap,
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 3e71cb007cd60..f434d537de247 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 5822241e3f4b4..ccdb1e0713946 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 <isl/hmap.h>
#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 309011577d1ed..94b40ef8de7e2 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 <isl/hmap.h>
#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 bcbea660d79d8..0b7a0e52cf3f1 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 <isl/hmap.h>
#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 a2be08e5c0e70..5f9b8160a4a99 100644
--- a/polly/lib/External/isl/include/isl/ilp.h
+++ b/polly/lib/External/isl/include/isl/ilp.h
@@ -31,6 +31,10 @@ __isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set,
__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);
diff --git a/polly/lib/External/isl/include/isl/list.h b/polly/lib/External/isl/include/isl/list.h
index 3d8dabedf05cf..af5d6bad99d31 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 55feb9b3b588c..38359c65fdb26 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 80e9ab5bed2e8..da86aacf4ac1a 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 <isl/hmap.h>
#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 f4a3f20293422..02bbc03b54fff 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 <isl/ctx.h>
+#include <isl/list.h>
+
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 b336003222b07..648bc0d759021 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 <isl/val_type.h>
#include <isl/space_type.h>
#include <isl/id_type.h>
+#include <isl/set_type.h>
#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 3e9b224fc4858..e2c79f823bd35 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 f3e1d8a15b266..f89ff0ebbd698 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 b77797f327e06..09d15f6223848 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 7a4e0dcb1e36d..533eb6850957c 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 <isl/val.h>
+#include <isl/val_type.h>
#include <isl/aff_type.h>
#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 c630dc0807908..029e9f9a93f4d 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 357eb60ab76c1..b61822bad802a 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 23e2281de1b93..d5c08ebf25f0f 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<ParmVarDecl *> find_callback_args(FunctionDecl *fd)
{
+ std::vector<ParmVarDecl *> 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<void(int i)> &print_arg)
+void Method::on_arg_list(int start, int end,
+ const Method::list_combiner &combiner,
+ const std::function<bool(int i)> &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<bool(int i)> &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<void(int i, int arg)> &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<void(int i, int arg)> &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<void(int i, int arg)> &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<void(int i, int arg)> &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<void(int i)> &print_arg) const
+ const std::function<void(int i, int arg)> &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 837cdee3e9394..55a8fb42eef2f 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
diff erent
* 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<bool(int i)> &on_arg_skip_next);
static void print_arg_list(std::ostream &os, int start, int end,
- const std::function<void(int i)> &print_arg);
+ const std::function<bool(int i)> &print_arg_skip_next);
+ void on_fd_arg_list(int start, int end,
+ const list_combiner &combiner,
+ const std::function<void(int i, int arg)> &on_arg) const;
+ void print_fd_arg_list(std::ostream &os, int start, int end,
+ const std::function<void(int i, int arg)> &print_arg) const;
+ void on_cpp_arg_list(const list_combiner &combiner,
+ const std::function<void(int i, int arg)> &on_arg) const;
+ void on_cpp_arg_list(
+ const std::function<void(int i, int arg)> &on_arg) const;
void print_cpp_arg_list(std::ostream &os,
- const std::function<void(int i)> &print_arg) const;
+ const std::function<void(int i, int arg)> &print_arg) const;
const isl_class &clazz;
FunctionDecl *const fd;
const std::string name;
const enum Kind kind;
- ParmVarDecl *const callback;
+ const std::vector<ParmVarDecl *> 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<void()> before;
+ const std::function<void()> between;
+ const std::function<void()> 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 e1fcb241953f7..b94847c59035e 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<string> 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 eacbc36a65e6d..4b9890325ccb0 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<FunctionProtoType>();
}
+/* 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 29faaaac086e5..90eae8266a730 100644
--- a/polly/lib/External/isl/interface/generator.h
+++ b/polly/lib/External/isl/interface/generator.h
@@ -190,11 +190,13 @@ class generator {
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 ae15c34dbe4a9..326cf12218782 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<T>(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 <class T>\n";
+ os << indent << (optional ? "std::optional<T> " : "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<void(void)> &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 264480212dd3b..17f4af05afe07 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 686bcc71b91c9..e4a8288631297 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<bool> &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<bool> 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<string, function_set>::const_iterator it;
- map<FunctionDecl *, vector<set_enum> >::const_iterator ie;
vector<string> super = find_superclasses(clazz.type);
const set<FunctionDecl *> &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 e56c23d9c5900..87d5caeefd0f5 100644
--- a/polly/lib/External/isl/interface/python.h
+++ b/polly/lib/External/isl/interface/python.h
@@ -38,6 +38,8 @@ class python_generator : public generator {
void print_restype(FunctionDecl *fd);
void print(map<string, isl_class> &classes, set<string> &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 @@ class python_generator : public generator {
vector<string> 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 debbfcd284400..2beca82550b25 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<Signature> 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<Signature> 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<Kind> add_name(const std::vector<Kind> &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<Kind> 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<Kind> &base_kinds)
+ const std::string &name, const std::vector<Kind> &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 a141a4826caa4..ae3315d812d6c 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<Kind> &base_kinds);
+ const std::vector<Kind> &class_tuples);
public:
template_cpp_generator(clang::SourceManager &SM,
std::set<clang::RecordDecl *> &exported_types,
diff --git a/polly/lib/External/isl/isl_aff.c b/polly/lib/External/isl/isl_aff.c
index 40ca78dec6b29..9bb4b22bd1ce3 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 <isl_ctx_private.h>
@@ -63,8 +65,12 @@
#include <isl_list_templ.c>
-__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 @@ __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
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 @@ __isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff,
__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 <isl_pw_templ.c>
+#include <isl_pw_un_op_templ.c>
#include <isl_pw_add_constant_val_templ.c>
+#include <isl_pw_add_disjoint_templ.c>
#include <isl_pw_bind_domain_templ.c>
#include <isl_pw_eval.c>
#include <isl_pw_hash.c>
+#include <isl_pw_fix_templ.c>
+#include <isl_pw_from_range_templ.c>
#include <isl_pw_insert_dims_templ.c>
#include <isl_pw_insert_domain_templ.c>
#include <isl_pw_move_dims_templ.c>
#include <isl_pw_neg_templ.c>
#include <isl_pw_pullback_templ.c>
+#include <isl_pw_scale_templ.c>
#include <isl_pw_sub_templ.c>
#include <isl_pw_union_opt.c>
@@ -2823,6 +2813,7 @@ static __isl_give isl_aff *isl_aff_zero_in_space(__isl_take isl_space *space)
#include <isl_union_single.c>
#include <isl_union_neg.c>
+#include <isl_union_sub_templ.c>
#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 @@ __isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1,
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 @@ static __isl_give isl_pw_aff *pw_aff_list_reduce(
*/
__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 <isl_multi_no_explicit_domain.c>
#include <isl_multi_templ.c>
+#include <isl_multi_un_op_templ.c>
+#include <isl_multi_bin_val_templ.c>
#include <isl_multi_add_constant_templ.c>
#include <isl_multi_apply_set.c>
#include <isl_multi_arith_templ.c>
@@ -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 @@ static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities(
__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 <isl_pw_templ.c>
+#include <isl_pw_un_op_templ.c>
#include <isl_pw_add_constant_multi_val_templ.c>
#include <isl_pw_add_constant_val_templ.c>
+#include <isl_pw_add_disjoint_templ.c>
#include <isl_pw_bind_domain_templ.c>
+#include <isl_pw_fix_templ.c>
+#include <isl_pw_from_range_templ.c>
#include <isl_pw_insert_dims_templ.c>
#include <isl_pw_insert_domain_templ.c>
#include <isl_pw_locals_templ.c>
@@ -4531,6 +4616,7 @@ __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1,
#include <isl_union_multi.c>
#include "isl_union_locals_templ.c"
#include <isl_union_neg.c>
+#include <isl_union_sub_templ.c>
#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
diff erence 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
diff erence 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 @@ __isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst,
__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 @@ isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
#include <isl_multi_explicit_domain.c>
#include <isl_multi_pw_aff_explicit_domain.c>
#include <isl_multi_templ.c>
+#include <isl_multi_un_op_templ.c>
+#include <isl_multi_bin_val_templ.c>
#include <isl_multi_add_constant_templ.c>
#include <isl_multi_apply_set.c>
#include <isl_multi_arith_templ.c>
@@ -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 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(
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 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(
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
@@ -7445,18 +7395,6 @@ __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff(
return NULL;
}
-/* 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".
*
@@ -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 @@ __isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff(
#include <isl_multi_explicit_domain.c>
#include <isl_multi_union_pw_aff_explicit_domain.c>
#include <isl_multi_templ.c>
+#include <isl_multi_un_op_templ.c>
+#include <isl_multi_bin_val_templ.c>
#include <isl_multi_apply_set.c>
#include <isl_multi_apply_union_set.c>
#include <isl_multi_arith_templ.c>
@@ -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 f661b824d2ef0..3f46d86b57e92 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 473add3b3ab62..eb814ea92d840 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_list_templ.h>
+__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 6bf517893f7b7..c7164c4b3e7c3 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 <string.h>
#include <isl/id.h>
+#include <isl/stream.h>
#include <isl/val.h>
#include <isl_ast_private.h>
@@ -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 @@ __isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr,
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 @@ __isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id,
/* 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 @@ __isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr)
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 @@ __isl_give isl_ast_node *isl_ast_node_alloc_block(
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
diff erent 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 <isl_list_read_yaml_templ.c>
+
+/* 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 @@ __isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node,
__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 <isl_list_read_yaml_templ.c>
+
+/* 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 a0776e8235062..9f04e1c3e1ed2 100644
--- a/polly/lib/External/isl/isl_ast_build.c
+++ b/polly/lib/External/isl/isl_ast_build.c
@@ -1910,14 +1910,14 @@ __isl_give isl_ast_build *isl_ast_build_product(
/* 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 3e35416f7255f..590fa6f5e5a59 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 @@ static __isl_give isl_ast_expr *scale(__isl_take isl_ast_expr *expr,
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 @@ static __isl_give isl_ast_expr *scale(__isl_take isl_ast_expr *expr,
*
*/
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 @@ static __isl_give isl_aff *extract_rational(__isl_take isl_aff *aff,
__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'
diff er 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 @@ static __isl_give isl_ast_expr *ast_expr_from_aff_list(
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 1128e632c3ac8..cb10fb4d86f3e 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 d337c4e4e2f6c..774dfab72296b 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 03e8449d90c60..d83377694ee87 100644
--- a/polly/lib/External/isl/isl_ast_graft.c
+++ b/polly/lib/External/isl/isl_ast_graft.c
@@ -14,6 +14,7 @@
#include <isl/id.h>
#include <isl/space.h>
+#include <isl/stream.h>
#include <isl_ast_private.h>
#include <isl_ast_build_expr.h>
#include <isl_ast_build_private.h>
@@ -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 <isl_list_templ.c>
+#include <isl_list_read_templ.c>
#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
diff erent 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 5ca7c03366386..5bf010b882a96 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 <isl/set.h>
#include <isl/list.h>
#include <isl/printer.h>
+#include <isl/stream.h>
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 0000000000000..6eed55bbdd426
--- /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 a7726a28df724..8bff794c0c485 100644
--- a/polly/lib/External/isl/isl_ast_private.h
+++ b/polly/lib/External/isl/isl_ast_private.h
@@ -7,6 +7,12 @@
#include <isl/map.h>
#include <isl/vec.h>
#include <isl/list.h>
+#include <isl/stream.h>
+
+#undef EL
+#define EL isl_ast_expr
+
+#include <isl_list_templ.h>
/* 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_list_templ.h>
-
__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 d4eb54f3ecb59..34a49eafb73a0 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 910c2146bd5a9..5d0d173af9fe2 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 176fd6f56a1dc..017e4af888aa9 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 b0b067d80e6d9..3bace2c552d2c 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 3be3ad500f1e8..c083a96538a76 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 2d7f85c0fd534..33ea278e44cf5 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 <isl_pw_templ.c>
+#include <isl_pw_add_disjoint_templ.c>
#include <isl_pw_eval.c>
+#include <isl_pw_fix_templ.c>
+#include <isl_pw_from_range_templ.c>
#include <isl_pw_insert_dims_templ.c>
#include <isl_pw_lift_templ.c>
#include <isl_pw_morph_templ.c>
@@ -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 <isl_union_single.c>
#include <isl_union_eval.c>
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 0000000000000..08c640d8b9b67
--- /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 59cb06e85edde..d0f6564a0201e 100644
--- a/polly/lib/External/isl/isl_hash.c
+++ b/polly/lib/External/isl/isl_hash.c
@@ -8,7 +8,7 @@
*/
#include <stdlib.h>
-#include <isl/hash.h>
+#include <isl_hash_private.h>
#include <isl/ctx.h>
#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 0000000000000..bc5acb4b79371
--- /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 <isl/hash.h>
+
+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 ab0f75b3693c7..d1f575e2461f4 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 3b053e87c2023..bcc22175a095d 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 4bfa9530ab04f..5a41ab67e8d82 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 <isl/id_to_ast_expr.h>
#include <isl/id.h>
-#include <isl/ast.h>
+
+#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 <isl/hmap_templ.c>
diff --git a/polly/lib/External/isl/isl_id_to_id.c b/polly/lib/External/isl/isl_id_to_id.c
index e92e8f63835ce..ca42f0d8fa73b 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 <isl/hmap_templ.c>
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 1ef27b5eaa792..fcfa8c16af612 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 <isl/id_to_pw_aff.h>
#include <isl/id.h>
-#include <isl/aff.h>
+
+#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 <isl/hmap_templ.c>
diff --git a/polly/lib/External/isl/isl_ilp.c b/polly/lib/External/isl/isl_ilp.c
index fe623ba09cdd2..2c004efe4b2ca 100644
--- a/polly/lib/External/isl/isl_ilp.c
+++ b/polly/lib/External/isl/isl_ilp.c
@@ -695,6 +695,10 @@ static __isl_give isl_val *isl_pw_aff_opt_val(__isl_take isl_pw_aff *pa,
return data.res;
}
+#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 0000000000000..6b2c5323225a7
--- /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 4c6839d15d8f1..e289d747316d9 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 @@ static struct isl_token *next_token(__isl_keep isl_stream *s)
* "-" "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 @@ __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s)
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 @@ static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s,
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 @@ static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s,
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 @@ static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s,
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 @@ static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s)
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 @@ __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
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 @@ __isl_give isl_pw_qpolynomial_fold *isl_stream_read_pw_qpolynomial_fold(
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 @@ static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s,
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 <isl_multi_from_tuple_templ.c>
-/* 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
diff erent 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 @@ static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
#include <isl_multi_read_no_explicit_domain_templ.c>
+/* 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 <isl_multi_from_tuple_templ.c>
+
/* 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
diff erent 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 @@ __isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
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 dc691b8a0b1e6..a2112cd8e2fb9 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 d9a2c40e9f12c..11c2bd52183ff 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 0000000000000..5b6143df9ee47
--- /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 <isl/stream.h>
+
+#include <isl_list_macro.h>
+
+/* 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 cfb4f33977939..4b04052896c1b 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 @@ __isl_give LIST(EL) *FN(FN(LIST(EL),set),EL_BASE)(__isl_take LIST(EL) *list,
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 e409359d28da0..5b50ea775c9ac 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 @@ __isl_give isl_local *isl_local_reorder(__isl_take isl_local *local,
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 a52622e4a1da7..76527036e20e6 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 1eebd44755754..604e276a0d1f6 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 @@ __isl_give isl_local_space *isl_local_space_reset_space(
__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 42c2ad0fc0224..fbf2159c88c3e 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 5fe179ab29df9..c6cc83848b782 100644
--- a/polly/lib/External/isl/isl_lp.c
+++ b/polly/lib/External/isl/isl_lp.c
@@ -22,7 +22,7 @@
#include <bset_to_bmap.c>
#include <set_to_map.c>
-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 516106cf3a80d..5cb7a56828d56 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 @@ __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
#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 @@ __isl_give isl_set *isl_set_project_out_param_id(__isl_take isl_set *set,
__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 9759c0df9facd..72e0e9bb7630c 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 6431b3daa9649..68ce54fff067a 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 f0c8d505c6c76..9e96e6074639a 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 <isl/hmap_templ.c>
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 fa4971fb733d0..a54f3fa720117 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 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),add_constant_val)(
__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 870f2676c4237..31e27f26fb41c 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 6765bd23cb535..dd497138a1fd4 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 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
__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 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
__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 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
__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 0000000000000..a7a3913da9b11
--- /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 80dd7db5878fd..5103edf866c81 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 a2775eab9fc19..fb5cb1147b95a 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 b9a8898831283..0d8420f072eb0 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 0000000000000..46d35cc224afe
--- /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 <isl_multi_macro.h>
+
+/* 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 9c880857948b6..ba9830e2b6df2 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 0000000000000..fc5aed2b3ffd8
--- /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 b8a6ec5440ee9..6baf562ad6857 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 @@ __isl_give MULTI(BASE) *FN(isl_stream_read_multi,BASE)(
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 3777024d2e95e..6e0a6ed5bc3ad 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 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
__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 0000000000000..bbf105b5927fa
--- /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 <isl_multi_macro.h>
+
+/* 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 9839a52516a3d..df49364cffbbe 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 @@ __isl_give isl_printer *isl_printer_print_pw_qpolynomial(
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 @@ static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p,
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 @@ __isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p,
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 @@ __isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p,
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 @@ __isl_give isl_printer *isl_printer_print_pw_multi_aff(
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 f7da70644ef0d..f315b3d9a9ce8 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 <isl_map_private.h>
@@ -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 a1e84494f35e4..f8f9d835ed9fb 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 0aac613f0c60e..7b4eae0148966 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 <isl_pw_templ.c>
+#include <isl_pw_un_op_templ.c>
+#include <isl_pw_add_disjoint_templ.c>
#include <isl_pw_eval.c>
+#include <isl_pw_fix_templ.c>
+#include <isl_pw_from_range_templ.c>
#include <isl_pw_insert_dims_templ.c>
#include <isl_pw_lift_templ.c>
#include <isl_pw_morph_templ.c>
#include <isl_pw_move_dims_templ.c>
#include <isl_pw_neg_templ.c>
#include <isl_pw_opt_templ.c>
+#include <isl_pw_split_dims_templ.c>
#include <isl_pw_sub_templ.c>
#undef BASE
@@ -3123,6 +3128,7 @@ static __isl_give isl_qpolynomial *isl_qpolynomial_zero_in_space(
#include <isl_union_single.c>
#include <isl_union_eval.c>
#include <isl_union_neg.c>
+#include <isl_union_sub_templ.c>
int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp)
{
@@ -4486,20 +4492,17 @@ __isl_give isl_qpolynomial *isl_qpolynomial_realign_domain(
__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 acab078385944..4e8cb82424664 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 65253bdcb969f..26f0fe5573bf1 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 0000000000000..f277b7c6c15fd
--- /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 0000000000000..160b9b5ef31eb
--- /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 <isl_pw_macro.h>
+
+/* 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 f59b78726a81d..40396b602adad 100644
--- a/polly/lib/External/isl/isl_pw_eval.c
+++ b/polly/lib/External/isl/isl_pw_eval.c
@@ -16,6 +16,16 @@
#include <isl_pw_macro.h>
+#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 0000000000000..36a50bc12a2b1
--- /dev/null
+++ b/polly/lib/External/isl/isl_pw_fix_templ.c
@@ -0,0 +1,71 @@
+#include <isl_pw_macro.h>
+
+/* 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 0000000000000..c9394bd60b903
--- /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 <isl_pw_macro.h>
+
+#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 c451dcac11324..df5bfb45bceb1 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 a90fea12168f3..3c08698a9a987 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 31788d79a7f73..a68a9476fc652 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 65970cf641665..d3da91371b38f 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 0000000000000..77f62c61f9d38
--- /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 6f1bda9a6b94f..5486061edd72a 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 0000000000000..81c8495e9cb7e
--- /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_pw_macro.h>
+
+__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 0000000000000..68e9165b61693
--- /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_pw_macro.h>
+
+__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 3fa6faf1b5ff4..30ddb922576c8 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 @@ static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
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
diff erence 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 @@ static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
__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 @@ static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
__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
diff erence 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
diff erence 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 @@ __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
__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 @@ __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
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 0000000000000..114609012edbe
--- /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 <isl_pw_macro.h>
+
+/* 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 d0fc38ce51f32..99b0045960f25 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 0000000000000..51fa8ed12810c
--- /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 33a8976fbc696..bfbdd9e0c6c1a 100644
--- a/polly/lib/External/isl/isl_reordering.c
+++ b/polly/lib/External/isl/isl_reordering.c
@@ -13,22 +13,49 @@
#include <isl_space_private.h>
#include <isl_reordering.h>
-__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 6664749b0ec6d..be56cf863057b 100644
--- a/polly/lib/External/isl/isl_reordering.h
+++ b/polly/lib/External/isl/isl_reordering.h
@@ -3,18 +3,19 @@
#include <isl/space.h>
-/* 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 e0e2c9bee8db6..2e26190bf293e 100644
--- a/polly/lib/External/isl/isl_sample.c
+++ b/polly/lib/External/isl/isl_sample.c
@@ -24,6 +24,9 @@
#include <bset_from_bmap.c>
#include <set_to_map.c>
+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 @@ static __isl_give isl_vec *gbr_sample(__isl_take isl_basic_set *bset)
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 13f0e5bef9f84..6ffdad8a0a935 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 38a3c6f9d369e..c35ac66dfa68a 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 5e37276253b14..9d140e56e7d98 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 71fdeed50d768..b98b72b7dc761 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 @@ static __isl_give isl_schedule_tree *read_mark(isl_stream *s)
return NULL;
}
+#undef EL_BASE
+#define EL_BASE val
+
+#include <isl_list_read_yaml_templ.c>
+
/* 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 @@ static __isl_give isl_schedule_tree *read_band(isl_stream *s)
return NULL;
}
+#undef EL_BASE
+#define EL_BASE schedule_tree
+
+#include <isl_list_read_yaml_templ.c>
+
/* 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 2a20a336ff254..8dfe1d728b650 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 5ab65d22522b4..ddd4a16d6bc3f 100644
--- a/polly/lib/External/isl/isl_scheduler.c
+++ b/polly/lib/External/isl/isl_scheduler.c
@@ -40,6 +40,9 @@
#include <isl/ilp.h>
#include <isl_val_private.h>
+#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 @@ static isl_stat extract_edge(__isl_take isl_map *map, void *user)
* 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 @@ static __isl_give isl_aff *extract_schedule_row(__isl_take isl_local_space *ls,
*
* 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
diff erent dependences impose
diff erent 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 @@ static int has_violated_conditional_constraint(isl_ctx *ctx,
/* 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 @@ static int has_violated_conditional_constraint(isl_ctx *ctx,
* 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
diff erences. Finally, check if these
diff erences 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
diff erences 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 @@ static __isl_give isl_schedule_node *compute_schedule_wcc_clustering(
* 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 0000000000000..d5d68e484c483
--- /dev/null
+++ b/polly/lib/External/isl/isl_scheduler.h
@@ -0,0 +1,289 @@
+#ifndef ISL_SCHEDULER_H
+#define ISL_SCHEDULER_H
+
+#include <isl/aff_type.h>
+#include <isl/hash.h>
+#include <isl/id_type.h>
+#include <isl/map_type.h>
+#include <isl/map_to_basic_set.h>
+#include <isl/mat.h>
+#include <isl/space_type.h>
+#include <isl/set_type.h>
+#include <isl/val_type.h>
+#include <isl/vec.h>
+#include <isl/union_map_type.h>
+
+#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 0000000000000..c2e91c90546ab
--- /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 <isl/id.h>
+#include <isl/schedule_node.h>
+#include <isl/union_set.h>
+
+#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
diff erences. Finally, check if these
diff erences 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
diff erences 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 0000000000000..bc003267ef59a
--- /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 0000000000000..ffbcfe25dea45
--- /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 <stdio.h>
+
+#include <isl/ctx.h>
+#include <isl/schedule_node.h>
+#include <isl/union_set.h>
+
+#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
diff erent 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
diff erent 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
diff erent 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 0000000000000..e92c5e163f7ea
--- /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 <isl/ctx.h>
+
+#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 86206d0e4ef5a..6067821ee29a0 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 <isl/hmap_templ.c>
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 862afaab2c45b..cca3cbb5c480a 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 <isl/hmap.h>
#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 fd67a89c65a64..16c7d6455ef04 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 140749e73a18c..dd656d81b8097 100644
--- a/polly/lib/External/isl/isl_space_private.h
+++ b/polly/lib/External/isl/isl_space_private.h
@@ -4,6 +4,7 @@
#include <isl/space.h>
#include <isl/hash.h>
#include <isl/id_type.h>
+#include <isl/stream.h>
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 1052360aa326a..9fffd45bf1521 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 0000000000000..0e889989461f7
--- /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 0000000000000..59111c6a08c84
--- /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 2d1c027062d7f..df5cacc34267a 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 4152735682fd6..5f528f918c37f 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 b580245b628d5..a7df7ab4452f1 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 <isl/lp.h>
#include <isl/map.h>
#include <isl/mat.h>
diff --git a/polly/lib/External/isl/isl_test.c b/polly/lib/External/isl/isl_test.c
index 2d0965097c47b..7048302190d86 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 <assert.h>
@@ -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 7b64d6ffaa244..54e7ee5e5fb76 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 <assert.h>
#include <stdlib.h>
@@ -28,6 +47,30 @@ static binary_fn<A1, R, T> const arg(const binary_fn<A1, R, T> &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 <typename A1, typename A2, typename R, typename T>
+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 <typename A1, typename A2, typename R, typename T>
+static ternary_fn<A1, A2, R, T> const arg(const ternary_fn<A1, A2, R, T> &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
@@ -60,6 +112,31 @@ static bool is_equal(const T &a, const T &b)
#define THROW_INVALID(msg) \
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 <typename R, typename T>
+static void test(isl::ctx ctx, R (T::*fn)() const, const std::string &name,
+ const std::vector<unary> &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 <typename R, typename T, typename A1, typename A2>
+static void test(isl::ctx ctx, R (T::*fn)(A1, A2) const,
+ const std::string &name, const std::vector<ternary> &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::val>(&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::id>(&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::id_list>(&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::multi_val>(&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::multi_val>(&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::multi_val>(&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::multi_val>(&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, isl::id>(&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<std::pair<const char *, void (*)(isl::ctx)>> 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 d606a21f8abbb..01308d171859c 100644
--- a/polly/lib/External/isl/isl_test_cpp.cc
+++ b/polly/lib/External/isl/isl_test_cpp.cc
@@ -12,6 +12,8 @@
#include <stdlib.h>
#include <string.h>
+#include <map>
+
#include <isl/options.h>
#include <isl/typed_cpp.h>
@@ -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<std::string, isl::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 0000000000000..3c213987fe4df
--- /dev/null
+++ b/polly/lib/External/isl/isl_test_cpp17-checked.cc
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+
+#include <exception>
+#include <iostream>
+
+#include <isl/options.h>
+#include <isl/cpp-checked.h>
+
+/* 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 0000000000000..c6b4bab7d439d
--- /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<S>(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<int>();
+ auto maybe_s = id.try_user<std::shared_ptr<S>>();
+ auto maybe_int2 = id2.try_user<int>();
+
+ 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<std::shared_ptr<S>>();
+ 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 0000000000000..5765a1f9ae0bc
--- /dev/null
+++ b/polly/lib/External/isl/isl_test_cpp17.cc
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+
+#include <exception>
+#include <sstream>
+
+#include <isl/options.h>
+#include <isl/cpp.h>
+
+/* 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<void(void)> &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<int>();
+ if (int_user != 5)
+ die("wrong integer retrieved from isl::id");
+ auto s_user = id3.user<std::string>();
+ if (s_user != "s")
+ die("wrong string retrieved from isl::id");
+ check_invalid([&id] () { id.user<std::string>(); });
+ check_invalid([&id2] () { id2.user<int>(); });
+ check_invalid([&id2] () { id2.user<std::string>(); });
+ check_invalid([&id3] () { id3.user<int>(); });
+}
+
+/* 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 443f5a1f4a84d..3894ad1cced91 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 fail(bs):
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 0000000000000..3b60e4db5b579
--- /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 2ea129b514400..eaafe18027037 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 @@ static __isl_give isl_union_map *bin_op(__isl_take isl_union_map *umap1,
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 0000000000000..3995a129193ac
--- /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 e84706c53ba56..cf563422ccf47 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 0000000000000..0def7168a2363
--- /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 d16ccd94aa3ff..875f81405684f 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 @@ static __isl_give UNION *FN(UNION,realign_domain)(__isl_take UNION *u,
__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 @@ static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1,
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
diff erence 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 3744aa74d082b..8b77622d7fb2e 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 <isl_multi_no_domain_templ.c>
#include <isl_multi_no_explicit_domain.c>
#include <isl_multi_templ.c>
+#include <isl_multi_un_op_templ.c>
+#include <isl_multi_bin_val_templ.c>
#include <isl_multi_arith_templ.c>
#include <isl_multi_dim_id_templ.c>
#include <isl_multi_dims.c>
@@ -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 7d0ea18c11a71..323015b8269cb 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 49bcef81f6059..a46f56f88b0b5 100644
--- a/polly/lib/External/isl/isl_vec_private.h
+++ b/polly/lib/External/isl/isl_vec_private.h
@@ -4,6 +4,8 @@
#include <isl_blk.h>
#include <isl/vec.h>
+#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 9e6c1ec011dac..e968ca71dd67c 100644
--- a/polly/lib/External/isl/pip.c
+++ b/polly/lib/External/isl/pip.c
@@ -12,7 +12,6 @@
#include <isl_map_private.h>
#include <isl/aff.h>
#include <isl/set.h>
-#include "isl_tab.h"
#include "isl_sample.h"
#include "isl_scan.h"
#include <isl_seq.h>
@@ -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 5c858c95608a1..d041315d4e11d 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 0000000000000..8ae3240c93b22
--- /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 0000000000000..00f0b7462b58c
--- /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 0000000000000..2c7d8d02a3f85
--- /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 0000000000000..884fa8ce32099
--- /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 0000000000000..5d164584e599f
--- /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 0000000000000..784e07bf5872a
--- /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 0000000000000..b2ffa29ad754c
--- /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 at 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 0000000000000..2275dd6d790fa
--- /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] }"
More information about the llvm-commits
mailing list