[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, &macros);
 
 	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]],
+				&copy_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