[polly] r228193 - Import isl(+imath) as an external library into Polly

Tobias Grosser tobias at grosser.es
Wed Feb 4 12:55:55 PST 2015


Added: polly/trunk/lib/External/isl/isl_coalesce.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_coalesce.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_coalesce.c (added)
+++ polly/trunk/lib/External/isl/isl_coalesce.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1745 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include "isl_map_private.h"
+#include <isl_seq.h>
+#include <isl/options.h>
+#include "isl_tab.h"
+#include <isl_mat_private.h>
+#include <isl_local_space_private.h>
+#include <isl_vec_private.h>
+
+#define STATUS_ERROR		-1
+#define STATUS_REDUNDANT	 1
+#define STATUS_VALID	 	 2
+#define STATUS_SEPARATE	 	 3
+#define STATUS_CUT	 	 4
+#define STATUS_ADJ_EQ	 	 5
+#define STATUS_ADJ_INEQ	 	 6
+
+static int status_in(isl_int *ineq, struct isl_tab *tab)
+{
+	enum isl_ineq_type type = isl_tab_ineq_type(tab, ineq);
+	switch (type) {
+	default:
+	case isl_ineq_error:		return STATUS_ERROR;
+	case isl_ineq_redundant:	return STATUS_VALID;
+	case isl_ineq_separate:		return STATUS_SEPARATE;
+	case isl_ineq_cut:		return STATUS_CUT;
+	case isl_ineq_adj_eq:		return STATUS_ADJ_EQ;
+	case isl_ineq_adj_ineq:		return STATUS_ADJ_INEQ;
+	}
+}
+
+/* Compute the position of the equalities of basic map "bmap_i"
+ * with respect to the basic map represented by "tab_j".
+ * The resulting array has twice as many entries as the number
+ * of equalities corresponding to the two inequalties to which
+ * each equality corresponds.
+ */
+static int *eq_status_in(__isl_keep isl_basic_map *bmap_i,
+	struct isl_tab *tab_j)
+{
+	int k, l;
+	int *eq = isl_calloc_array(bmap_i->ctx, int, 2 * bmap_i->n_eq);
+	unsigned dim;
+
+	if (!eq)
+		return NULL;
+
+	dim = isl_basic_map_total_dim(bmap_i);
+	for (k = 0; k < bmap_i->n_eq; ++k) {
+		for (l = 0; l < 2; ++l) {
+			isl_seq_neg(bmap_i->eq[k], bmap_i->eq[k], 1+dim);
+			eq[2 * k + l] = status_in(bmap_i->eq[k], tab_j);
+			if (eq[2 * k + l] == STATUS_ERROR)
+				goto error;
+		}
+		if (eq[2 * k] == STATUS_SEPARATE ||
+		    eq[2 * k + 1] == STATUS_SEPARATE)
+			break;
+	}
+
+	return eq;
+error:
+	free(eq);
+	return NULL;
+}
+
+/* Compute the position of the inequalities of basic map "bmap_i"
+ * (also represented by "tab_i", if not NULL) with respect to the basic map
+ * represented by "tab_j".
+ */
+static int *ineq_status_in(__isl_keep isl_basic_map *bmap_i,
+	struct isl_tab *tab_i, struct isl_tab *tab_j)
+{
+	int k;
+	unsigned n_eq = bmap_i->n_eq;
+	int *ineq = isl_calloc_array(bmap_i->ctx, int, bmap_i->n_ineq);
+
+	if (!ineq)
+		return NULL;
+
+	for (k = 0; k < bmap_i->n_ineq; ++k) {
+		if (tab_i && isl_tab_is_redundant(tab_i, n_eq + k)) {
+			ineq[k] = STATUS_REDUNDANT;
+			continue;
+		}
+		ineq[k] = status_in(bmap_i->ineq[k], tab_j);
+		if (ineq[k] == STATUS_ERROR)
+			goto error;
+		if (ineq[k] == STATUS_SEPARATE)
+			break;
+	}
+
+	return ineq;
+error:
+	free(ineq);
+	return NULL;
+}
+
+static int any(int *con, unsigned len, int status)
+{
+	int i;
+
+	for (i = 0; i < len ; ++i)
+		if (con[i] == status)
+			return 1;
+	return 0;
+}
+
+static int count(int *con, unsigned len, int status)
+{
+	int i;
+	int c = 0;
+
+	for (i = 0; i < len ; ++i)
+		if (con[i] == status)
+			c++;
+	return c;
+}
+
+static int all(int *con, unsigned len, int status)
+{
+	int i;
+
+	for (i = 0; i < len ; ++i) {
+		if (con[i] == STATUS_REDUNDANT)
+			continue;
+		if (con[i] != status)
+			return 0;
+	}
+	return 1;
+}
+
+static void drop(struct isl_map *map, int i, struct isl_tab **tabs)
+{
+	isl_basic_map_free(map->p[i]);
+	isl_tab_free(tabs[i]);
+
+	if (i != map->n - 1) {
+		map->p[i] = map->p[map->n - 1];
+		tabs[i] = tabs[map->n - 1];
+	}
+	tabs[map->n - 1] = NULL;
+	map->n--;
+}
+
+/* Replace the pair of basic maps i and j by the basic map bounded
+ * by the valid constraints in both basic maps and the constraint
+ * in extra (if not NULL).
+ */
+static int fuse(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j,
+	__isl_keep isl_mat *extra)
+{
+	int k, l;
+	struct isl_basic_map *fused = NULL;
+	struct isl_tab *fused_tab = NULL;
+	unsigned total = isl_basic_map_total_dim(map->p[i]);
+	unsigned extra_rows = extra ? extra->n_row : 0;
+
+	fused = isl_basic_map_alloc_space(isl_space_copy(map->p[i]->dim),
+			map->p[i]->n_div,
+			map->p[i]->n_eq + map->p[j]->n_eq,
+			map->p[i]->n_ineq + map->p[j]->n_ineq + extra_rows);
+	if (!fused)
+		goto error;
+
+	for (k = 0; k < map->p[i]->n_eq; ++k) {
+		if (eq_i && (eq_i[2 * k] != STATUS_VALID ||
+			     eq_i[2 * k + 1] != STATUS_VALID))
+			continue;
+		l = isl_basic_map_alloc_equality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->eq[l], map->p[i]->eq[k], 1 + total);
+	}
+
+	for (k = 0; k < map->p[j]->n_eq; ++k) {
+		if (eq_j && (eq_j[2 * k] != STATUS_VALID ||
+			     eq_j[2 * k + 1] != STATUS_VALID))
+			continue;
+		l = isl_basic_map_alloc_equality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->eq[l], map->p[j]->eq[k], 1 + total);
+	}
+
+	for (k = 0; k < map->p[i]->n_ineq; ++k) {
+		if (ineq_i[k] != STATUS_VALID)
+			continue;
+		l = isl_basic_map_alloc_inequality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->ineq[l], map->p[i]->ineq[k], 1 + total);
+	}
+
+	for (k = 0; k < map->p[j]->n_ineq; ++k) {
+		if (ineq_j[k] != STATUS_VALID)
+			continue;
+		l = isl_basic_map_alloc_inequality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->ineq[l], map->p[j]->ineq[k], 1 + total);
+	}
+
+	for (k = 0; k < map->p[i]->n_div; ++k) {
+		int l = isl_basic_map_alloc_div(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->div[l], map->p[i]->div[k], 1 + 1 + total);
+	}
+
+	for (k = 0; k < extra_rows; ++k) {
+		l = isl_basic_map_alloc_inequality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total);
+	}
+
+	fused = isl_basic_map_gauss(fused, NULL);
+	ISL_F_SET(fused, ISL_BASIC_MAP_FINAL);
+	if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) &&
+	    ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL))
+		ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL);
+
+	fused_tab = isl_tab_from_basic_map(fused, 0);
+	if (isl_tab_detect_redundant(fused_tab) < 0)
+		goto error;
+
+	isl_basic_map_free(map->p[i]);
+	map->p[i] = fused;
+	isl_tab_free(tabs[i]);
+	tabs[i] = fused_tab;
+	drop(map, j, tabs);
+
+	return 1;
+error:
+	isl_tab_free(fused_tab);
+	isl_basic_map_free(fused);
+	return -1;
+}
+
+/* Given a pair of basic maps i and j such that all constraints are either
+ * "valid" or "cut", check if the facets corresponding to the "cut"
+ * constraints of i lie entirely within basic map j.
+ * If so, replace the pair by the basic map consisting of the valid
+ * constraints in both basic maps.
+ *
+ * To see that we are not introducing any extra points, call the
+ * two basic maps A and B and the resulting map U and let x
+ * be an element of U \setminus ( A \cup B ).
+ * Then there is a pair of cut constraints c_1 and c_2 in A and B such that x
+ * violates them.  Let X be the intersection of U with the opposites
+ * of these constraints.  Then x \in X.
+ * The facet corresponding to c_1 contains the corresponding facet of A.
+ * This facet is entirely contained in B, so c_2 is valid on the facet.
+ * However, since it is also (part of) a facet of X, -c_2 is also valid
+ * on the facet.  This means c_2 is saturated on the facet, so c_1 and
+ * c_2 must be opposites of each other, but then x could not violate
+ * both of them.
+ */
+static int check_facets(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *ineq_i, int *ineq_j)
+{
+	int k, l;
+	struct isl_tab_undo *snap;
+	unsigned n_eq = map->p[i]->n_eq;
+
+	snap = isl_tab_snap(tabs[i]);
+
+	for (k = 0; k < map->p[i]->n_ineq; ++k) {
+		if (ineq_i[k] != STATUS_CUT)
+			continue;
+		if (isl_tab_select_facet(tabs[i], n_eq + k) < 0)
+			return -1;
+		for (l = 0; l < map->p[j]->n_ineq; ++l) {
+			int stat;
+			if (ineq_j[l] != STATUS_CUT)
+				continue;
+			stat = status_in(map->p[j]->ineq[l], tabs[i]);
+			if (stat != STATUS_VALID)
+				break;
+		}
+		if (isl_tab_rollback(tabs[i], snap) < 0)
+			return -1;
+		if (l < map->p[j]->n_ineq)
+			break;
+	}
+
+	if (k < map->p[i]->n_ineq)
+		/* BAD CUT PAIR */
+		return 0;
+	return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
+}
+
+/* Check if basic map "i" contains the basic map represented
+ * by the tableau "tab".
+ */
+static int contains(struct isl_map *map, int i, int *ineq_i,
+	struct isl_tab *tab)
+{
+	int k, l;
+	unsigned dim;
+
+	dim = isl_basic_map_total_dim(map->p[i]);
+	for (k = 0; k < map->p[i]->n_eq; ++k) {
+		for (l = 0; l < 2; ++l) {
+			int stat;
+			isl_seq_neg(map->p[i]->eq[k], map->p[i]->eq[k], 1+dim);
+			stat = status_in(map->p[i]->eq[k], tab);
+			if (stat != STATUS_VALID)
+				return 0;
+		}
+	}
+
+	for (k = 0; k < map->p[i]->n_ineq; ++k) {
+		int stat;
+		if (ineq_i[k] == STATUS_REDUNDANT)
+			continue;
+		stat = status_in(map->p[i]->ineq[k], tab);
+		if (stat != STATUS_VALID)
+			return 0;
+	}
+	return 1;
+}
+
+/* Basic map "i" has an inequality (say "k") that is adjacent
+ * to some inequality of basic map "j".  All the other inequalities
+ * are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * Note that this function is only called if some of the equalities or
+ * inequalities of basic map "j" do cut basic map "i".  The function is
+ * correct even if there are no such cut constraints, but in that case
+ * the additional checks performed by this function are overkill.
+ *
+ * In particular, we replace constraint k, say f >= 0, by constraint
+ * f <= -1, add the inequalities of "j" that are valid for "i"
+ * and check if the result is a subset of basic map "j".
+ * If so, then we know that this result is exactly equal to basic map "j"
+ * since all its constraints are valid for basic map "j".
+ * By combining the valid constraints of "i" (all equalities and all
+ * inequalities except "k") and the valid constraints of "j" we therefore
+ * obtain a basic map that is equal to their union.
+ * In this case, there is no need to perform a rollback of the tableau
+ * since it is going to be destroyed in fuse().
+ *
+ *
+ *	|\__			|\__
+ *	|   \__			|   \__
+ *	|      \_	=>	|      \__
+ *	|_______| _		|_________\
+ *
+ *
+ *	|\			|\
+ *	| \			| \
+ *	|  \			|  \
+ *	|  |			|   \
+ *	|  ||\		=>      |    \
+ *	|  || \			|     \
+ *	|  ||  |		|      |
+ *	|__||_/			|_____/
+ */
+static int is_adj_ineq_extension(__isl_keep isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int k;
+	struct isl_tab_undo *snap;
+	unsigned n_eq = map->p[i]->n_eq;
+	unsigned total = isl_basic_map_total_dim(map->p[i]);
+	int r;
+
+	if (isl_tab_extend_cons(tabs[i], 1 + map->p[j]->n_ineq) < 0)
+		return -1;
+
+	for (k = 0; k < map->p[i]->n_ineq; ++k)
+		if (ineq_i[k] == STATUS_ADJ_INEQ)
+			break;
+	if (k >= map->p[i]->n_ineq)
+		isl_die(isl_map_get_ctx(map), isl_error_internal,
+			"ineq_i should have exactly one STATUS_ADJ_INEQ",
+			return -1);
+
+	snap = isl_tab_snap(tabs[i]);
+
+	if (isl_tab_unrestrict(tabs[i], n_eq + k) < 0)
+		return -1;
+
+	isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+	isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+	r = isl_tab_add_ineq(tabs[i], map->p[i]->ineq[k]);
+	isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+	isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+	if (r < 0)
+		return -1;
+
+	for (k = 0; k < map->p[j]->n_ineq; ++k) {
+		if (ineq_j[k] != STATUS_VALID)
+			continue;
+		if (isl_tab_add_ineq(tabs[i], map->p[j]->ineq[k]) < 0)
+			return -1;
+	}
+
+	if (contains(map, j, ineq_j, tabs[i]))
+		return fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, NULL);
+
+	if (isl_tab_rollback(tabs[i], snap) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+/* Both basic maps have at least one inequality with and adjacent
+ * (but opposite) inequality in the other basic map.
+ * Check that there are no cut constraints and that there is only
+ * a single pair of adjacent inequalities.
+ * If so, we can replace the pair by a single basic map described
+ * by all but the pair of adjacent inequalities.
+ * Any additional points introduced lie strictly between the two
+ * adjacent hyperplanes and can therefore be integral.
+ *
+ *        ____			  _____
+ *       /    ||\		 /     \
+ *      /     || \		/       \
+ *      \     ||  \	=>	\        \
+ *       \    ||  /		 \       /
+ *        \___||_/		  \_____/
+ *
+ * The test for a single pair of adjancent inequalities is important
+ * for avoiding the combination of two basic maps like the following
+ *
+ *       /|
+ *      / |
+ *     /__|
+ *         _____
+ *         |   |
+ *         |   |
+ *         |___|
+ *
+ * If there are some cut constraints on one side, then we may
+ * still be able to fuse the two basic maps, but we need to perform
+ * some additional checks in is_adj_ineq_extension.
+ */
+static int check_adj_ineq(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int count_i, count_j;
+	int cut_i, cut_j;
+
+	count_i = count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ);
+	count_j = count(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ);
+
+	if (count_i != 1 && count_j != 1)
+		return 0;
+
+	cut_i = any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) ||
+		any(ineq_i, map->p[i]->n_ineq, STATUS_CUT);
+	cut_j = any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT) ||
+		any(ineq_j, map->p[j]->n_ineq, STATUS_CUT);
+
+	if (!cut_i && !cut_j && count_i == 1 && count_j == 1)
+		return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
+
+	if (count_i == 1 && !cut_i)
+		return is_adj_ineq_extension(map, i, j, tabs,
+						eq_i, ineq_i, eq_j, ineq_j);
+
+	if (count_j == 1 && !cut_j)
+		return is_adj_ineq_extension(map, j, i, tabs,
+						eq_j, ineq_j, eq_i, ineq_i);
+
+	return 0;
+}
+
+/* Basic map "i" has an inequality "k" that is adjacent to some equality
+ * of basic map "j".  All the other inequalities are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * In particular, we relax constraint "k", compute the corresponding
+ * facet and check whether it is included in the other basic map.
+ * If so, we know that relaxing the constraint extends the basic
+ * map with exactly the other basic map (we already know that this
+ * other basic map is included in the extension, because there
+ * were no "cut" inequalities in "i") and we can replace the
+ * two basic maps by this extension.
+ *        ____			  _____
+ *       /    || 		 /     |
+ *      /     ||  		/      |
+ *      \     ||   	=>	\      |
+ *       \    ||		 \     |
+ *        \___||		  \____|
+ */
+static int is_adj_eq_extension(struct isl_map *map, int i, int j, int k,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+	int super;
+	struct isl_tab_undo *snap, *snap2;
+	unsigned n_eq = map->p[i]->n_eq;
+
+	if (isl_tab_is_equality(tabs[i], n_eq + k))
+		return 0;
+
+	snap = isl_tab_snap(tabs[i]);
+	tabs[i] = isl_tab_relax(tabs[i], n_eq + k);
+	snap2 = isl_tab_snap(tabs[i]);
+	if (isl_tab_select_facet(tabs[i], n_eq + k) < 0)
+		return -1;
+	super = contains(map, j, ineq_j, tabs[i]);
+	if (super) {
+		if (isl_tab_rollback(tabs[i], snap2) < 0)
+			return -1;
+		map->p[i] = isl_basic_map_cow(map->p[i]);
+		if (!map->p[i])
+			return -1;
+		isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+		ISL_F_SET(map->p[i], ISL_BASIC_MAP_FINAL);
+		drop(map, j, tabs);
+		changed = 1;
+	} else
+		if (isl_tab_rollback(tabs[i], snap) < 0)
+			return -1;
+
+	return changed;
+}
+
+/* Data structure that keeps track of the wrapping constraints
+ * and of information to bound the coefficients of those constraints.
+ *
+ * bound is set if we want to apply a bound on the coefficients
+ * mat contains the wrapping constraints
+ * max is the bound on the coefficients (if bound is set)
+ */
+struct isl_wraps {
+	int bound;
+	isl_mat *mat;
+	isl_int max;
+};
+
+/* Update wraps->max to be greater than or equal to the coefficients
+ * in the equalities and inequalities of bmap that can be removed if we end up
+ * applying wrapping.
+ */
+static void wraps_update_max(struct isl_wraps *wraps,
+	__isl_keep isl_basic_map *bmap, int *eq, int *ineq)
+{
+	int k;
+	isl_int max_k;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	isl_int_init(max_k);
+
+	for (k = 0; k < bmap->n_eq; ++k) {
+		if (eq[2 * k] == STATUS_VALID &&
+		    eq[2 * k + 1] == STATUS_VALID)
+			continue;
+		isl_seq_abs_max(bmap->eq[k] + 1, total, &max_k);
+		if (isl_int_abs_gt(max_k, wraps->max))
+			isl_int_set(wraps->max, max_k);
+	}
+
+	for (k = 0; k < bmap->n_ineq; ++k) {
+		if (ineq[k] == STATUS_VALID || ineq[k] == STATUS_REDUNDANT)
+			continue;
+		isl_seq_abs_max(bmap->ineq[k] + 1, total, &max_k);
+		if (isl_int_abs_gt(max_k, wraps->max))
+			isl_int_set(wraps->max, max_k);
+	}
+
+	isl_int_clear(max_k);
+}
+
+/* Initialize the isl_wraps data structure.
+ * If we want to bound the coefficients of the wrapping constraints,
+ * we set wraps->max to the largest coefficient
+ * in the equalities and inequalities that can be removed if we end up
+ * applying wrapping.
+ */
+static void wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat,
+	__isl_keep isl_map *map, int i, int j,
+	int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	isl_ctx *ctx;
+
+	wraps->bound = 0;
+	wraps->mat = mat;
+	if (!mat)
+		return;
+	ctx = isl_mat_get_ctx(mat);
+	wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx);
+	if (!wraps->bound)
+		return;
+	isl_int_init(wraps->max);
+	isl_int_set_si(wraps->max, 0);
+	wraps_update_max(wraps, map->p[i], eq_i, ineq_i);
+	wraps_update_max(wraps, map->p[j], eq_j, ineq_j);
+}
+
+/* Free the contents of the isl_wraps data structure.
+ */
+static void wraps_free(struct isl_wraps *wraps)
+{
+	isl_mat_free(wraps->mat);
+	if (wraps->bound)
+		isl_int_clear(wraps->max);
+}
+
+/* Is the wrapping constraint in row "row" allowed?
+ *
+ * If wraps->bound is set, we check that none of the coefficients
+ * is greater than wraps->max.
+ */
+static int allow_wrap(struct isl_wraps *wraps, int row)
+{
+	int i;
+
+	if (!wraps->bound)
+		return 1;
+
+	for (i = 1; i < wraps->mat->n_col; ++i)
+		if (isl_int_abs_gt(wraps->mat->row[row][i], wraps->max))
+			return 0;
+
+	return 1;
+}
+
+/* For each non-redundant constraint in "bmap" (as determined by "tab"),
+ * wrap the constraint around "bound" such that it includes the whole
+ * set "set" and append the resulting constraint to "wraps".
+ * "wraps" is assumed to have been pre-allocated to the appropriate size.
+ * wraps->n_row is the number of actual wrapped constraints that have
+ * been added.
+ * If any of the wrapping problems results in a constraint that is
+ * identical to "bound", then this means that "set" is unbounded in such
+ * way that no wrapping is possible.  If this happens then wraps->n_row
+ * is reset to zero.
+ * Similarly, if we want to bound the coefficients of the wrapping
+ * constraints and a newly added wrapping constraint does not
+ * satisfy the bound, then wraps->n_row is also reset to zero.
+ */
+static int add_wraps(struct isl_wraps *wraps, __isl_keep isl_basic_map *bmap,
+	struct isl_tab *tab, isl_int *bound, __isl_keep isl_set *set)
+{
+	int l;
+	int w;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	w = wraps->mat->n_row;
+
+	for (l = 0; l < bmap->n_ineq; ++l) {
+		if (isl_seq_is_neg(bound, bmap->ineq[l], 1 + total))
+			continue;
+		if (isl_seq_eq(bound, bmap->ineq[l], 1 + total))
+			continue;
+		if (isl_tab_is_redundant(tab, bmap->n_eq + l))
+			continue;
+
+		isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+		if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->ineq[l]))
+			return -1;
+		if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+			goto unbounded;
+		if (!allow_wrap(wraps, w))
+			goto unbounded;
+		++w;
+	}
+	for (l = 0; l < bmap->n_eq; ++l) {
+		if (isl_seq_is_neg(bound, bmap->eq[l], 1 + total))
+			continue;
+		if (isl_seq_eq(bound, bmap->eq[l], 1 + total))
+			continue;
+
+		isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+		isl_seq_neg(wraps->mat->row[w + 1], bmap->eq[l], 1 + total);
+		if (!isl_set_wrap_facet(set, wraps->mat->row[w],
+					wraps->mat->row[w + 1]))
+			return -1;
+		if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+			goto unbounded;
+		if (!allow_wrap(wraps, w))
+			goto unbounded;
+		++w;
+
+		isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+		if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->eq[l]))
+			return -1;
+		if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+			goto unbounded;
+		if (!allow_wrap(wraps, w))
+			goto unbounded;
+		++w;
+	}
+
+	wraps->mat->n_row = w;
+	return 0;
+unbounded:
+	wraps->mat->n_row = 0;
+	return 0;
+}
+
+/* Check if the constraints in "wraps" from "first" until the last
+ * are all valid for the basic set represented by "tab".
+ * If not, wraps->n_row is set to zero.
+ */
+static int check_wraps(__isl_keep isl_mat *wraps, int first,
+	struct isl_tab *tab)
+{
+	int i;
+
+	for (i = first; i < wraps->n_row; ++i) {
+		enum isl_ineq_type type;
+		type = isl_tab_ineq_type(tab, wraps->row[i]);
+		if (type == isl_ineq_error)
+			return -1;
+		if (type == isl_ineq_redundant)
+			continue;
+		wraps->n_row = 0;
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Return a set that corresponds to the non-redudant constraints
+ * (as recorded in tab) of bmap.
+ *
+ * It's important to remove the redundant constraints as some
+ * of the other constraints may have been modified after the
+ * constraints were marked redundant.
+ * In particular, a constraint may have been relaxed.
+ * Redundant constraints are ignored when a constraint is relaxed
+ * and should therefore continue to be ignored ever after.
+ * Otherwise, the relaxation might be thwarted by some of
+ * these constraints.
+ */
+static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap,
+	struct isl_tab *tab)
+{
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_update_from_tab(bmap, tab);
+	return isl_set_from_basic_set(isl_basic_map_underlying_set(bmap));
+}
+
+/* Given a basic set i with a constraint k that is adjacent to either the
+ * whole of basic set j or a facet of basic set j, check if we can wrap
+ * both the facet corresponding to k and the facet of j (or the whole of j)
+ * around their ridges to include the other set.
+ * If so, replace the pair of basic sets by their union.
+ *
+ * All constraints of i (except k) are assumed to be valid for j.
+ *
+ * However, the constraints of j may not be valid for i and so
+ * we have to check that the wrapping constraints for j are valid for i.
+ *
+ * In the case where j has a facet adjacent to i, tab[j] is assumed
+ * to have been restricted to this facet, so that the non-redundant
+ * constraints in tab[j] are the ridges of the facet.
+ * Note that for the purpose of wrapping, it does not matter whether
+ * we wrap the ridges of i around the whole of j or just around
+ * the facet since all the other constraints are assumed to be valid for j.
+ * In practice, we wrap to include the whole of j.
+ *        ____			  _____
+ *       /    | 		 /     \
+ *      /     ||  		/      |
+ *      \     ||   	=>	\      |
+ *       \    ||		 \     |
+ *        \___||		  \____|
+ *
+ */
+static int can_wrap_in_facet(struct isl_map *map, int i, int j, int k,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+	struct isl_wraps wraps;
+	isl_mat *mat;
+	struct isl_set *set_i = NULL;
+	struct isl_set *set_j = NULL;
+	struct isl_vec *bound = NULL;
+	unsigned total = isl_basic_map_total_dim(map->p[i]);
+	struct isl_tab_undo *snap;
+	int n;
+
+	set_i = set_from_updated_bmap(map->p[i], tabs[i]);
+	set_j = set_from_updated_bmap(map->p[j], tabs[j]);
+	mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+					map->p[i]->n_ineq + map->p[j]->n_ineq,
+					1 + total);
+	wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+	bound = isl_vec_alloc(map->ctx, 1 + total);
+	if (!set_i || !set_j || !wraps.mat || !bound)
+		goto error;
+
+	isl_seq_cpy(bound->el, map->p[i]->ineq[k], 1 + total);
+	isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+	isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+	wraps.mat->n_row = 1;
+
+	if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	snap = isl_tab_snap(tabs[i]);
+
+	if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + k) < 0)
+		goto error;
+	if (isl_tab_detect_redundant(tabs[i]) < 0)
+		goto error;
+
+	isl_seq_neg(bound->el, map->p[i]->ineq[k], 1 + total);
+
+	n = wraps.mat->n_row;
+	if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0)
+		goto error;
+
+	if (isl_tab_rollback(tabs[i], snap) < 0)
+		goto error;
+	if (check_wraps(wraps.mat, n, tabs[i]) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+unbounded:
+	wraps_free(&wraps);
+
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+
+	isl_vec_free(bound);
+
+	return changed;
+error:
+	wraps_free(&wraps);
+	isl_vec_free(bound);
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+	return -1;
+}
+
+/* Set the is_redundant property of the "n" constraints in "cuts",
+ * except "k" to "v".
+ * This is a fairly tricky operation as it bypasses isl_tab.c.
+ * The reason we want to temporarily mark some constraints redundant
+ * is that we want to ignore them in add_wraps.
+ *
+ * Initially all cut constraints are non-redundant, but the
+ * selection of a facet right before the call to this function
+ * may have made some of them redundant.
+ * Likewise, the same constraints are marked non-redundant
+ * in the second call to this function, before they are officially
+ * made non-redundant again in the subsequent rollback.
+ */
+static void set_is_redundant(struct isl_tab *tab, unsigned n_eq,
+	int *cuts, int n, int k, int v)
+{
+	int l;
+
+	for (l = 0; l < n; ++l) {
+		if (l == k)
+			continue;
+		tab->con[n_eq + cuts[l]].is_redundant = v;
+	}
+}
+
+/* Given a pair of basic maps i and j such that j sticks out
+ * of i at n cut constraints, each time by at most one,
+ * try to compute wrapping constraints and replace the two
+ * basic maps by a single basic map.
+ * The other constraints of i are assumed to be valid for j.
+ *
+ * The facets of i corresponding to the cut constraints are
+ * wrapped around their ridges, except those ridges determined
+ * by any of the other cut constraints.
+ * The intersections of cut constraints need to be ignored
+ * as the result of wrapping one cut constraint around another
+ * would result in a constraint cutting the union.
+ * In each case, the facets are wrapped to include the union
+ * of the two basic maps.
+ *
+ * The pieces of j that lie at an offset of exactly one from
+ * one of the cut constraints of i are wrapped around their edges.
+ * Here, there is no need to ignore intersections because we
+ * are wrapping around the union of the two basic maps.
+ *
+ * If any wrapping fails, i.e., if we cannot wrap to touch
+ * the union, then we give up.
+ * Otherwise, the pair of basic maps is replaced by their union.
+ */
+static int wrap_in_facets(struct isl_map *map, int i, int j,
+	int *cuts, int n, struct isl_tab **tabs,
+	int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+	struct isl_wraps wraps;
+	isl_mat *mat;
+	isl_set *set = NULL;
+	isl_vec *bound = NULL;
+	unsigned total = isl_basic_map_total_dim(map->p[i]);
+	int max_wrap;
+	int k;
+	struct isl_tab_undo *snap_i, *snap_j;
+
+	if (isl_tab_extend_cons(tabs[j], 1) < 0)
+		goto error;
+
+	max_wrap = 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+		    map->p[i]->n_ineq + map->p[j]->n_ineq;
+	max_wrap *= n;
+
+	set = isl_set_union(set_from_updated_bmap(map->p[i], tabs[i]),
+			    set_from_updated_bmap(map->p[j], tabs[j]));
+	mat = isl_mat_alloc(map->ctx, max_wrap, 1 + total);
+	wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+	bound = isl_vec_alloc(map->ctx, 1 + total);
+	if (!set || !wraps.mat || !bound)
+		goto error;
+
+	snap_i = isl_tab_snap(tabs[i]);
+	snap_j = isl_tab_snap(tabs[j]);
+
+	wraps.mat->n_row = 0;
+
+	for (k = 0; k < n; ++k) {
+		if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + cuts[k]) < 0)
+			goto error;
+		if (isl_tab_detect_redundant(tabs[i]) < 0)
+			goto error;
+		set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 1);
+
+		isl_seq_neg(bound->el, map->p[i]->ineq[cuts[k]], 1 + total);
+		if (!tabs[i]->empty &&
+		    add_wraps(&wraps, map->p[i], tabs[i], bound->el, set) < 0)
+			goto error;
+
+		set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 0);
+		if (isl_tab_rollback(tabs[i], snap_i) < 0)
+			goto error;
+
+		if (tabs[i]->empty)
+			break;
+		if (!wraps.mat->n_row)
+			break;
+
+		isl_seq_cpy(bound->el, map->p[i]->ineq[cuts[k]], 1 + total);
+		isl_int_add_ui(bound->el[0], bound->el[0], 1);
+		if (isl_tab_add_eq(tabs[j], bound->el) < 0)
+			goto error;
+		if (isl_tab_detect_redundant(tabs[j]) < 0)
+			goto error;
+
+		if (!tabs[j]->empty &&
+		    add_wraps(&wraps, map->p[j], tabs[j], bound->el, set) < 0)
+			goto error;
+
+		if (isl_tab_rollback(tabs[j], snap_j) < 0)
+			goto error;
+
+		if (!wraps.mat->n_row)
+			break;
+	}
+
+	if (k == n)
+		changed = fuse(map, i, j, tabs,
+				eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+	isl_vec_free(bound);
+	wraps_free(&wraps);
+	isl_set_free(set);
+
+	return changed;
+error:
+	isl_vec_free(bound);
+	wraps_free(&wraps);
+	isl_set_free(set);
+	return -1;
+}
+
+/* Given two basic sets i and j such that i has no cut equalities,
+ * check if relaxing all the cut inequalities of i by one turns
+ * them into valid constraint for j and check if we can wrap in
+ * the bits that are sticking out.
+ * If so, replace the pair by their union.
+ *
+ * We first check if all relaxed cut inequalities of i are valid for j
+ * and then try to wrap in the intersections of the relaxed cut inequalities
+ * with j.
+ *
+ * During this wrapping, we consider the points of j that lie at a distance
+ * of exactly 1 from i.  In particular, we ignore the points that lie in
+ * between this lower-dimensional space and the basic map i.
+ * We can therefore only apply this to integer maps.
+ *        ____			  _____
+ *       / ___|_		 /     \
+ *      / |    |  		/      |
+ *      \ |    |   	=>	\      |
+ *       \|____|		 \     |
+ *        \___| 		  \____/
+ *
+ *	 _____			 ______
+ *	| ____|_		|      \
+ *	| |     |		|       |
+ *	| |	|	=>	|       |
+ *	|_|     |		|       |
+ *	  |_____|		 \______|
+ *
+ *	 _______
+ *	|       |
+ *	|  |\   |
+ *	|  | \  |
+ *	|  |  \ |
+ *	|  |   \|
+ *	|  |    \
+ *	|  |_____\
+ *	|       |
+ *	|_______|
+ *
+ * Wrapping can fail if the result of wrapping one of the facets
+ * around its edges does not produce any new facet constraint.
+ * In particular, this happens when we try to wrap in unbounded sets.
+ *
+ *	 _______________________________________________________________________
+ *	|
+ *	|  ___
+ *	| |   |
+ *	|_|   |_________________________________________________________________
+ *	  |___|
+ *
+ * The following is not an acceptable result of coalescing the above two
+ * sets as it includes extra integer points.
+ *	 _______________________________________________________________________
+ *	|
+ *	|     
+ *	|      
+ *	|
+ *	 \______________________________________________________________________
+ */
+static int can_wrap_in_set(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+	int k, m;
+	int n;
+	int *cuts = NULL;
+
+	if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) ||
+	    ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL))
+		return 0;
+
+	n = count(ineq_i, map->p[i]->n_ineq, STATUS_CUT);
+	if (n == 0)
+		return 0;
+
+	cuts = isl_alloc_array(map->ctx, int, n);
+	if (!cuts)
+		return -1;
+
+	for (k = 0, m = 0; m < n; ++k) {
+		enum isl_ineq_type type;
+
+		if (ineq_i[k] != STATUS_CUT)
+			continue;
+
+		isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+		type = isl_tab_ineq_type(tabs[j], map->p[i]->ineq[k]);
+		isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+		if (type == isl_ineq_error)
+			goto error;
+		if (type != isl_ineq_redundant)
+			break;
+		cuts[m] = k;
+		++m;
+	}
+
+	if (m == n)
+		changed = wrap_in_facets(map, i, j, cuts, n, tabs,
+					 eq_i, ineq_i, eq_j, ineq_j);
+
+	free(cuts);
+
+	return changed;
+error:
+	free(cuts);
+	return -1;
+}
+
+/* Check if either i or j has a single cut constraint that can
+ * be used to wrap in (a facet of) the other basic set.
+ * if so, replace the pair by their union.
+ */
+static int check_wrap(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+
+	if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT))
+		changed = can_wrap_in_set(map, i, j, tabs,
+					    eq_i, ineq_i, eq_j, ineq_j);
+	if (changed)
+		return changed;
+
+	if (!any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
+		changed = can_wrap_in_set(map, j, i, tabs,
+					    eq_j, ineq_j, eq_i, ineq_i);
+	return changed;
+}
+
+/* At least one of the basic maps has an equality that is adjacent
+ * to inequality.  Make sure that only one of the basic maps has
+ * such an equality and that the other basic map has exactly one
+ * inequality adjacent to an equality.
+ * We call the basic map that has the inequality "i" and the basic
+ * map that has the equality "j".
+ * If "i" has any "cut" (in)equality, then relaxing the inequality
+ * by one would not result in a basic map that contains the other
+ * basic map.
+ */
+static int check_adj_eq(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int changed = 0;
+	int k;
+
+	if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) &&
+	    any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ))
+		/* ADJ EQ TOO MANY */
+		return 0;
+
+	if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ))
+		return check_adj_eq(map, j, i, tabs,
+					eq_j, ineq_j, eq_i, ineq_i);
+
+	/* j has an equality adjacent to an inequality in i */
+
+	if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT))
+		return 0;
+	if (any(ineq_i, map->p[i]->n_ineq, STATUS_CUT))
+		/* ADJ EQ CUT */
+		return 0;
+	if (count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) != 1 ||
+	    any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ) ||
+	    any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) ||
+	    any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ))
+		/* ADJ EQ TOO MANY */
+		return 0;
+
+	for (k = 0; k < map->p[i]->n_ineq; ++k)
+		if (ineq_i[k] == STATUS_ADJ_EQ)
+			break;
+
+	changed = is_adj_eq_extension(map, i, j, k, tabs,
+					eq_i, ineq_i, eq_j, ineq_j);
+	if (changed)
+		return changed;
+
+	if (count(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ) != 1)
+		return 0;
+
+	changed = can_wrap_in_facet(map, i, j, k, tabs, eq_i, ineq_i, eq_j, ineq_j);
+
+	return changed;
+}
+
+/* The two basic maps lie on adjacent hyperplanes.  In particular,
+ * basic map "i" has an equality that lies parallel to basic map "j".
+ * Check if we can wrap the facets around the parallel hyperplanes
+ * to include the other set.
+ *
+ * We perform basically the same operations as can_wrap_in_facet,
+ * except that we don't need to select a facet of one of the sets.
+ *				_
+ *	\\			\\
+ *	 \\		=>	 \\
+ *	  \			  \|
+ *
+ * We only allow one equality of "i" to be adjacent to an equality of "j"
+ * to avoid coalescing
+ *
+ *	[m, n] -> { [x, y] -> [x, 1 + y] : x >= 1 and y >= 1 and
+ *					    x <= 10 and y <= 10;
+ *		    [x, y] -> [1 + x, y] : x >= 1 and x <= 20 and
+ *					    y >= 5 and y <= 15 }
+ *
+ * to
+ *
+ *	[m, n] -> { [x, y] -> [x2, y2] : x >= 1 and 10y2 <= 20 - x + 10y and
+ *					4y2 >= 5 + 3y and 5y2 <= 15 + 4y and
+ *					y2 <= 1 + x + y - x2 and y2 >= y and
+ *					y2 >= 1 + x + y - x2 }
+ */
+static int check_eq_adj_eq(struct isl_map *map, int i, int j,
+	struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+	int k;
+	int changed = 0;
+	struct isl_wraps wraps;
+	isl_mat *mat;
+	struct isl_set *set_i = NULL;
+	struct isl_set *set_j = NULL;
+	struct isl_vec *bound = NULL;
+	unsigned total = isl_basic_map_total_dim(map->p[i]);
+
+	if (count(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ) != 1)
+		return 0;
+
+	for (k = 0; k < 2 * map->p[i]->n_eq ; ++k)
+		if (eq_i[k] == STATUS_ADJ_EQ)
+			break;
+
+	set_i = set_from_updated_bmap(map->p[i], tabs[i]);
+	set_j = set_from_updated_bmap(map->p[j], tabs[j]);
+	mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+					map->p[i]->n_ineq + map->p[j]->n_ineq,
+					1 + total);
+	wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+	bound = isl_vec_alloc(map->ctx, 1 + total);
+	if (!set_i || !set_j || !wraps.mat || !bound)
+		goto error;
+
+	if (k % 2 == 0)
+		isl_seq_neg(bound->el, map->p[i]->eq[k / 2], 1 + total);
+	else
+		isl_seq_cpy(bound->el, map->p[i]->eq[k / 2], 1 + total);
+	isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+	isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+	wraps.mat->n_row = 1;
+
+	if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	isl_int_sub_ui(bound->el[0], bound->el[0], 1);
+	isl_seq_neg(bound->el, bound->el, 1 + total);
+
+	isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total);
+	wraps.mat->n_row++;
+
+	if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+	if (0) {
+error:		changed = -1;
+	}
+unbounded:
+
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+	isl_vec_free(bound);
+
+	return changed;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return 1.
+ * Otherwise, return 0;
+ * The two basic maps are assumed to live in the same local space.
+ *
+ * We first check the effect of each constraint of one basic map
+ * on the other basic map.
+ * The constraint may be
+ *	redundant	the constraint is redundant in its own
+ *			basic map and should be ignore and removed
+ *			in the end
+ *	valid		all (integer) points of the other basic map
+ *			satisfy the constraint
+ *	separate	no (integer) point of the other basic map
+ *			satisfies the constraint
+ *	cut		some but not all points of the other basic map
+ *			satisfy the constraint
+ *	adj_eq		the given constraint is adjacent (on the outside)
+ *			to an equality of the other basic map
+ *	adj_ineq	the given constraint is adjacent (on the outside)
+ *			to an inequality of the other basic map
+ *
+ * We consider seven cases in which we can replace the pair by a single
+ * basic map.  We ignore all "redundant" constraints.
+ *
+ *	1. all constraints of one basic map are valid
+ *		=> the other basic map is a subset and can be removed
+ *
+ *	2. all constraints of both basic maps are either "valid" or "cut"
+ *	   and the facets corresponding to the "cut" constraints
+ *	   of one of the basic maps lies entirely inside the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	3. there is a single pair of adjacent inequalities
+ *	   (all other constraints are "valid")
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	4. one basic map has a single adjacent inequality, while the other
+ *	   constraints are "valid".  The other basic map has some
+ *	   "cut" constraints, but replacing the adjacent inequality by
+ *	   its opposite and adding the valid constraints of the other
+ *	   basic map results in a subset of the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	5. there is a single adjacent pair of an inequality and an equality,
+ *	   the other constraints of the basic map containing the inequality are
+ *	   "valid".  Moreover, if the inequality the basic map is relaxed
+ *	   and then turned into an equality, then resulting facet lies
+ *	   entirely inside the other basic map
+ *		=> the pair can be replaced by the basic map containing
+ *		   the inequality, with the inequality relaxed.
+ *
+ *	6. there is a single adjacent pair of an inequality and an equality,
+ *	   the other constraints of the basic map containing the inequality are
+ *	   "valid".  Moreover, the facets corresponding to both
+ *	   the inequality and the equality can be wrapped around their
+ *	   ridges to include the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps together
+ *		   with all wrapping constraints
+ *
+ *	7. one of the basic maps extends beyond the other by at most one.
+ *	   Moreover, the facets corresponding to the cut constraints and
+ *	   the pieces of the other basic map at offset one from these cut
+ *	   constraints can be wrapped around their ridges to include
+ *	   the union of the two basic maps
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps together
+ *		   with all wrapping constraints
+ *
+ *	8. the two basic maps live in adjacent hyperplanes.  In principle
+ *	   such sets can always be combined through wrapping, but we impose
+ *	   that there is only one such pair, to avoid overeager coalescing.
+ *
+ * Throughout the computation, we maintain a collection of tableaus
+ * corresponding to the basic maps.  When the basic maps are dropped
+ * or combined, the tableaus are modified accordingly.
+ */
+static int coalesce_local_pair(__isl_keep isl_map *map, int i, int j,
+	struct isl_tab **tabs)
+{
+	int changed = 0;
+	int *eq_i = NULL;
+	int *eq_j = NULL;
+	int *ineq_i = NULL;
+	int *ineq_j = NULL;
+
+	eq_i = eq_status_in(map->p[i], tabs[j]);
+	if (map->p[i]->n_eq && !eq_i)
+		goto error;
+	if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ERROR))
+		goto error;
+	if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	eq_j = eq_status_in(map->p[j], tabs[i]);
+	if (map->p[j]->n_eq && !eq_j)
+		goto error;
+	if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ERROR))
+		goto error;
+	if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	ineq_i = ineq_status_in(map->p[i], tabs[i], tabs[j]);
+	if (map->p[i]->n_ineq && !ineq_i)
+		goto error;
+	if (any(ineq_i, map->p[i]->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(ineq_i, map->p[i]->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	ineq_j = ineq_status_in(map->p[j], tabs[j], tabs[i]);
+	if (map->p[j]->n_ineq && !ineq_j)
+		goto error;
+	if (any(ineq_j, map->p[j]->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(ineq_j, map->p[j]->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) &&
+	    all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) {
+		drop(map, j, tabs);
+		changed = 1;
+	} else if (all(eq_j, 2 * map->p[j]->n_eq, STATUS_VALID) &&
+		   all(ineq_j, map->p[j]->n_ineq, STATUS_VALID)) {
+		drop(map, i, tabs);
+		changed = 1;
+	} else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ)) {
+		changed = check_eq_adj_eq(map, i, j, tabs,
+					eq_i, ineq_i, eq_j, ineq_j);
+	} else if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_EQ)) {
+		changed = check_eq_adj_eq(map, j, i, tabs,
+					eq_j, ineq_j, eq_i, ineq_i);
+	} else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) ||
+		   any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ)) {
+		changed = check_adj_eq(map, i, j, tabs,
+					eq_i, ineq_i, eq_j, ineq_j);
+	} else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) ||
+		   any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ)) {
+		/* Can't happen */
+		/* BAD ADJ INEQ */
+	} else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) ||
+		   any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ)) {
+		changed = check_adj_ineq(map, i, j, tabs,
+					eq_i, ineq_i, eq_j, ineq_j);
+	} else {
+		if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) &&
+		    !any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
+			changed = check_facets(map, i, j, tabs, ineq_i, ineq_j);
+		if (!changed)
+			changed = check_wrap(map, i, j, tabs,
+						eq_i, ineq_i, eq_j, ineq_j);
+	}
+
+done:
+	free(eq_i);
+	free(eq_j);
+	free(ineq_i);
+	free(ineq_j);
+	return changed;
+error:
+	free(eq_i);
+	free(eq_j);
+	free(ineq_i);
+	free(ineq_j);
+	return -1;
+}
+
+/* Do the two basic maps live in the same local space, i.e.,
+ * do they have the same (known) divs?
+ * If either basic map has any unknown divs, then we can only assume
+ * that they do not live in the same local space.
+ */
+static int same_divs(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int i;
+	int known;
+	int total;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+	if (bmap1->n_div != bmap2->n_div)
+		return 0;
+
+	if (bmap1->n_div == 0)
+		return 1;
+
+	known = isl_basic_map_divs_known(bmap1);
+	if (known < 0 || !known)
+		return known;
+	known = isl_basic_map_divs_known(bmap2);
+	if (known < 0 || !known)
+		return known;
+
+	total = isl_basic_map_total_dim(bmap1);
+	for (i = 0; i < bmap1->n_div; ++i)
+		if (!isl_seq_eq(bmap1->div[i], bmap2->div[i], 2 + total))
+			return 0;
+
+	return 1;
+}
+
+/* Given two basic maps "i" and "j", where the divs of "i" form a subset
+ * of those of "j", check if basic map "j" is a subset of basic map "i"
+ * and, if so, drop basic map "j".
+ *
+ * We first expand the divs of basic map "i" to match those of basic map "j",
+ * using the divs and expansion computed by the caller.
+ * Then we check if all constraints of the expanded "i" are valid for "j".
+ */
+static int coalesce_subset(__isl_keep isl_map *map, int i, int j,
+	struct isl_tab **tabs, __isl_keep isl_mat *div, int *exp)
+{
+	isl_basic_map *bmap;
+	int changed = 0;
+	int *eq_i = NULL;
+	int *ineq_i = NULL;
+
+	bmap = isl_basic_map_copy(map->p[i]);
+	bmap = isl_basic_set_expand_divs(bmap, isl_mat_copy(div), exp);
+
+	if (!bmap)
+		goto error;
+
+	eq_i = eq_status_in(bmap, tabs[j]);
+	if (bmap->n_eq && !eq_i)
+		goto error;
+	if (any(eq_i, 2 * bmap->n_eq, STATUS_ERROR))
+		goto error;
+	if (any(eq_i, 2 * bmap->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	ineq_i = ineq_status_in(bmap, NULL, tabs[j]);
+	if (bmap->n_ineq && !ineq_i)
+		goto error;
+	if (any(ineq_i, bmap->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(ineq_i, bmap->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) &&
+	    all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) {
+		drop(map, j, tabs);
+		changed = 1;
+	}
+
+done:
+	isl_basic_map_free(bmap);
+	free(eq_i);
+	free(ineq_i);
+	return 0;
+error:
+	isl_basic_map_free(bmap);
+	free(eq_i);
+	free(ineq_i);
+	return -1;
+}
+
+/* Check if the basic map "j" is a subset of basic map "i",
+ * assuming that "i" has fewer divs that "j".
+ * If not, then we change the order.
+ *
+ * If the two basic maps have the same number of divs, then
+ * they must necessarily be different.  Otherwise, we would have
+ * called coalesce_local_pair.  We therefore don't try anything
+ * in this case.
+ *
+ * We first check if the divs of "i" are all known and form a subset
+ * of those of "j".  If so, we pass control over to coalesce_subset.
+ */
+static int check_coalesce_subset(__isl_keep isl_map *map, int i, int j,
+	struct isl_tab **tabs)
+{
+	int known;
+	isl_mat *div_i, *div_j, *div;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	int subset;
+
+	if (map->p[i]->n_div == map->p[j]->n_div)
+		return 0;
+	if (map->p[j]->n_div < map->p[i]->n_div)
+		return check_coalesce_subset(map, j, i, tabs);
+
+	known = isl_basic_map_divs_known(map->p[i]);
+	if (known < 0 || !known)
+		return known;
+
+	ctx = isl_map_get_ctx(map);
+
+	div_i = isl_basic_map_get_divs(map->p[i]);
+	div_j = isl_basic_map_get_divs(map->p[j]);
+
+	if (!div_i || !div_j)
+		goto error;
+
+	exp1 = isl_alloc_array(ctx, int, div_i->n_row);
+	exp2 = isl_alloc_array(ctx, int, div_j->n_row);
+	if ((div_i->n_row && !exp1) || (div_j->n_row && !exp2))
+		goto error;
+
+	div = isl_merge_divs(div_i, div_j, exp1, exp2);
+	if (!div)
+		goto error;
+
+	if (div->n_row == div_j->n_row)
+		subset = coalesce_subset(map, i, j, tabs, div, exp1);
+	else
+		subset = 0;
+
+	isl_mat_free(div);
+
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+
+	free(exp2);
+	free(exp1);
+
+	return subset;
+error:
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+	free(exp1);
+	free(exp2);
+	return -1;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return 1.
+ * Otherwise, return 0;
+ *
+ * We first check if the two basic maps live in the same local space.
+ * If so, we do the complete check.  Otherwise, we check if one is
+ * an obvious subset of the other.
+ */
+static int coalesce_pair(__isl_keep isl_map *map, int i, int j,
+	struct isl_tab **tabs)
+{
+	int same;
+
+	same = same_divs(map->p[i], map->p[j]);
+	if (same < 0)
+		return -1;
+	if (same)
+		return coalesce_local_pair(map, i, j, tabs);
+
+	return check_coalesce_subset(map, i, j, tabs);
+}
+
+static struct isl_map *coalesce(struct isl_map *map, struct isl_tab **tabs)
+{
+	int i, j;
+
+	for (i = map->n - 2; i >= 0; --i)
+restart:
+		for (j = i + 1; j < map->n; ++j) {
+			int changed;
+			changed = coalesce_pair(map, i, j, tabs);
+			if (changed < 0)
+				goto error;
+			if (changed)
+				goto restart;
+		}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* For each pair of basic maps in the map, check if the union of the two
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and start over.
+ *
+ * Since we are constructing the tableaus of the basic maps anyway,
+ * we exploit them to detect implicit equalities and redundant constraints.
+ * This also helps the coalescing as it can ignore the redundant constraints.
+ * In order to avoid confusion, we make all implicit equalities explicit
+ * in the basic maps.  We don't call isl_basic_map_gauss, though,
+ * as that may affect the number of constraints.
+ * This means that we have to call isl_basic_map_gauss at the end
+ * of the computation to ensure that the basic maps are not left
+ * in an unexpected state.
+ */
+struct isl_map *isl_map_coalesce(struct isl_map *map)
+{
+	int i;
+	unsigned n;
+	struct isl_tab **tabs = NULL;
+
+	map = isl_map_remove_empty_parts(map);
+	if (!map)
+		return NULL;
+
+	if (map->n <= 1)
+		return map;
+
+	map = isl_map_sort_divs(map);
+	map = isl_map_cow(map);
+
+	if (!map)
+		return NULL;
+
+	tabs = isl_calloc_array(map->ctx, struct isl_tab *, map->n);
+	if (!tabs)
+		goto error;
+
+	n = map->n;
+	for (i = 0; i < map->n; ++i) {
+		tabs[i] = isl_tab_from_basic_map(map->p[i], 0);
+		if (!tabs[i])
+			goto error;
+		if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT))
+			if (isl_tab_detect_implicit_equalities(tabs[i]) < 0)
+				goto error;
+		map->p[i] = isl_tab_make_equalities_explicit(tabs[i],
+								map->p[i]);
+		if (!map->p[i])
+			goto error;
+		if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT))
+			if (isl_tab_detect_redundant(tabs[i]) < 0)
+				goto error;
+	}
+	for (i = map->n - 1; i >= 0; --i)
+		if (tabs[i]->empty)
+			drop(map, i, tabs);
+
+	map = coalesce(map, tabs);
+
+	if (map)
+		for (i = 0; i < map->n; ++i) {
+			map->p[i] = isl_basic_map_update_from_tab(map->p[i],
+								    tabs[i]);
+			map->p[i] = isl_basic_map_gauss(map->p[i], NULL);
+			map->p[i] = isl_basic_map_finalize(map->p[i]);
+			if (!map->p[i])
+				goto error;
+			ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT);
+			ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT);
+		}
+
+	for (i = 0; i < n; ++i)
+		isl_tab_free(tabs[i]);
+
+	free(tabs);
+
+	return map;
+error:
+	if (tabs)
+		for (i = 0; i < n; ++i)
+			isl_tab_free(tabs[i]);
+	free(tabs);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* For each pair of basic sets in the set, check if the union of the two
+ * can be represented by a single basic set.
+ * If so, replace the pair by the single basic set and start over.
+ */
+struct isl_set *isl_set_coalesce(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_coalesce((struct isl_map *)set);
+}

Added: polly/trunk/lib/External/isl/isl_config.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_config.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_config.h (added)
+++ polly/trunk/lib/External/isl/isl_config.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,169 @@
+/* isl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if HeaderSearchOptions::AddPath takes 4 arguments */
+#undef ADDPATH_TAKES_4_ARGUMENTS
+
+/* Clang installation prefix */
+#undef CLANG_PREFIX
+
+/* Define if CompilerInstance::createDiagnostics takes argc and argv */
+#undef CREATEDIAGNOSTICS_TAKES_ARG
+
+/* Define if CompilerInstance::createPreprocessor takes TranslationUnitKind */
+#undef CREATEPREPROCESSOR_TAKES_TUKIND
+
+/* Define if TargetInfo::CreateTargetInfo takes pointer */
+#undef CREATETARGETINFO_TAKES_POINTER
+
+/* Define if TargetInfo::CreateTargetInfo takes shared_ptr */
+#undef CREATETARGETINFO_TAKES_SHARED_PTR
+
+/* Define if Driver constructor takes default image name */
+#undef DRIVER_CTOR_TAKES_DEFAULTIMAGENAME
+
+/* Define to Diagnostic for older versions of clang */
+#undef DiagnosticsEngine
+
+/* most gcc compilers know a function __attribute__((__warn_unused_result__))
+   */
+#undef GCC_WARN_UNUSED_RESULT
+
+/* Define if llvm/ADT/OwningPtr.h exists */
+#undef HAVE_ADT_OWNINGPTR_H
+
+/* Define if clang/Basic/DiagnosticOptions.h exists */
+#undef HAVE_BASIC_DIAGNOSTICOPTIONS_H
+
+/* Define if Driver constructor takes CXXIsProduction argument */
+#undef HAVE_CXXISPRODUCTION
+
+/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */
+#undef HAVE_DECL_FFS
+
+/* Define to 1 if you have the declaration of `mp_get_memory_functions', and
+   to 0 if you don't. */
+#undef HAVE_DECL_MP_GET_MEMORY_FUNCTIONS
+
+/* Define to 1 if you have the declaration of `__builtin_ffs', and to 0 if you
+   don't. */
+#undef HAVE_DECL___BUILTIN_FFS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if Driver constructor takes IsProduction argument */
+#undef HAVE_ISPRODUCTION
+
+/* Define to 1 if you have the `gmp' library (-lgmp). */
+#undef HAVE_LIBGMP
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if SourceManager has a setMainFileID method */
+#undef HAVE_SETMAINFILEID
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* define if your compiler has __attribute__ */
+#undef HAVE___ATTRIBUTE__
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclContinue
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclReturn
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if Driver::BuildCompilation takes ArrayRef */
+#undef USE_ARRAYREF
+
+/* use gmp to implement isl_int */
+#undef USE_GMP_FOR_MP
+
+/* use imath to implement isl_int */
+#define USE_IMATH_FOR_MP 1
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to getParamType for newer versions of clang */
+#undef getArgType
+
+/* Define to getHostTriple for older versions of clang */
+#undef getDefaultTargetTriple
+
+/* Define to getInstantiationLineNumber for older versions of clang */
+#undef getExpansionLineNumber
+
+/* Define to getNumParams for newer versions of clang */
+#undef getNumArgs
+
+/* Define to getResultType for older versions of clang */
+#undef getReturnType
+
+#include <isl_config_post.h>

Added: polly/trunk/lib/External/isl/isl_config_post.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_config_post.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_config_post.h (added)
+++ polly/trunk/lib/External/isl/isl_config_post.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,13 @@
+#ifndef HAVE___ATTRIBUTE__
+#define __attribute__(x)
+#endif
+
+#if (HAVE_DECL_FFS==0) && (HAVE_DECL___BUILTIN_FFS==1)
+#define ffs __builtin_ffs
+#endif
+
+#ifdef GCC_WARN_UNUSED_RESULT
+#define WARN_UNUSED	GCC_WARN_UNUSED_RESULT
+#else
+#define WARN_UNUSED
+#endif

Added: polly/trunk/lib/External/isl/isl_constraint.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_constraint.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_constraint.c (added)
+++ polly/trunk/lib/External/isl/isl_constraint.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1437 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_constraint_private.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl/deprecated/constraint_int.h>
+
+#undef BASE
+#define BASE constraint
+
+#include <isl_list_templ.c>
+
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c)
+{
+	return c ? isl_local_space_get_ctx(c->ls) : NULL;
+}
+
+static unsigned n(struct isl_constraint *c, enum isl_dim_type type)
+{
+	return isl_local_space_dim(c->ls, type);
+}
+
+static unsigned offset(struct isl_constraint *c, enum isl_dim_type type)
+{
+	return isl_local_space_offset(c->ls, type);
+}
+
+static unsigned basic_map_offset(__isl_keep isl_basic_map *bmap,
+							enum isl_dim_type type)
+{
+	return type == isl_dim_div ? 1 + isl_space_dim(bmap->dim, isl_dim_all)
+				   : 1 + isl_space_offset(bmap->dim, type);
+}
+
+static unsigned basic_set_offset(struct isl_basic_set *bset,
+							enum isl_dim_type type)
+{
+	isl_space *dim = bset->dim;
+	switch (type) {
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	case isl_dim_div:	return 1 + dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+__isl_give isl_constraint *isl_constraint_alloc_vec(int eq,
+	__isl_take isl_local_space *ls, __isl_take isl_vec *v)
+{
+	isl_constraint *constraint;
+
+	if (!ls || !v)
+		goto error;
+
+	constraint = isl_alloc_type(isl_vec_get_ctx(v), isl_constraint);
+	if (!constraint)
+		goto error;
+
+	constraint->ref = 1;
+	constraint->eq = eq;
+	constraint->ls = ls;
+	constraint->v = v;
+
+	return constraint;
+error:
+	isl_local_space_free(ls);
+	isl_vec_free(v);
+	return NULL;
+}
+
+__isl_give isl_constraint *isl_constraint_alloc(int eq,
+	__isl_take isl_local_space *ls)
+{
+	isl_ctx *ctx;
+	isl_vec *v;
+
+	if (!ls)
+		return NULL;
+
+	ctx = isl_local_space_get_ctx(ls);
+	v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+	v = isl_vec_clr(v);
+	return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+struct isl_constraint *isl_basic_map_constraint(struct isl_basic_map *bmap,
+	isl_int **line)
+{
+	int eq;
+	isl_ctx *ctx;
+	isl_vec *v;
+	isl_local_space *ls = NULL;
+	isl_constraint *constraint;
+
+	if (!bmap || !line)
+		goto error;
+
+	eq = line >= bmap->eq;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	ls = isl_basic_map_get_local_space(bmap);
+	v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+	if (!v)
+		goto error;
+	isl_seq_cpy(v->el, line[0], v->size);
+	constraint = isl_constraint_alloc_vec(eq, ls, v);
+
+	isl_basic_map_free(bmap);
+	return constraint;
+error:
+	isl_local_space_free(ls);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+	isl_int **line)
+{
+	return isl_basic_map_constraint((struct isl_basic_map *)bset, line);
+}
+
+__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc(1, ls);
+}
+
+__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc(0, ls);
+}
+
+struct isl_constraint *isl_constraint_dup(struct isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	return isl_constraint_alloc_vec(c->eq, isl_local_space_copy(c->ls),
+						isl_vec_copy(c->v));
+}
+
+struct isl_constraint *isl_constraint_cow(struct isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	if (c->ref == 1)
+		return c;
+	c->ref--;
+	return isl_constraint_dup(c);
+}
+
+struct isl_constraint *isl_constraint_copy(struct isl_constraint *constraint)
+{
+	if (!constraint)
+		return NULL;
+
+	constraint->ref++;
+	return constraint;
+}
+
+__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	if (--c->ref > 0)
+		return NULL;
+
+	isl_local_space_free(c->ls);
+	isl_vec_free(c->v);
+	free(c);
+
+	return NULL;
+}
+
+/* Return the number of constraints in "bmap", i.e., the
+ * number of times isl_basic_map_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+
+	return bmap->n_eq + bmap->n_ineq;
+}
+
+/* Return the number of constraints in "bset", i.e., the
+ * number of times isl_basic_set_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_n_constraint(bset);
+}
+
+int isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap,
+	int (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+	int i;
+	struct isl_constraint *c;
+
+	if (!bmap)
+		return -1;
+
+	isl_assert(bmap->ctx, ISL_F_ISSET(bmap, ISL_BASIC_MAP_FINAL),
+			return -1);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+						&bmap->eq[i]);
+		if (!c)
+			return -1;
+		if (fn(c, user) < 0)
+			return -1;
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+						&bmap->ineq[i]);
+		if (!c)
+			return -1;
+		if (fn(c, user) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+int isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset,
+	int (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+	return isl_basic_map_foreach_constraint((isl_basic_map *)bset, fn, user);
+}
+
+/* Add the constraint to the list that "user" points to, if it is not
+ * a div constraint.
+ */
+static int collect_constraint(__isl_take isl_constraint *constraint,
+	void *user)
+{
+	isl_constraint_list **list = user;
+
+	if (isl_constraint_is_div_constraint(constraint))
+		isl_constraint_free(constraint);
+	else
+		*list = isl_constraint_list_add(*list, constraint);
+
+	return 0;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bmap".  The input is required to have only known divs.
+ *
+ * There is no need to include the div constraints as they are
+ * implied by the div expressions.
+ */
+__isl_give isl_constraint_list *isl_basic_map_get_constraint_list(
+	__isl_keep isl_basic_map *bmap)
+{
+	int n;
+	int known;
+	isl_ctx *ctx;
+	isl_constraint_list *list;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		return NULL;
+	ctx = isl_basic_map_get_ctx(bmap);
+	if (!known)
+		isl_die(ctx, isl_error_invalid,
+			"input involves unknown divs", return NULL);
+
+	n = isl_basic_map_n_constraint(bmap);
+	list = isl_constraint_list_alloc(ctx, n);
+	if (isl_basic_map_foreach_constraint(bmap,
+					    &collect_constraint, &list) < 0)
+		list = isl_constraint_list_free(list);
+
+	return list;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bset".  The input is required to have only known divs.
+ */
+__isl_give isl_constraint_list *isl_basic_set_get_constraint_list(
+	__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_constraint_list(bset);
+}
+
+int isl_constraint_is_equal(struct isl_constraint *constraint1,
+	struct isl_constraint *constraint2)
+{
+	int equal;
+
+	if (!constraint1 || !constraint2)
+		return 0;
+	if (constraint1->eq != constraint2->eq)
+		return 0;
+	equal = isl_local_space_is_equal(constraint1->ls, constraint2->ls);
+	if (equal < 0 || !equal)
+		return equal;
+	return isl_vec_is_equal(constraint1->v, constraint2->v);
+}
+
+struct isl_basic_map *isl_basic_map_add_constraint(
+	struct isl_basic_map *bmap, struct isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	int equal_space;
+
+	if (!bmap || !constraint)
+		goto error;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	dim = isl_constraint_get_space(constraint);
+	equal_space = isl_space_is_equal(bmap->dim, dim);
+	isl_space_free(dim);
+	isl_assert(ctx, equal_space, goto error);
+
+	bmap = isl_basic_map_intersect(bmap,
+				isl_basic_map_from_constraint(constraint));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_constraint_free(constraint);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraint(
+	struct isl_basic_set *bset, struct isl_constraint *constraint)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_add_constraint((struct isl_basic_map *)bset,
+						constraint);
+}
+
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+	__isl_take isl_constraint *constraint)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_constraint(constraint);
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+	__isl_take isl_constraint *constraint)
+{
+	return isl_map_add_constraint(set, constraint);
+}
+
+__isl_give isl_space *isl_constraint_get_space(
+	__isl_keep isl_constraint *constraint)
+{
+	return constraint ? isl_local_space_get_space(constraint->ls) : NULL;
+}
+
+__isl_give isl_local_space *isl_constraint_get_local_space(
+	__isl_keep isl_constraint *constraint)
+{
+	return constraint ? isl_local_space_copy(constraint->ls) : NULL;
+}
+
+int isl_constraint_dim(struct isl_constraint *constraint,
+	enum isl_dim_type type)
+{
+	if (!constraint)
+		return -1;
+	return n(constraint, type);
+}
+
+int isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	isl_ctx *ctx;
+	int *active = NULL;
+	int involves = 0;
+
+	if (!constraint)
+		return -1;
+	if (n == 0)
+		return 0;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (first + n > isl_constraint_dim(constraint, type))
+		isl_die(ctx, isl_error_invalid,
+			"range out of bounds", return -1);
+
+	active = isl_local_space_get_active(constraint->ls,
+					    constraint->v->el + 1);
+	if (!active)
+		goto error;
+
+	first += isl_local_space_offset(constraint->ls, type) - 1;
+	for (i = 0; i < n; ++i)
+		if (active[first + i]) {
+			involves = 1;
+			break;
+		}
+
+	free(active);
+
+	return involves;
+error:
+	free(active);
+	return -1;
+}
+
+/* Does the given constraint represent a lower bound on the given
+ * dimension?
+ */
+int isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!constraint)
+		return -1;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", return -1);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_int_is_pos(constraint->v->el[pos]);
+}
+
+/* Does the given constraint represent an upper bound on the given
+ * dimension?
+ */
+int isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!constraint)
+		return -1;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", return -1);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_int_is_neg(constraint->v->el[pos]);
+}
+
+const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	return constraint ?
+	    isl_local_space_get_dim_name(constraint->ls, type, pos) : NULL;
+}
+
+void isl_constraint_get_constant(struct isl_constraint *constraint, isl_int *v)
+{
+	if (!constraint)
+		return;
+	isl_int_set(*v, constraint->v->el[0]);
+}
+
+/* Return the constant term of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_constant_val(
+	__isl_keep isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	return isl_val_int_from_isl_int(ctx, constraint->v->el[0]);
+}
+
+void isl_constraint_get_coefficient(struct isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int *v)
+{
+	if (!constraint)
+		return;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds", return);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set(*v, constraint->v->el[pos]);
+}
+
+/* Return the coefficient of the variable of type "type" at position "pos"
+ * of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_coefficient_val(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (pos < 0 || pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return NULL);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_val_int_from_isl_int(ctx, constraint->v->el[pos]);
+}
+
+__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint,
+	int pos)
+{
+	if (!constraint)
+		return NULL;
+
+	return isl_local_space_get_div(constraint->ls, pos);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant(
+	__isl_take isl_constraint *constraint, isl_int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	isl_int_set(constraint->v->el[0], v);
+	return constraint;
+}
+
+/* Replace the constant term of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_constant_val(
+	__isl_take isl_constraint *constraint, __isl_take isl_val *v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"expecting integer value", goto error);
+	constraint->v = isl_vec_set_element_val(constraint->v, 0, v);
+	if (!constraint->v)
+		constraint = isl_constraint_free(constraint);
+	return constraint;
+error:
+	isl_val_free(v);
+	return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant_si(
+	__isl_take isl_constraint *constraint, int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	isl_int_set_si(constraint->v->el[0], v);
+	return constraint;
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds",
+			return isl_constraint_free(constraint));
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set(constraint->v->el[pos], v);
+
+	return constraint;
+}
+
+/* Replace the coefficient of the variable of type "type" at position "pos"
+ * of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_coefficient_val(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"expecting integer value", goto error);
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", goto error);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	constraint->v = isl_vec_set_element_val(constraint->v, pos, v);
+	if (!constraint->v)
+		constraint = isl_constraint_free(constraint);
+	return constraint;
+error:
+	isl_val_free(v);
+	return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient_si(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds",
+			return isl_constraint_free(constraint));
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set_si(constraint->v->el[pos], v);
+
+	return constraint;
+}
+
+/* Drop any constraint from "bset" that is identical to "constraint".
+ * In particular, this means that the local spaces of "bset" and
+ * "constraint" need to be the same.
+ *
+ * Since the given constraint may actually be a pointer into the bset,
+ * we have to be careful not to reorder the constraints as the user
+ * may be holding on to other constraints from the same bset.
+ * This should be cleaned up when the internal representation of
+ * isl_constraint is changed to use isl_aff.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraint(
+	__isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint)
+{
+	int i;
+	unsigned n;
+	isl_int **row;
+	unsigned total;
+	isl_local_space *ls1;
+	int equal;
+
+	if (!bset || !constraint)
+		goto error;
+
+	ls1 = isl_basic_set_get_local_space(bset);
+	equal = isl_local_space_is_equal(ls1, constraint->ls);
+	isl_local_space_free(ls1);
+	if (equal < 0)
+		goto error;
+	if (!equal) {
+		isl_constraint_free(constraint);
+		return bset;
+	}
+
+	if (isl_constraint_is_equality(constraint)) {
+		n = bset->n_eq;
+		row = bset->eq;
+	} else {
+		n = bset->n_ineq;
+		row = bset->ineq;
+	}
+
+	total = isl_constraint_dim(constraint, isl_dim_all);
+	for (i = 0; i < n; ++i)
+		if (isl_seq_eq(row[i], constraint->v->el, 1 + total))
+			isl_seq_clr(row[i], 1 + total);
+			
+	isl_constraint_free(constraint);
+	return bset;
+error:
+	isl_constraint_free(constraint);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (isl_constraint_is_equality(constraint))
+		isl_die(ctx, isl_error_invalid, "cannot negate equality",
+			return isl_constraint_free(constraint));
+	constraint->v = isl_vec_neg(constraint->v);
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+	isl_int_sub_ui(constraint->v->el[0], constraint->v->el[0], 1);
+	return constraint;
+}
+
+int isl_constraint_is_equality(struct isl_constraint *constraint)
+{
+	if (!constraint)
+		return -1;
+	return constraint->eq;
+}
+
+int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint)
+{
+	int i;
+	int n_div;
+
+	if (!constraint)
+		return -1;
+	if (isl_constraint_is_equality(constraint))
+		return 0;
+	n_div = isl_constraint_dim(constraint, isl_dim_div);
+	for (i = 0; i < n_div; ++i) {
+		if (isl_local_space_is_div_constraint(constraint->ls,
+							constraint->v->el, i))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* We manually set ISL_BASIC_SET_FINAL instead of calling
+ * isl_basic_map_finalize because we want to keep the position
+ * of the divs and we therefore do not want to throw away redundant divs.
+ * This is arguably a bit fragile.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_constraint(
+	__isl_take isl_constraint *constraint)
+{
+	int k;
+	isl_local_space *ls;
+	struct isl_basic_map *bmap;
+	isl_int *c;
+	unsigned total;
+
+	if (!constraint)
+		return NULL;
+
+	ls = isl_local_space_copy(constraint->ls);
+	bmap = isl_basic_map_from_local_space(ls);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 1);
+	if (isl_constraint_is_equality(constraint)) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->eq[k];
+	}
+	else {
+		k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->ineq[k];
+	}
+	total = isl_basic_map_total_dim(bmap);
+	isl_seq_cpy(c, constraint->v->el, 1 + total);
+	isl_constraint_free(constraint);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+error:
+	isl_constraint_free(constraint);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_constraint(
+	struct isl_constraint *constraint)
+{
+	if (!constraint)
+		return NULL;
+
+	if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"not a set constraint", goto error);
+	return (isl_basic_set *)isl_basic_map_from_constraint(constraint);
+error:
+	isl_constraint_free(constraint);
+	return NULL;
+}
+
+/* Is the variable of "type" at position "pos" of "bmap" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+int isl_basic_map_has_defining_equality(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos,
+	__isl_give isl_constraint **c)
+{
+	int i;
+	unsigned offset;
+	unsigned total;
+
+	if (!bmap)
+		return -1;
+	offset = basic_map_offset(bmap, type);
+	total = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), return -1);
+	for (i = 0; i < bmap->n_eq; ++i) {
+		if (isl_int_is_zero(bmap->eq[i][offset + pos]) ||
+		    isl_seq_first_non_zero(bmap->eq[i]+offset+pos+1,
+					   1+total-offset-pos-1) != -1)
+			continue;
+		if (c)
+			*c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+								&bmap->eq[i]);
+		return 1;
+	}
+	return 0;
+}
+
+/* Is the variable of "type" at position "pos" of "bset" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+int isl_basic_set_has_defining_equality(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type, int pos,
+	__isl_give isl_constraint **c)
+{
+	return isl_basic_map_has_defining_equality((isl_basic_map *)bset,
+						    type, pos, c);
+}
+
+int isl_basic_set_has_defining_inequalities(
+	struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+	struct isl_constraint **lower,
+	struct isl_constraint **upper)
+{
+	int i, j;
+	unsigned offset;
+	unsigned total;
+	isl_int m;
+	isl_int **lower_line, **upper_line;
+
+	if (!bset)
+		return -1;
+	offset = basic_set_offset(bset, type);
+	total = isl_basic_set_total_dim(bset);
+	isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), return -1);
+	isl_int_init(m);
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_int_is_one(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_int_is_negone(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_seq_first_non_zero(bset->ineq[i]+offset+pos+1,
+						1+total-offset-pos-1) != -1)
+			continue;
+		for (j = i + 1; j < bset->n_ineq; ++j) {
+			if (!isl_seq_is_neg(bset->ineq[i]+1, bset->ineq[j]+1,
+					    total))
+				continue;
+			isl_int_add(m, bset->ineq[i][0], bset->ineq[j][0]);
+			if (isl_int_abs_ge(m, bset->ineq[i][offset+pos]))
+				continue;
+
+			if (isl_int_is_pos(bset->ineq[i][offset+pos])) {
+				lower_line = &bset->ineq[i];
+				upper_line = &bset->ineq[j];
+			} else {
+				lower_line = &bset->ineq[j];
+				upper_line = &bset->ineq[i];
+			}
+			*lower = isl_basic_set_constraint(
+					isl_basic_set_copy(bset), lower_line);
+			*upper = isl_basic_set_constraint(
+					isl_basic_set_copy(bset), upper_line);
+			isl_int_clear(m);
+			return 1;
+		}
+	}
+	*lower = NULL;
+	*upper = NULL;
+	isl_int_clear(m);
+	return 0;
+}
+
+/* Given two constraints "a" and "b" on the variable at position "abs_pos"
+ * (in "a" and "b"), add a constraint to "bset" that ensures that the
+ * bound implied by "a" is (strictly) larger than the bound implied by "b".
+ *
+ * If both constraints imply lower bounds, then this means that "a" is
+ * active in the result.
+ * If both constraints imply upper bounds, then this means that "b" is
+ * active in the result.
+ */
+static __isl_give isl_basic_set *add_larger_bound_constraint(
+	__isl_take isl_basic_set *bset, isl_int *a, isl_int *b,
+	unsigned abs_pos, int strict)
+{
+	int k;
+	isl_int t;
+	unsigned total;
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+
+	total = isl_basic_set_dim(bset, isl_dim_all);
+
+	isl_int_init(t);
+	isl_int_neg(t, b[1 + abs_pos]);
+
+	isl_seq_combine(bset->ineq[k], t, a, a[1 + abs_pos], b, 1 + abs_pos);
+	isl_seq_combine(bset->ineq[k] + 1 + abs_pos,
+		t, a + 1 + abs_pos + 1, a[1 + abs_pos], b + 1 + abs_pos + 1,
+		total - abs_pos);
+
+	if (strict)
+		isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+
+	isl_int_clear(t);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Add constraints to "context" that ensure that "u" is the smallest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_smallest_upper_bound(
+	__isl_keep isl_basic_set *context,
+	__isl_keep isl_basic_set *bset, unsigned abs_pos, int n_upper, int u)
+{
+	int j;
+
+	context = isl_basic_set_copy(context);
+	context = isl_basic_set_cow(context);
+
+	context = isl_basic_set_extend_constraints(context, 0, n_upper - 1);
+
+	for (j = 0; j < bset->n_ineq; ++j) {
+		if (j == u)
+			continue;
+		if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+			continue;
+		context = add_larger_bound_constraint(context,
+			bset->ineq[j], bset->ineq[u], abs_pos, j > u);
+	}
+
+	context = isl_basic_set_simplify(context);
+	context = isl_basic_set_finalize(context);
+
+	return context;
+}
+
+/* Add constraints to "context" that ensure that "u" is the largest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_largest_lower_bound(
+	__isl_keep isl_basic_set *context,
+	__isl_keep isl_basic_set *bset, unsigned abs_pos, int n_lower, int l)
+{
+	int j;
+
+	context = isl_basic_set_copy(context);
+	context = isl_basic_set_cow(context);
+
+	context = isl_basic_set_extend_constraints(context, 0, n_lower - 1);
+
+	for (j = 0; j < bset->n_ineq; ++j) {
+		if (j == l)
+			continue;
+		if (!isl_int_is_pos(bset->ineq[j][1 + abs_pos]))
+			continue;
+		context = add_larger_bound_constraint(context,
+			bset->ineq[l], bset->ineq[j], abs_pos, j > l);
+	}
+
+	context = isl_basic_set_simplify(context);
+	context = isl_basic_set_finalize(context);
+
+	return context;
+}
+
+static int foreach_upper_bound(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_upper,
+	int (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i;
+	isl_constraint *upper = NULL;
+	int i;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_smallest_upper_bound(context, bset,
+							abs_pos, n_upper, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+		upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->ineq[i]);
+		if (!upper || !context_i)
+			goto error;
+		if (fn(NULL, upper, context_i, user) < 0)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return -1;
+
+	return 0;
+error:
+	isl_constraint_free(upper);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context);
+	return -1;
+}
+
+static int foreach_lower_bound(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_lower,
+	int (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i;
+	isl_constraint *lower = NULL;
+	int i;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_largest_lower_bound(context, bset,
+							abs_pos, n_lower, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+		lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->ineq[i]);
+		if (!lower || !context_i)
+			goto error;
+		if (fn(lower, NULL, context_i, user) < 0)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return -1;
+
+	return 0;
+error:
+	isl_constraint_free(lower);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context);
+	return -1;
+}
+
+static int foreach_bound_pair(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_lower, int n_upper,
+	int (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i, *context_j;
+	isl_constraint *lower = NULL;
+	isl_constraint *upper = NULL;
+	int i, j;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (!isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_largest_lower_bound(context, bset,
+							abs_pos, n_lower, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+
+		for (j = 0; j < bset->n_ineq; ++j) {
+			if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+				continue;
+
+			context_j = set_smallest_upper_bound(context_i, bset,
+							    abs_pos, n_upper, j);
+			context_j = isl_basic_set_extend_constraints(context_j,
+									0, 1);
+			context_j = add_larger_bound_constraint(context_j,
+				bset->ineq[i], bset->ineq[j], abs_pos, 0);
+			context_j = isl_basic_set_simplify(context_j);
+			context_j = isl_basic_set_finalize(context_j);
+			if (isl_basic_set_is_empty(context_j)) {
+				isl_basic_set_free(context_j);
+				continue;
+			}
+			lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+							&bset->ineq[i]);
+			upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+							&bset->ineq[j]);
+			if (!lower || !upper || !context_j)
+				goto error;
+			if (fn(lower, upper, context_j, user) < 0)
+				break;
+		}
+
+		isl_basic_set_free(context_i);
+
+		if (j < bset->n_ineq)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return -1;
+
+	return 0;
+error:
+	isl_constraint_free(lower);
+	isl_constraint_free(upper);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context_j);
+	isl_basic_set_free(context);
+	return -1;
+}
+
+/* For each pair of lower and upper bounds on the variable "pos"
+ * of type "type", call "fn" with these lower and upper bounds and the
+ * set of constraints on the remaining variables where these bounds
+ * are active, i.e., (stricly) larger/smaller than the other lower/upper bounds.
+ *
+ * If the designated variable is equal to an affine combination of the
+ * other variables then fn is called with both lower and upper
+ * set to the corresponding equality.
+ *
+ * If there is no lower (or upper) bound, then NULL is passed
+ * as the corresponding bound.
+ *
+ * We first check if the variable is involved in any equality.
+ * If not, we count the number of lower and upper bounds and
+ * act accordingly.
+ */
+int isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos,
+	int (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	int i;
+	isl_constraint *lower = NULL;
+	isl_constraint *upper = NULL;
+	isl_basic_set *context = NULL;
+	unsigned abs_pos;
+	int n_lower, n_upper;
+
+	if (!bset)
+		return -1;
+	isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), return -1);
+	isl_assert(bset->ctx, type == isl_dim_param || type == isl_dim_set,
+		return -1);
+
+	abs_pos = pos;
+	if (type == isl_dim_set)
+		abs_pos += isl_basic_set_dim(bset, isl_dim_param);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][1 + abs_pos]))
+			continue;
+
+		lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->eq[i]);
+		upper = isl_constraint_copy(lower);
+		context = isl_basic_set_remove_dims(isl_basic_set_copy(bset),
+					type, pos, 1);
+		if (!lower || !upper || !context)
+			goto error;
+		return fn(lower, upper, context, user);
+	}
+
+	n_lower = 0;
+	n_upper = 0;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+			n_lower++;
+		else if (isl_int_is_neg(bset->ineq[i][1 + abs_pos]))
+			n_upper++;
+	}
+
+	context = isl_basic_set_copy(bset);
+	context = isl_basic_set_cow(context);
+	if (!context)
+		goto error;
+	for (i = context->n_ineq - 1; i >= 0; --i)
+		if (!isl_int_is_zero(context->ineq[i][1 + abs_pos]))
+			isl_basic_set_drop_inequality(context, i);
+
+	context = isl_basic_set_drop(context, type, pos, 1);
+	if (!n_lower && !n_upper)
+		return fn(NULL, NULL, context, user);
+	if (!n_lower)
+		return foreach_upper_bound(bset, type, abs_pos, context, n_upper,
+						fn, user);
+	if (!n_upper)
+		return foreach_lower_bound(bset, type, abs_pos, context, n_lower,
+						fn, user);
+	return foreach_bound_pair(bset, type, abs_pos, context, n_lower, n_upper,
+					fn, user);
+error:
+	isl_constraint_free(lower);
+	isl_constraint_free(upper);
+	isl_basic_set_free(context);
+	return -1;
+}
+
+__isl_give isl_aff *isl_constraint_get_bound(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+	isl_aff *aff;
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+	ctx = isl_constraint_get_ctx(constraint);
+	if (pos >= isl_constraint_dim(constraint, type))
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", return NULL);
+	if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+		isl_die(ctx, isl_error_invalid,
+			"not a set constraint", return NULL);
+
+	pos += offset(constraint, type);
+	if (isl_int_is_zero(constraint->v->el[pos]))
+		isl_die(ctx, isl_error_invalid,
+			"constraint does not define a bound on given dimension",
+			return NULL);
+
+	aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+	if (!aff)
+		return NULL;
+
+	if (isl_int_is_neg(constraint->v->el[pos]))
+		isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	else
+		isl_seq_neg(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	isl_int_set_si(aff->v->el[1 + pos], 0);
+	isl_int_abs(aff->v->el[0], constraint->v->el[pos]);
+
+	return aff;
+}
+
+/* For an inequality constraint
+ *
+ *	f >= 0
+ *
+ * or an equality constraint
+ *
+ *	f = 0
+ *
+ * return the affine expression f.
+ */
+__isl_give isl_aff *isl_constraint_get_aff(
+	__isl_keep isl_constraint *constraint)
+{
+	isl_aff *aff;
+
+	if (!constraint)
+		return NULL;
+
+	aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+	if (!aff)
+		return NULL;
+
+	isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	isl_int_set_si(aff->v->el[0], 1);
+
+	return aff;
+}
+
+/* Construct an inequality (eq = 0) or equality (eq = 1) constraint from "aff".
+ * In particular, construct aff >= 0 or aff = 0.
+ *
+ * The denominator of "aff" can be ignored.
+ */
+static __isl_give isl_constraint *isl_constraint_alloc_aff(int eq,
+	__isl_take isl_aff *aff)
+{
+	isl_local_space *ls;
+	isl_vec *v;
+
+	if (!aff)
+		return NULL;
+	ls = isl_aff_get_domain_local_space(aff);
+	v = isl_vec_drop_els(isl_vec_copy(aff->v), 0, 1);
+	isl_aff_free(aff);
+
+	return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+/* Construct an equality constraint equating the given affine expression
+ * to zero.
+ */
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff)
+{
+	return isl_constraint_alloc_aff(1, aff);
+}
+
+/* Construct an inequality constraint enforcing the given affine expression
+ * to be non-negative.
+ */
+__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff)
+{
+	return isl_constraint_alloc_aff(0, aff);
+}
+
+/* Compare two isl_constraints.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do consider constraints that only involve
+ * earlier dimensions as "smaller".
+ */
+int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2)
+{
+	int cmp;
+	int last1, last2;
+
+	if (c1 == c2)
+		return 0;
+	if (!c1)
+		return -1;
+	if (!c2)
+		return 1;
+	cmp = isl_local_space_cmp(c1->ls, c2->ls);
+	if (cmp != 0)
+		return cmp;
+
+	last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+	last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+	if (last1 != last2)
+		return last1 - last2;
+
+	return isl_seq_cmp(c1->v->el, c2->v->el, c1->v->size);
+}
+
+/* Compare two constraints based on their final (non-zero) coefficients.
+ * In particular, the constraint that involves later variables or
+ * that has a larger coefficient for a shared latest variable
+ * is considered "greater" than the other constraint.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * If the constraints live in different local spaces, then we cannot
+ * really compare the constraints so we compare the local spaces instead.
+ */
+int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2)
+{
+	int cmp;
+	int last1, last2;
+
+	if (c1 == c2)
+		return 0;
+	if (!c1)
+		return -1;
+	if (!c2)
+		return 1;
+	cmp = isl_local_space_cmp(c1->ls, c2->ls);
+	if (cmp != 0)
+		return cmp;
+
+	last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+	last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+	if (last1 != last2)
+		return last1 - last2;
+	if (last1 == -1)
+		return 0;
+	return isl_int_abs_cmp(c1->v->el[1 + last1], c2->v->el[1 + last2]);
+}

Added: polly/trunk/lib/External/isl/isl_constraint_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_constraint_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_constraint_private.h (added)
+++ polly/trunk/lib/External/isl/isl_constraint_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,32 @@
+#ifndef ISL_CONSTRAINT_PRIVATE_H
+#define ISL_CONSTRAINT_PRIVATE_H
+
+#include <isl/constraint.h>
+#include <isl/local_space.h>
+#include <isl/vec.h>
+
+struct isl_constraint {
+	int ref;
+
+	int eq;
+	isl_local_space	*ls;
+	isl_vec		*v;
+};
+
+#undef EL
+#define EL isl_constraint
+
+#include <isl_list_templ.h>
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+	isl_int **line);
+
+void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int *v);
+__isl_give isl_constraint *isl_constraint_set_constant(
+	__isl_take isl_constraint *constraint, isl_int v);
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int v);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_convex_hull.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_convex_hull.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_convex_hull.c (added)
+++ polly/trunk/lib/External/isl/isl_convex_hull.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,2829 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_lp_private.h>
+#include <isl/map.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_options_private.h>
+#include "isl_equalities.h"
+#include "isl_tab.h"
+#include <isl_sort.h>
+
+static struct isl_basic_set *uset_convex_hull_wrap_bounded(struct isl_set *set);
+
+/* Return 1 if constraint c is redundant with respect to the constraints
+ * in bmap.  If c is a lower [upper] bound in some variable and bmap
+ * does not have a lower [upper] bound in that variable, then c cannot
+ * be redundant and we do not need solve any lp.
+ */
+int isl_basic_map_constraint_is_redundant(struct isl_basic_map **bmap,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+	enum isl_lp_result res;
+	unsigned total;
+	int i, j;
+
+	if (!bmap)
+		return -1;
+
+	total = isl_basic_map_total_dim(*bmap);
+	for (i = 0; i < total; ++i) {
+		int sign;
+		if (isl_int_is_zero(c[1+i]))
+			continue;
+		sign = isl_int_sgn(c[1+i]);
+		for (j = 0; j < (*bmap)->n_ineq; ++j)
+			if (sign == isl_int_sgn((*bmap)->ineq[j][1+i]))
+				break;
+		if (j == (*bmap)->n_ineq)
+			break;
+	}
+	if (i < total)
+		return 0;
+
+	res = isl_basic_map_solve_lp(*bmap, 0, c, (*bmap)->ctx->one,
+					opt_n, opt_d, NULL);
+	if (res == isl_lp_unbounded)
+		return 0;
+	if (res == isl_lp_error)
+		return -1;
+	if (res == isl_lp_empty) {
+		*bmap = isl_basic_map_set_to_empty(*bmap);
+		return 0;
+	}
+	return !isl_int_is_neg(*opt_n);
+}
+
+int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+	return isl_basic_map_constraint_is_redundant(
+			(struct isl_basic_map **)bset, c, opt_n, opt_d);
+}
+
+/* Remove redundant
+ * constraints.  If the minimal value along the normal of a constraint
+ * is the same if the constraint is removed, then the constraint is redundant.
+ *
+ * Alternatively, we could have intersected the basic map with the
+ * corresponding equality and the checked if the dimension was that
+ * of a facet.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+	__isl_take isl_basic_map *bmap)
+{
+	struct isl_tab *tab;
+
+	if (!bmap)
+		return NULL;
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT))
+		return bmap;
+	if (bmap->n_ineq <= 1)
+		return bmap;
+
+	tab = isl_tab_from_basic_map(bmap, 0);
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		goto error;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	bmap = isl_basic_map_update_from_tab(bmap, tab);
+	isl_tab_free(tab);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	return bmap;
+error:
+	isl_tab_free(tab);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+	__isl_take isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_remove_redundancies((struct isl_basic_map *)bset);
+}
+
+/* Remove redundant constraints in each of the basic maps.
+ */
+__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map)
+{
+	return isl_map_inline_foreach_basic_map(map,
+					    &isl_basic_map_remove_redundancies);
+}
+
+__isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set)
+{
+	return isl_map_remove_redundancies(set);
+}
+
+/* Check if the set set is bound in the direction of the affine
+ * constraint c and if so, set the constant term such that the
+ * resulting constraint is a bounding constraint for the set.
+ */
+static int uset_is_bound(struct isl_set *set, isl_int *c, unsigned len)
+{
+	int first;
+	int j;
+	isl_int opt;
+	isl_int opt_denom;
+
+	isl_int_init(opt);
+	isl_int_init(opt_denom);
+	first = 1;
+	for (j = 0; j < set->n; ++j) {
+		enum isl_lp_result res;
+
+		if (ISL_F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY))
+			continue;
+
+		res = isl_basic_set_solve_lp(set->p[j],
+				0, c, set->ctx->one, &opt, &opt_denom, NULL);
+		if (res == isl_lp_unbounded)
+			break;
+		if (res == isl_lp_error)
+			goto error;
+		if (res == isl_lp_empty) {
+			set->p[j] = isl_basic_set_set_to_empty(set->p[j]);
+			if (!set->p[j])
+				goto error;
+			continue;
+		}
+		if (first || isl_int_is_neg(opt)) {
+			if (!isl_int_is_one(opt_denom))
+				isl_seq_scale(c, c, opt_denom, len);
+			isl_int_sub(c[0], c[0], opt);
+		}
+		first = 0;
+	}
+	isl_int_clear(opt);
+	isl_int_clear(opt_denom);
+	return j >= set->n;
+error:
+	isl_int_clear(opt);
+	isl_int_clear(opt_denom);
+	return -1;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+	__isl_take isl_basic_set *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL);
+
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_rational(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_set_rational(bset);
+}
+
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_rational(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set)
+{
+	return isl_map_set_rational(set);
+}
+
+static struct isl_basic_set *isl_basic_set_add_equality(
+	struct isl_basic_set *bset, isl_int *c)
+{
+	int i;
+	unsigned dim;
+
+	if (!bset)
+		return NULL;
+
+	if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+		return bset;
+
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_n_dim(bset);
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_extend(bset, 0, dim, 0, 1, 0);
+	i = isl_basic_set_alloc_equality(bset);
+	if (i < 0)
+		goto error;
+	isl_seq_cpy(bset->eq[i], c, 1 + dim);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static struct isl_set *isl_set_add_basic_set_equality(struct isl_set *set, isl_int *c)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_add_equality(set->p[i], c);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given a union of basic sets, construct the constraints for wrapping
+ * a facet around one of its ridges.
+ * In particular, if each of n the d-dimensional basic sets i in "set"
+ * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0
+ * and is defined by the constraints
+ *				    [ 1 ]
+ *				A_i [ x ]  >= 0
+ *
+ * then the resulting set is of dimension n*(1+d) and has as constraints
+ *
+ *				    [ a_i ]
+ *				A_i [ x_i ] >= 0
+ *
+ *				      a_i   >= 0
+ *
+ *			\sum_i x_{i,1} = 1
+ */
+static struct isl_basic_set *wrap_constraints(struct isl_set *set)
+{
+	struct isl_basic_set *lp;
+	unsigned n_eq;
+	unsigned n_ineq;
+	int i, j, k;
+	unsigned dim, lp_dim;
+
+	if (!set)
+		return NULL;
+
+	dim = 1 + isl_set_n_dim(set);
+	n_eq = 1;
+	n_ineq = set->n;
+	for (i = 0; i < set->n; ++i) {
+		n_eq += set->p[i]->n_eq;
+		n_ineq += set->p[i]->n_ineq;
+	}
+	lp = isl_basic_set_alloc(set->ctx, 0, dim * set->n, 0, n_eq, n_ineq);
+	lp = isl_basic_set_set_rational(lp);
+	if (!lp)
+		return NULL;
+	lp_dim = isl_basic_set_n_dim(lp);
+	k = isl_basic_set_alloc_equality(lp);
+	isl_int_set_si(lp->eq[k][0], -1);
+	for (i = 0; i < set->n; ++i) {
+		isl_int_set_si(lp->eq[k][1+dim*i], 0);
+		isl_int_set_si(lp->eq[k][1+dim*i+1], 1);
+		isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2);
+	}
+	for (i = 0; i < set->n; ++i) {
+		k = isl_basic_set_alloc_inequality(lp);
+		isl_seq_clr(lp->ineq[k], 1+lp_dim);
+		isl_int_set_si(lp->ineq[k][1+dim*i], 1);
+
+		for (j = 0; j < set->p[i]->n_eq; ++j) {
+			k = isl_basic_set_alloc_equality(lp);
+			isl_seq_clr(lp->eq[k], 1+dim*i);
+			isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim);
+			isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1));
+		}
+
+		for (j = 0; j < set->p[i]->n_ineq; ++j) {
+			k = isl_basic_set_alloc_inequality(lp);
+			isl_seq_clr(lp->ineq[k], 1+dim*i);
+			isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim);
+			isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1));
+		}
+	}
+	return lp;
+}
+
+/* Given a facet "facet" of the convex hull of "set" and a facet "ridge"
+ * of that facet, compute the other facet of the convex hull that contains
+ * the ridge.
+ *
+ * We first transform the set such that the facet constraint becomes
+ *
+ *			x_1 >= 0
+ *
+ * I.e., the facet lies in
+ *
+ *			x_1 = 0
+ *
+ * and on that facet, the constraint that defines the ridge is
+ *
+ *			x_2 >= 0
+ *
+ * (This transformation is not strictly needed, all that is needed is
+ * that the ridge contains the origin.)
+ *
+ * Since the ridge contains the origin, the cone of the convex hull
+ * will be of the form
+ *
+ *			x_1 >= 0
+ *			x_2 >= a x_1
+ *
+ * with this second constraint defining the new facet.
+ * The constant a is obtained by settting x_1 in the cone of the
+ * convex hull to 1 and minimizing x_2.
+ * Now, each element in the cone of the convex hull is the sum
+ * of elements in the cones of the basic sets.
+ * If a_i is the dilation factor of basic set i, then the problem
+ * we need to solve is
+ *
+ *			min \sum_i x_{i,2}
+ *			st
+ *				\sum_i x_{i,1} = 1
+ *				    a_i   >= 0
+ *				  [ a_i ]
+ *				A [ x_i ] >= 0
+ *
+ * with
+ *				    [  1  ]
+ *				A_i [ x_i ] >= 0
+ *
+ * the constraints of each (transformed) basic set.
+ * If a = n/d, then the constraint defining the new facet (in the transformed
+ * space) is
+ *
+ *			-n x_1 + d x_2 >= 0
+ *
+ * In the original space, we need to take the same combination of the
+ * corresponding constraints "facet" and "ridge".
+ *
+ * If a = -infty = "-1/0", then we just return the original facet constraint.
+ * This means that the facet is unbounded, but has a bounded intersection
+ * with the union of sets.
+ */
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+	isl_int *facet, isl_int *ridge)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_mat *T = NULL;
+	struct isl_basic_set *lp = NULL;
+	struct isl_vec *obj;
+	enum isl_lp_result res;
+	isl_int num, den;
+	unsigned dim;
+
+	if (!set)
+		return NULL;
+	ctx = set->ctx;
+	set = isl_set_copy(set);
+	set = isl_set_set_rational(set);
+
+	dim = 1 + isl_set_n_dim(set);
+	T = isl_mat_alloc(ctx, 3, dim);
+	if (!T)
+		goto error;
+	isl_int_set_si(T->row[0][0], 1);
+	isl_seq_clr(T->row[0]+1, dim - 1);
+	isl_seq_cpy(T->row[1], facet, dim);
+	isl_seq_cpy(T->row[2], ridge, dim);
+	T = isl_mat_right_inverse(T);
+	set = isl_set_preimage(set, T);
+	T = NULL;
+	if (!set)
+		goto error;
+	lp = wrap_constraints(set);
+	obj = isl_vec_alloc(ctx, 1 + dim*set->n);
+	if (!obj)
+		goto error;
+	isl_int_set_si(obj->block.data[0], 0);
+	for (i = 0; i < set->n; ++i) {
+		isl_seq_clr(obj->block.data + 1 + dim*i, 2);
+		isl_int_set_si(obj->block.data[1 + dim*i+2], 1);
+		isl_seq_clr(obj->block.data + 1 + dim*i+3, dim-3);
+	}
+	isl_int_init(num);
+	isl_int_init(den);
+	res = isl_basic_set_solve_lp(lp, 0,
+			    obj->block.data, ctx->one, &num, &den, NULL);
+	if (res == isl_lp_ok) {
+		isl_int_neg(num, num);
+		isl_seq_combine(facet, num, facet, den, ridge, dim);
+		isl_seq_normalize(ctx, facet, dim);
+	}
+	isl_int_clear(num);
+	isl_int_clear(den);
+	isl_vec_free(obj);
+	isl_basic_set_free(lp);
+	isl_set_free(set);
+	if (res == isl_lp_error)
+		return NULL;
+	isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded, 
+		   return NULL);
+	return facet;
+error:
+	isl_basic_set_free(lp);
+	isl_mat_free(T);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute the constraint of a facet of "set".
+ *
+ * We first compute the intersection with a bounding constraint
+ * that is orthogonal to one of the coordinate axes.
+ * If the affine hull of this intersection has only one equality,
+ * we have found a facet.
+ * Otherwise, we wrap the current bounding constraint around
+ * one of the equalities of the face (one that is not equal to
+ * the current bounding constraint).
+ * This process continues until we have found a facet.
+ * The dimension of the intersection increases by at least
+ * one on each iteration, so termination is guaranteed.
+ */
+static __isl_give isl_mat *initial_facet_constraint(__isl_keep isl_set *set)
+{
+	struct isl_set *slice = NULL;
+	struct isl_basic_set *face = NULL;
+	int i;
+	unsigned dim = isl_set_n_dim(set);
+	int is_bound;
+	isl_mat *bounds = NULL;
+
+	isl_assert(set->ctx, set->n > 0, goto error);
+	bounds = isl_mat_alloc(set->ctx, 1, 1 + dim);
+	if (!bounds)
+		return NULL;
+
+	isl_seq_clr(bounds->row[0], dim);
+	isl_int_set_si(bounds->row[0][1 + dim - 1], 1);
+	is_bound = uset_is_bound(set, bounds->row[0], 1 + dim);
+	if (is_bound < 0)
+		goto error;
+	isl_assert(set->ctx, is_bound, goto error);
+	isl_seq_normalize(set->ctx, bounds->row[0], 1 + dim);
+	bounds->n_row = 1;
+
+	for (;;) {
+		slice = isl_set_copy(set);
+		slice = isl_set_add_basic_set_equality(slice, bounds->row[0]);
+		face = isl_set_affine_hull(slice);
+		if (!face)
+			goto error;
+		if (face->n_eq == 1) {
+			isl_basic_set_free(face);
+			break;
+		}
+		for (i = 0; i < face->n_eq; ++i)
+			if (!isl_seq_eq(bounds->row[0], face->eq[i], 1 + dim) &&
+			    !isl_seq_is_neg(bounds->row[0],
+						face->eq[i], 1 + dim))
+				break;
+		isl_assert(set->ctx, i < face->n_eq, goto error);
+		if (!isl_set_wrap_facet(set, bounds->row[0], face->eq[i]))
+			goto error;
+		isl_seq_normalize(set->ctx, bounds->row[0], bounds->n_col);
+		isl_basic_set_free(face);
+	}
+
+	return bounds;
+error:
+	isl_basic_set_free(face);
+	isl_mat_free(bounds);
+	return NULL;
+}
+
+/* Given the bounding constraint "c" of a facet of the convex hull of "set",
+ * compute a hyperplane description of the facet, i.e., compute the facets
+ * of the facet.
+ *
+ * We compute an affine transformation that transforms the constraint
+ *
+ *			  [ 1 ]
+ *			c [ x ] = 0
+ *
+ * to the constraint
+ *
+ *			   z_1  = 0
+ *
+ * by computing the right inverse U of a matrix that starts with the rows
+ *
+ *			[ 1 0 ]
+ *			[  c  ]
+ *
+ * Then
+ *			[ 1 ]     [ 1 ]
+ *			[ x ] = U [ z ]
+ * and
+ *			[ 1 ]     [ 1 ]
+ *			[ z ] = Q [ x ]
+ *
+ * with Q = U^{-1}
+ * Since z_1 is zero, we can drop this variable as well as the corresponding
+ * column of U to obtain
+ *
+ *			[ 1 ]      [ 1  ]
+ *			[ x ] = U' [ z' ]
+ * and
+ *			[ 1  ]      [ 1 ]
+ *			[ z' ] = Q' [ x ]
+ *
+ * with Q' equal to Q, but without the corresponding row.
+ * After computing the facets of the facet in the z' space,
+ * we convert them back to the x space through Q.
+ */
+static struct isl_basic_set *compute_facet(struct isl_set *set, isl_int *c)
+{
+	struct isl_mat *m, *U, *Q;
+	struct isl_basic_set *facet = NULL;
+	struct isl_ctx *ctx;
+	unsigned dim;
+
+	ctx = set->ctx;
+	set = isl_set_copy(set);
+	dim = isl_set_n_dim(set);
+	m = isl_mat_alloc(set->ctx, 2, 1 + dim);
+	if (!m)
+		goto error;
+	isl_int_set_si(m->row[0][0], 1);
+	isl_seq_clr(m->row[0]+1, dim);
+	isl_seq_cpy(m->row[1], c, 1+dim);
+	U = isl_mat_right_inverse(m);
+	Q = isl_mat_right_inverse(isl_mat_copy(U));
+	U = isl_mat_drop_cols(U, 1, 1);
+	Q = isl_mat_drop_rows(Q, 1, 1);
+	set = isl_set_preimage(set, U);
+	facet = uset_convex_hull_wrap_bounded(set);
+	facet = isl_basic_set_preimage(facet, Q);
+	if (facet)
+		isl_assert(ctx, facet->n_eq == 0, goto error);
+	return facet;
+error:
+	isl_basic_set_free(facet);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given an initial facet constraint, compute the remaining facets.
+ * We do this by running through all facets found so far and computing
+ * the adjacent facets through wrapping, adding those facets that we
+ * hadn't already found before.
+ *
+ * For each facet we have found so far, we first compute its facets
+ * in the resulting convex hull.  That is, we compute the ridges
+ * of the resulting convex hull contained in the facet.
+ * We also compute the corresponding facet in the current approximation
+ * of the convex hull.  There is no need to wrap around the ridges
+ * in this facet since that would result in a facet that is already
+ * present in the current approximation.
+ *
+ * This function can still be significantly optimized by checking which of
+ * the facets of the basic sets are also facets of the convex hull and
+ * using all the facets so far to help in constructing the facets of the
+ * facets
+ * and/or
+ * using the technique in section "3.1 Ridge Generation" of
+ * "Extended Convex Hull" by Fukuda et al.
+ */
+static struct isl_basic_set *extend(struct isl_basic_set *hull,
+	struct isl_set *set)
+{
+	int i, j, f;
+	int k;
+	struct isl_basic_set *facet = NULL;
+	struct isl_basic_set *hull_facet = NULL;
+	unsigned dim;
+
+	if (!hull)
+		return NULL;
+
+	isl_assert(set->ctx, set->n > 0, goto error);
+
+	dim = isl_set_n_dim(set);
+
+	for (i = 0; i < hull->n_ineq; ++i) {
+		facet = compute_facet(set, hull->ineq[i]);
+		facet = isl_basic_set_add_equality(facet, hull->ineq[i]);
+		facet = isl_basic_set_gauss(facet, NULL);
+		facet = isl_basic_set_normalize_constraints(facet);
+		hull_facet = isl_basic_set_copy(hull);
+		hull_facet = isl_basic_set_add_equality(hull_facet, hull->ineq[i]);
+		hull_facet = isl_basic_set_gauss(hull_facet, NULL);
+		hull_facet = isl_basic_set_normalize_constraints(hull_facet);
+		if (!facet || !hull_facet)
+			goto error;
+		hull = isl_basic_set_cow(hull);
+		hull = isl_basic_set_extend_space(hull,
+			isl_space_copy(hull->dim), 0, 0, facet->n_ineq);
+		if (!hull)
+			goto error;
+		for (j = 0; j < facet->n_ineq; ++j) {
+			for (f = 0; f < hull_facet->n_ineq; ++f)
+				if (isl_seq_eq(facet->ineq[j],
+						hull_facet->ineq[f], 1 + dim))
+					break;
+			if (f < hull_facet->n_ineq)
+				continue;
+			k = isl_basic_set_alloc_inequality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim);
+			if (!isl_set_wrap_facet(set, hull->ineq[k], facet->ineq[j]))
+				goto error;
+		}
+		isl_basic_set_free(hull_facet);
+		isl_basic_set_free(facet);
+	}
+	hull = isl_basic_set_simplify(hull);
+	hull = isl_basic_set_finalize(hull);
+	return hull;
+error:
+	isl_basic_set_free(hull_facet);
+	isl_basic_set_free(facet);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Special case for computing the convex hull of a one dimensional set.
+ * We simply collect the lower and upper bounds of each basic set
+ * and the biggest of those.
+ */
+static struct isl_basic_set *convex_hull_1d(struct isl_set *set)
+{
+	struct isl_mat *c = NULL;
+	isl_int *lower = NULL;
+	isl_int *upper = NULL;
+	int i, j, k;
+	isl_int a, b;
+	struct isl_basic_set *hull;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_simplify(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	set = isl_set_remove_empty_parts(set);
+	if (!set)
+		goto error;
+	isl_assert(set->ctx, set->n > 0, goto error);
+	c = isl_mat_alloc(set->ctx, 2, 2);
+	if (!c)
+		goto error;
+
+	if (set->p[0]->n_eq > 0) {
+		isl_assert(set->ctx, set->p[0]->n_eq == 1, goto error);
+		lower = c->row[0];
+		upper = c->row[1];
+		if (isl_int_is_pos(set->p[0]->eq[0][1])) {
+			isl_seq_cpy(lower, set->p[0]->eq[0], 2);
+			isl_seq_neg(upper, set->p[0]->eq[0], 2);
+		} else {
+			isl_seq_neg(lower, set->p[0]->eq[0], 2);
+			isl_seq_cpy(upper, set->p[0]->eq[0], 2);
+		}
+	} else {
+		for (j = 0; j < set->p[0]->n_ineq; ++j) {
+			if (isl_int_is_pos(set->p[0]->ineq[j][1])) {
+				lower = c->row[0];
+				isl_seq_cpy(lower, set->p[0]->ineq[j], 2);
+			} else {
+				upper = c->row[1];
+				isl_seq_cpy(upper, set->p[0]->ineq[j], 2);
+			}
+		}
+	}
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (i = 0; i < set->n; ++i) {
+		struct isl_basic_set *bset = set->p[i];
+		int has_lower = 0;
+		int has_upper = 0;
+
+		for (j = 0; j < bset->n_eq; ++j) {
+			has_lower = 1;
+			has_upper = 1;
+			if (lower) {
+				isl_int_mul(a, lower[0], bset->eq[j][1]);
+				isl_int_mul(b, lower[1], bset->eq[j][0]);
+				if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+					isl_seq_cpy(lower, bset->eq[j], 2);
+				if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+					isl_seq_neg(lower, bset->eq[j], 2);
+			}
+			if (upper) {
+				isl_int_mul(a, upper[0], bset->eq[j][1]);
+				isl_int_mul(b, upper[1], bset->eq[j][0]);
+				if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+					isl_seq_neg(upper, bset->eq[j], 2);
+				if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+					isl_seq_cpy(upper, bset->eq[j], 2);
+			}
+		}
+		for (j = 0; j < bset->n_ineq; ++j) {
+			if (isl_int_is_pos(bset->ineq[j][1]))
+				has_lower = 1;
+			if (isl_int_is_neg(bset->ineq[j][1]))
+				has_upper = 1;
+			if (lower && isl_int_is_pos(bset->ineq[j][1])) {
+				isl_int_mul(a, lower[0], bset->ineq[j][1]);
+				isl_int_mul(b, lower[1], bset->ineq[j][0]);
+				if (isl_int_lt(a, b))
+					isl_seq_cpy(lower, bset->ineq[j], 2);
+			}
+			if (upper && isl_int_is_neg(bset->ineq[j][1])) {
+				isl_int_mul(a, upper[0], bset->ineq[j][1]);
+				isl_int_mul(b, upper[1], bset->ineq[j][0]);
+				if (isl_int_gt(a, b))
+					isl_seq_cpy(upper, bset->ineq[j], 2);
+			}
+		}
+		if (!has_lower)
+			lower = NULL;
+		if (!has_upper)
+			upper = NULL;
+	}
+	isl_int_clear(a);
+	isl_int_clear(b);
+
+	hull = isl_basic_set_alloc(set->ctx, 0, 1, 0, 0, 2);
+	hull = isl_basic_set_set_rational(hull);
+	if (!hull)
+		goto error;
+	if (lower) {
+		k = isl_basic_set_alloc_inequality(hull);
+		isl_seq_cpy(hull->ineq[k], lower, 2);
+	}
+	if (upper) {
+		k = isl_basic_set_alloc_inequality(hull);
+		isl_seq_cpy(hull->ineq[k], upper, 2);
+	}
+	hull = isl_basic_set_finalize(hull);
+	isl_set_free(set);
+	isl_mat_free(c);
+	return hull;
+error:
+	isl_set_free(set);
+	isl_mat_free(c);
+	return NULL;
+}
+
+static struct isl_basic_set *convex_hull_0d(struct isl_set *set)
+{
+	struct isl_basic_set *convex_hull;
+
+	if (!set)
+		return NULL;
+
+	if (isl_set_is_empty(set))
+		convex_hull = isl_basic_set_empty(isl_space_copy(set->dim));
+	else
+		convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+	isl_set_free(set);
+	return convex_hull;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions using Fourier-Motzkin elimination.
+ * The convex hull is the set of all points that can be written as
+ * the sum of points from both basic sets (in homogeneous coordinates).
+ * We set up the constraints in a space with dimensions for each of
+ * the three sets and then project out the dimensions corresponding
+ * to the two original basic sets, retaining only those corresponding
+ * to the convex hull.
+ */
+static struct isl_basic_set *convex_hull_pair_elim(struct isl_basic_set *bset1,
+	struct isl_basic_set *bset2)
+{
+	int i, j, k;
+	struct isl_basic_set *bset[2];
+	struct isl_basic_set *hull = NULL;
+	unsigned dim;
+
+	if (!bset1 || !bset2)
+		goto error;
+
+	dim = isl_basic_set_n_dim(bset1);
+	hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0,
+				1 + dim + bset1->n_eq + bset2->n_eq,
+				2 + bset1->n_ineq + bset2->n_ineq);
+	bset[0] = bset1;
+	bset[1] = bset2;
+	for (i = 0; i < 2; ++i) {
+		for (j = 0; j < bset[i]->n_eq; ++j) {
+			k = isl_basic_set_alloc_equality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(hull->eq[k], (i+1) * (1+dim));
+			isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+			isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j],
+					1+dim);
+		}
+		for (j = 0; j < bset[i]->n_ineq; ++j) {
+			k = isl_basic_set_alloc_inequality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(hull->ineq[k], (i+1) * (1+dim));
+			isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+			isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim),
+					bset[i]->ineq[j], 1+dim);
+		}
+		k = isl_basic_set_alloc_inequality(hull);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(hull->ineq[k], 1+2+3*dim);
+		isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1);
+	}
+	for (j = 0; j < 1+dim; ++j) {
+		k = isl_basic_set_alloc_equality(hull);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(hull->eq[k], 1+2+3*dim);
+		isl_int_set_si(hull->eq[k][j], -1);
+		isl_int_set_si(hull->eq[k][1+dim+j], 1);
+		isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1);
+	}
+	hull = isl_basic_set_set_rational(hull);
+	hull = isl_basic_set_remove_dims(hull, isl_dim_set, dim, 2*(1+dim));
+	hull = isl_basic_set_remove_redundancies(hull);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return hull;
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+int isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	int bounded;
+
+	if (!bset)
+		return -1;
+	if (isl_basic_set_plain_is_empty(bset))
+		return 1;
+
+	tab = isl_tab_from_recession_cone(bset, 1);
+	bounded = isl_tab_cone_is_bounded(tab);
+	isl_tab_free(tab);
+	return bounded;
+}
+
+/* Is the image bounded for each value of the parameters and
+ * the domain variables?
+ */
+int isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap)
+{
+	unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	int bounded;
+
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_move_dims(bmap, isl_dim_param, nparam,
+					isl_dim_in, 0, n_in);
+	bounded = isl_basic_set_is_bounded((isl_basic_set *)bmap);
+	isl_basic_map_free(bmap);
+
+	return bounded;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+int isl_set_is_bounded(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i) {
+		int bounded = isl_basic_set_is_bounded(set->p[i]);
+		if (!bounded || bounded < 0)
+			return bounded;
+	}
+	return 1;
+}
+
+/* Compute the lineality space of the convex hull of bset1 and bset2.
+ *
+ * We first compute the intersection of the recession cone of bset1
+ * with the negative of the recession cone of bset2 and then compute
+ * the linear hull of the resulting cone.
+ */
+static struct isl_basic_set *induced_lineality_space(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	int i, k;
+	struct isl_basic_set *lin = NULL;
+	unsigned dim;
+
+	if (!bset1 || !bset2)
+		goto error;
+
+	dim = isl_basic_set_total_dim(bset1);
+	lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset1), 0,
+					bset1->n_eq + bset2->n_eq,
+					bset1->n_ineq + bset2->n_ineq);
+	lin = isl_basic_set_set_rational(lin);
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset1->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset1->eq[i] + 1, dim);
+	}
+	for (i = 0; i < bset1->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->ineq[k][0], 0);
+		isl_seq_cpy(lin->ineq[k] + 1, bset1->ineq[i] + 1, dim);
+	}
+	for (i = 0; i < bset2->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_neg(lin->eq[k] + 1, bset2->eq[i] + 1, dim);
+	}
+	for (i = 0; i < bset2->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->ineq[k][0], 0);
+		isl_seq_neg(lin->ineq[k] + 1, bset2->ineq[i] + 1, dim);
+	}
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return isl_basic_set_affine_hull(lin);
+error:
+	isl_basic_set_free(lin);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+static struct isl_basic_set *uset_convex_hull(struct isl_set *set);
+
+/* Given a set and a linear space "lin" of dimension n > 0,
+ * project the linear space from the set, compute the convex hull
+ * and then map the set back to the original space.
+ *
+ * Let
+ *
+ *	M x = 0
+ *
+ * describe the linear space.  We first compute the Hermite normal
+ * form H = M U of M = H Q, to obtain
+ *
+ *	H Q x = 0
+ *
+ * The last n rows of H will be zero, so the last n variables of x' = Q x
+ * are the one we want to project out.  We do this by transforming each
+ * basic set A x >= b to A U x' >= b and then removing the last n dimensions.
+ * After computing the convex hull in x'_1, i.e., A' x'_1 >= b',
+ * we transform the hull back to the original space as A' Q_1 x >= b',
+ * with Q_1 all but the last n rows of Q.
+ */
+static struct isl_basic_set *modulo_lineality(struct isl_set *set,
+	struct isl_basic_set *lin)
+{
+	unsigned total = isl_basic_set_total_dim(lin);
+	unsigned lin_dim;
+	struct isl_basic_set *hull;
+	struct isl_mat *M, *U, *Q;
+
+	if (!set || !lin)
+		goto error;
+	lin_dim = total - lin->n_eq;
+	M = isl_mat_sub_alloc6(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
+	M = isl_mat_left_hermite(M, 0, &U, &Q);
+	if (!M)
+		goto error;
+	isl_mat_free(M);
+	isl_basic_set_free(lin);
+
+	Q = isl_mat_drop_rows(Q, Q->n_row - lin_dim, lin_dim);
+
+	U = isl_mat_lin_to_aff(U);
+	Q = isl_mat_lin_to_aff(Q);
+
+	set = isl_set_preimage(set, U);
+	set = isl_set_remove_dims(set, isl_dim_set, total - lin_dim, lin_dim);
+	hull = uset_convex_hull(set);
+	hull = isl_basic_set_preimage(hull, Q);
+
+	return hull;
+error:
+	isl_basic_set_free(lin);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given two polyhedra with as constraints h_{ij} x >= 0 in homegeneous space,
+ * set up an LP for solving
+ *
+ *	\sum_j \alpha_{1j} h_{1j} = \sum_j \alpha_{2j} h_{2j}
+ *
+ * \alpha{i0} corresponds to the (implicit) positivity constraint 1 >= 0
+ * The next \alpha{ij} correspond to the equalities and come in pairs.
+ * The final \alpha{ij} correspond to the inequalities.
+ */
+static struct isl_basic_set *valid_direction_lp(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	isl_space *dim;
+	struct isl_basic_set *lp;
+	unsigned d;
+	int n;
+	int i, j, k;
+
+	if (!bset1 || !bset2)
+		goto error;
+	d = 1 + isl_basic_set_total_dim(bset1);
+	n = 2 +
+	    2 * bset1->n_eq + bset1->n_ineq + 2 * bset2->n_eq + bset2->n_ineq;
+	dim = isl_space_set_alloc(bset1->ctx, 0, n);
+	lp = isl_basic_set_alloc_space(dim, 0, d, n);
+	if (!lp)
+		goto error;
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_set_alloc_inequality(lp);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(lp->ineq[k] + 1, n);
+		isl_int_set_si(lp->ineq[k][0], -1);
+		isl_int_set_si(lp->ineq[k][1 + i], 1);
+	}
+	for (i = 0; i < d; ++i) {
+		k = isl_basic_set_alloc_equality(lp);
+		if (k < 0)
+			goto error;
+		n = 0;
+		isl_int_set_si(lp->eq[k][n], 0); n++;
+		/* positivity constraint 1 >= 0 */
+		isl_int_set_si(lp->eq[k][n], i == 0); n++;
+		for (j = 0; j < bset1->n_eq; ++j) {
+			isl_int_set(lp->eq[k][n], bset1->eq[j][i]); n++;
+			isl_int_neg(lp->eq[k][n], bset1->eq[j][i]); n++;
+		}
+		for (j = 0; j < bset1->n_ineq; ++j) {
+			isl_int_set(lp->eq[k][n], bset1->ineq[j][i]); n++;
+		}
+		/* positivity constraint 1 >= 0 */
+		isl_int_set_si(lp->eq[k][n], -(i == 0)); n++;
+		for (j = 0; j < bset2->n_eq; ++j) {
+			isl_int_neg(lp->eq[k][n], bset2->eq[j][i]); n++;
+			isl_int_set(lp->eq[k][n], bset2->eq[j][i]); n++;
+		}
+		for (j = 0; j < bset2->n_ineq; ++j) {
+			isl_int_neg(lp->eq[k][n], bset2->ineq[j][i]); n++;
+		}
+	}
+	lp = isl_basic_set_gauss(lp, NULL);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return lp;
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Compute a vector s in the homogeneous space such that <s, r> > 0
+ * for all rays in the homogeneous space of the two cones that correspond
+ * to the input polyhedra bset1 and bset2.
+ *
+ * We compute s as a vector that satisfies
+ *
+ *	s = \sum_j \alpha_{ij} h_{ij}	for i = 1,2			(*)
+ *
+ * with h_{ij} the normals of the facets of polyhedron i
+ * (including the "positivity constraint" 1 >= 0) and \alpha_{ij}
+ * strictly positive numbers.  For simplicity we impose \alpha_{ij} >= 1.
+ * We first set up an LP with as variables the \alpha{ij}.
+ * In this formulation, for each polyhedron i,
+ * the first constraint is the positivity constraint, followed by pairs
+ * of variables for the equalities, followed by variables for the inequalities.
+ * We then simply pick a feasible solution and compute s using (*).
+ *
+ * Note that we simply pick any valid direction and make no attempt
+ * to pick a "good" or even the "best" valid direction.
+ */
+static struct isl_vec *valid_direction(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	struct isl_basic_set *lp;
+	struct isl_tab *tab;
+	struct isl_vec *sample = NULL;
+	struct isl_vec *dir;
+	unsigned d;
+	int i;
+	int n;
+
+	if (!bset1 || !bset2)
+		goto error;
+	lp = valid_direction_lp(isl_basic_set_copy(bset1),
+				isl_basic_set_copy(bset2));
+	tab = isl_tab_from_basic_set(lp, 0);
+	sample = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+	isl_basic_set_free(lp);
+	if (!sample)
+		goto error;
+	d = isl_basic_set_total_dim(bset1);
+	dir = isl_vec_alloc(bset1->ctx, 1 + d);
+	if (!dir)
+		goto error;
+	isl_seq_clr(dir->block.data + 1, dir->size - 1);
+	n = 1;
+	/* positivity constraint 1 >= 0 */
+	isl_int_set(dir->block.data[0], sample->block.data[n]); n++;
+	for (i = 0; i < bset1->n_eq; ++i) {
+		isl_int_sub(sample->block.data[n],
+			    sample->block.data[n], sample->block.data[n+1]);
+		isl_seq_combine(dir->block.data,
+				bset1->ctx->one, dir->block.data,
+				sample->block.data[n], bset1->eq[i], 1 + d);
+
+		n += 2;
+	}
+	for (i = 0; i < bset1->n_ineq; ++i)
+		isl_seq_combine(dir->block.data,
+				bset1->ctx->one, dir->block.data,
+				sample->block.data[n++], bset1->ineq[i], 1 + d);
+	isl_vec_free(sample);
+	isl_seq_normalize(bset1->ctx, dir->el, dir->size);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return dir;
+error:
+	isl_vec_free(sample);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Given a polyhedron b_i + A_i x >= 0 and a map T = S^{-1},
+ * compute b_i' + A_i' x' >= 0, with
+ *
+ *	[ b_i A_i ]        [ y' ]		              [ y' ]
+ *	[  1   0  ] S^{-1} [ x' ] >= 0	or	[ b_i' A_i' ] [ x' ] >= 0
+ *
+ * In particular, add the "positivity constraint" and then perform
+ * the mapping.
+ */
+static struct isl_basic_set *homogeneous_map(struct isl_basic_set *bset,
+	struct isl_mat *T)
+{
+	int k;
+
+	if (!bset)
+		goto error;
+	bset = isl_basic_set_extend_constraints(bset, 0, 1);
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bset->ineq[k] + 1, isl_basic_set_total_dim(bset));
+	isl_int_set_si(bset->ineq[k][0], 1);
+	bset = isl_basic_set_preimage(bset, T);
+	return bset;
+error:
+	isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions, where the convex hull is known to be pointed,
+ * but the basic sets may be unbounded.
+ *
+ * We turn this problem into the computation of a convex hull of a pair
+ * _bounded_ polyhedra by "changing the direction of the homogeneous
+ * dimension".  This idea is due to Matthias Koeppe.
+ *
+ * Consider the cones in homogeneous space that correspond to the
+ * input polyhedra.  The rays of these cones are also rays of the
+ * polyhedra if the coordinate that corresponds to the homogeneous
+ * dimension is zero.  That is, if the inner product of the rays
+ * with the homogeneous direction is zero.
+ * The cones in the homogeneous space can also be considered to
+ * correspond to other pairs of polyhedra by chosing a different
+ * homogeneous direction.  To ensure that both of these polyhedra
+ * are bounded, we need to make sure that all rays of the cones
+ * correspond to vertices and not to rays.
+ * Let s be a direction such that <s, r> > 0 for all rays r of both cones.
+ * Then using s as a homogeneous direction, we obtain a pair of polytopes.
+ * The vector s is computed in valid_direction.
+ *
+ * Note that we need to consider _all_ rays of the cones and not just
+ * the rays that correspond to rays in the polyhedra.  If we were to
+ * only consider those rays and turn them into vertices, then we
+ * may inadvertently turn some vertices into rays.
+ *
+ * The standard homogeneous direction is the unit vector in the 0th coordinate.
+ * We therefore transform the two polyhedra such that the selected
+ * direction is mapped onto this standard direction and then proceed
+ * with the normal computation.
+ * Let S be a non-singular square matrix with s as its first row,
+ * then we want to map the polyhedra to the space
+ *
+ *	[ y' ]     [ y ]		[ y ]          [ y' ]
+ *	[ x' ] = S [ x ]	i.e.,	[ x ] = S^{-1} [ x' ]
+ *
+ * We take S to be the unimodular completion of s to limit the growth
+ * of the coefficients in the following computations.
+ *
+ * Let b_i + A_i x >= 0 be the constraints of polyhedron i.
+ * We first move to the homogeneous dimension
+ *
+ *	b_i y + A_i x >= 0		[ b_i A_i ] [ y ]    [ 0 ]
+ *	    y         >= 0	or	[  1   0  ] [ x ] >= [ 0 ]
+ *
+ * Then we change directoin
+ *
+ *	[ b_i A_i ]        [ y' ]		              [ y' ]
+ *	[  1   0  ] S^{-1} [ x' ] >= 0	or	[ b_i' A_i' ] [ x' ] >= 0
+ *
+ * Then we compute the convex hull of the polytopes b_i' + A_i' x' >= 0
+ * resulting in b' + A' x' >= 0, which we then convert back
+ *
+ *	            [ y ]		        [ y ]
+ *	[ b' A' ] S [ x ] >= 0	or	[ b A ] [ x ] >= 0
+ *
+ * The polyhedron b + A x >= 0 is then the convex hull of the input polyhedra.
+ */
+static struct isl_basic_set *convex_hull_pair_pointed(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	struct isl_ctx *ctx = NULL;
+	struct isl_vec *dir = NULL;
+	struct isl_mat *T = NULL;
+	struct isl_mat *T2 = NULL;
+	struct isl_basic_set *hull;
+	struct isl_set *set;
+
+	if (!bset1 || !bset2)
+		goto error;
+	ctx = bset1->ctx;
+	dir = valid_direction(isl_basic_set_copy(bset1),
+				isl_basic_set_copy(bset2));
+	if (!dir)
+		goto error;
+	T = isl_mat_alloc(bset1->ctx, dir->size, dir->size);
+	if (!T)
+		goto error;
+	isl_seq_cpy(T->row[0], dir->block.data, dir->size);
+	T = isl_mat_unimodular_complete(T, 1);
+	T2 = isl_mat_right_inverse(isl_mat_copy(T));
+
+	bset1 = homogeneous_map(bset1, isl_mat_copy(T2));
+	bset2 = homogeneous_map(bset2, T2);
+	set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+	set = isl_set_add_basic_set(set, bset1);
+	set = isl_set_add_basic_set(set, bset2);
+	hull = uset_convex_hull(set);
+	hull = isl_basic_set_preimage(hull, T);
+	 
+	isl_vec_free(dir);
+
+	return hull;
+error:
+	isl_vec_free(dir);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set);
+static struct isl_basic_set *modulo_affine_hull(
+	struct isl_set *set, struct isl_basic_set *affine_hull);
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions.
+ *
+ * This function is called from uset_convex_hull_unbounded, which
+ * means that the complete convex hull is unbounded.  Some pairs
+ * of basic sets may still be bounded, though.
+ * They may even lie inside a lower dimensional space, in which
+ * case they need to be handled inside their affine hull since
+ * the main algorithm assumes that the result is full-dimensional.
+ *
+ * If the convex hull of the two basic sets would have a non-trivial
+ * lineality space, we first project out this lineality space.
+ */
+static struct isl_basic_set *convex_hull_pair(struct isl_basic_set *bset1,
+	struct isl_basic_set *bset2)
+{
+	isl_basic_set *lin, *aff;
+	int bounded1, bounded2;
+
+	if (bset1->ctx->opt->convex == ISL_CONVEX_HULL_FM)
+		return convex_hull_pair_elim(bset1, bset2);
+
+	aff = isl_set_affine_hull(isl_basic_set_union(isl_basic_set_copy(bset1),
+						    isl_basic_set_copy(bset2)));
+	if (!aff)
+		goto error;
+	if (aff->n_eq != 0) 
+		return modulo_affine_hull(isl_basic_set_union(bset1, bset2), aff);
+	isl_basic_set_free(aff);
+
+	bounded1 = isl_basic_set_is_bounded(bset1);
+	bounded2 = isl_basic_set_is_bounded(bset2);
+
+	if (bounded1 < 0 || bounded2 < 0)
+		goto error;
+
+	if (bounded1 && bounded2)
+		return uset_convex_hull_wrap(isl_basic_set_union(bset1, bset2));
+
+	if (bounded1 || bounded2)
+		return convex_hull_pair_pointed(bset1, bset2);
+
+	lin = induced_lineality_space(isl_basic_set_copy(bset1),
+				      isl_basic_set_copy(bset2));
+	if (!lin)
+		goto error;
+	if (isl_basic_set_is_universe(lin)) {
+		isl_basic_set_free(bset1);
+		isl_basic_set_free(bset2);
+		return lin;
+	}
+	if (lin->n_eq < isl_basic_set_total_dim(lin)) {
+		struct isl_set *set;
+		set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+		set = isl_set_add_basic_set(set, bset1);
+		set = isl_set_add_basic_set(set, bset2);
+		return modulo_lineality(set, lin);
+	}
+	isl_basic_set_free(lin);
+
+	return convex_hull_pair_pointed(bset1, bset2);
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Compute the lineality space of a basic set.
+ * We currently do not allow the basic set to have any divs.
+ * We basically just drop the constants and turn every inequality
+ * into an equality.
+ */
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset)
+{
+	int i, k;
+	struct isl_basic_set *lin = NULL;
+	unsigned dim;
+
+	if (!bset)
+		goto error;
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_total_dim(bset);
+
+	lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), 0, dim, 0);
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset->eq[i] + 1, dim);
+	}
+	lin = isl_basic_set_gauss(lin, NULL);
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset->n_ineq && lin->n_eq < dim; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset->ineq[i] + 1, dim);
+		lin = isl_basic_set_gauss(lin, NULL);
+		if (!lin)
+			goto error;
+	}
+	isl_basic_set_free(bset);
+	return lin;
+error:
+	isl_basic_set_free(lin);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Compute the (linear) hull of the lineality spaces of the basic sets in the
+ * "underlying" set "set".
+ */
+static struct isl_basic_set *uset_combined_lineality_space(struct isl_set *set)
+{
+	int i;
+	struct isl_set *lin = NULL;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *dim = isl_set_get_space(set);
+		isl_set_free(set);
+		return isl_basic_set_empty(dim);
+	}
+
+	lin = isl_set_alloc_space(isl_set_get_space(set), set->n, 0);
+	for (i = 0; i < set->n; ++i)
+		lin = isl_set_add_basic_set(lin,
+		    isl_basic_set_lineality_space(isl_basic_set_copy(set->p[i])));
+	isl_set_free(set);
+	return isl_set_affine_hull(lin);
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions.
+ * In each step, we combined two basic sets until only one
+ * basic set is left.
+ * The input basic sets are assumed not to have a non-trivial
+ * lineality space.  If any of the intermediate results has
+ * a non-trivial lineality space, it is projected out.
+ */
+static struct isl_basic_set *uset_convex_hull_unbounded(struct isl_set *set)
+{
+	struct isl_basic_set *convex_hull = NULL;
+
+	convex_hull = isl_set_copy_basic_set(set);
+	set = isl_set_drop_basic_set(set, convex_hull);
+	if (!set)
+		goto error;
+	while (set->n > 0) {
+		struct isl_basic_set *t;
+		t = isl_set_copy_basic_set(set);
+		if (!t)
+			goto error;
+		set = isl_set_drop_basic_set(set, t);
+		if (!set)
+			goto error;
+		convex_hull = convex_hull_pair(convex_hull, t);
+		if (set->n == 0)
+			break;
+		t = isl_basic_set_lineality_space(isl_basic_set_copy(convex_hull));
+		if (!t)
+			goto error;
+		if (isl_basic_set_is_universe(t)) {
+			isl_basic_set_free(convex_hull);
+			convex_hull = t;
+			break;
+		}
+		if (t->n_eq < isl_basic_set_total_dim(t)) {
+			set = isl_set_add_basic_set(set, convex_hull);
+			return modulo_lineality(set, t);
+		}
+		isl_basic_set_free(t);
+	}
+	isl_set_free(set);
+	return convex_hull;
+error:
+	isl_set_free(set);
+	isl_basic_set_free(convex_hull);
+	return NULL;
+}
+
+/* Compute an initial hull for wrapping containing a single initial
+ * facet.
+ * This function assumes that the given set is bounded.
+ */
+static struct isl_basic_set *initial_hull(struct isl_basic_set *hull,
+	struct isl_set *set)
+{
+	struct isl_mat *bounds = NULL;
+	unsigned dim;
+	int k;
+
+	if (!hull)
+		goto error;
+	bounds = initial_facet_constraint(set);
+	if (!bounds)
+		goto error;
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		goto error;
+	dim = isl_set_n_dim(set);
+	isl_assert(set->ctx, 1 + dim == bounds->n_col, goto error);
+	isl_seq_cpy(hull->ineq[k], bounds->row[0], bounds->n_col);
+	isl_mat_free(bounds);
+
+	return hull;
+error:
+	isl_basic_set_free(hull);
+	isl_mat_free(bounds);
+	return NULL;
+}
+
+struct max_constraint {
+	struct isl_mat *c;
+	int	 	count;
+	int		ineq;
+};
+
+static int max_constraint_equal(const void *entry, const void *val)
+{
+	struct max_constraint *a = (struct max_constraint *)entry;
+	isl_int *b = (isl_int *)val;
+
+	return isl_seq_eq(a->c->row[0] + 1, b, a->c->n_col - 1);
+}
+
+static void update_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+	isl_int *con, unsigned len, int n, int ineq)
+{
+	struct isl_hash_table_entry *entry;
+	struct max_constraint *c;
+	uint32_t c_hash;
+
+	c_hash = isl_seq_get_hash(con + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+			con + 1, 0);
+	if (!entry)
+		return;
+	c = entry->data;
+	if (c->count < n) {
+		isl_hash_table_remove(ctx, table, entry);
+		return;
+	}
+	c->count++;
+	if (isl_int_gt(c->c->row[0][0], con[0]))
+		return;
+	if (isl_int_eq(c->c->row[0][0], con[0])) {
+		if (ineq)
+			c->ineq = ineq;
+		return;
+	}
+	c->c = isl_mat_cow(c->c);
+	isl_int_set(c->c->row[0][0], con[0]);
+	c->ineq = ineq;
+}
+
+/* Check whether the constraint hash table "table" constains the constraint
+ * "con".
+ */
+static int has_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+	isl_int *con, unsigned len, int n)
+{
+	struct isl_hash_table_entry *entry;
+	struct max_constraint *c;
+	uint32_t c_hash;
+
+	c_hash = isl_seq_get_hash(con + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+			con + 1, 0);
+	if (!entry)
+		return 0;
+	c = entry->data;
+	if (c->count < n)
+		return 0;
+	return isl_int_eq(c->c->row[0][0], con[0]);
+}
+
+/* Check for inequality constraints of a basic set without equalities
+ * such that the same or more stringent copies of the constraint appear
+ * in all of the basic sets.  Such constraints are necessarily facet
+ * constraints of the convex hull.
+ *
+ * If the resulting basic set is by chance identical to one of
+ * the basic sets in "set", then we know that this basic set contains
+ * all other basic sets and is therefore the convex hull of set.
+ * In this case we set *is_hull to 1.
+ */
+static struct isl_basic_set *common_constraints(struct isl_basic_set *hull,
+	struct isl_set *set, int *is_hull)
+{
+	int i, j, s, n;
+	int min_constraints;
+	int best;
+	struct max_constraint *constraints = NULL;
+	struct isl_hash_table *table = NULL;
+	unsigned total;
+
+	*is_hull = 0;
+
+	for (i = 0; i < set->n; ++i)
+		if (set->p[i]->n_eq == 0)
+			break;
+	if (i >= set->n)
+		return hull;
+	min_constraints = set->p[i]->n_ineq;
+	best = i;
+	for (i = best + 1; i < set->n; ++i) {
+		if (set->p[i]->n_eq != 0)
+			continue;
+		if (set->p[i]->n_ineq >= min_constraints)
+			continue;
+		min_constraints = set->p[i]->n_ineq;
+		best = i;
+	}
+	constraints = isl_calloc_array(hull->ctx, struct max_constraint,
+					min_constraints);
+	if (!constraints)
+		return hull;
+	table = isl_alloc_type(hull->ctx, struct isl_hash_table);
+	if (isl_hash_table_init(hull->ctx, table, min_constraints))
+		goto error;
+
+	total = isl_space_dim(set->dim, isl_dim_all);
+	for (i = 0; i < set->p[best]->n_ineq; ++i) {
+		constraints[i].c = isl_mat_sub_alloc6(hull->ctx,
+			set->p[best]->ineq + i, 0, 1, 0, 1 + total);
+		if (!constraints[i].c)
+			goto error;
+		constraints[i].ineq = 1;
+	}
+	for (i = 0; i < min_constraints; ++i) {
+		struct isl_hash_table_entry *entry;
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(constraints[i].c->row[0] + 1, total);
+		entry = isl_hash_table_find(hull->ctx, table, c_hash,
+			max_constraint_equal, constraints[i].c->row[0] + 1, 1);
+		if (!entry)
+			goto error;
+		isl_assert(hull->ctx, !entry->data, goto error);
+		entry->data = &constraints[i];
+	}
+
+	n = 0;
+	for (s = 0; s < set->n; ++s) {
+		if (s == best)
+			continue;
+
+		for (i = 0; i < set->p[s]->n_eq; ++i) {
+			isl_int *eq = set->p[s]->eq[i];
+			for (j = 0; j < 2; ++j) {
+				isl_seq_neg(eq, eq, 1 + total);
+				update_constraint(hull->ctx, table,
+							    eq, total, n, 0);
+			}
+		}
+		for (i = 0; i < set->p[s]->n_ineq; ++i) {
+			isl_int *ineq = set->p[s]->ineq[i];
+			update_constraint(hull->ctx, table, ineq, total, n,
+				set->p[s]->n_eq == 0);
+		}
+		++n;
+	}
+
+	for (i = 0; i < min_constraints; ++i) {
+		if (constraints[i].count < n)
+			continue;
+		if (!constraints[i].ineq)
+			continue;
+		j = isl_basic_set_alloc_inequality(hull);
+		if (j < 0)
+			goto error;
+		isl_seq_cpy(hull->ineq[j], constraints[i].c->row[0], 1 + total);
+	}
+
+	for (s = 0; s < set->n; ++s) {
+		if (set->p[s]->n_eq)
+			continue;
+		if (set->p[s]->n_ineq != hull->n_ineq)
+			continue;
+		for (i = 0; i < set->p[s]->n_ineq; ++i) {
+			isl_int *ineq = set->p[s]->ineq[i];
+			if (!has_constraint(hull->ctx, table, ineq, total, n))
+				break;
+		}
+		if (i == set->p[s]->n_ineq)
+			*is_hull = 1;
+	}
+
+	isl_hash_table_clear(table);
+	for (i = 0; i < min_constraints; ++i)
+		isl_mat_free(constraints[i].c);
+	free(constraints);
+	free(table);
+	return hull;
+error:
+	isl_hash_table_clear(table);
+	free(table);
+	if (constraints)
+		for (i = 0; i < min_constraints; ++i)
+			isl_mat_free(constraints[i].c);
+	free(constraints);
+	return hull;
+}
+
+/* Create a template for the convex hull of "set" and fill it up
+ * obvious facet constraints, if any.  If the result happens to
+ * be the convex hull of "set" then *is_hull is set to 1.
+ */
+static struct isl_basic_set *proto_hull(struct isl_set *set, int *is_hull)
+{
+	struct isl_basic_set *hull;
+	unsigned n_ineq;
+	int i;
+
+	n_ineq = 1;
+	for (i = 0; i < set->n; ++i) {
+		n_ineq += set->p[i]->n_eq;
+		n_ineq += set->p[i]->n_ineq;
+	}
+	hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+	hull = isl_basic_set_set_rational(hull);
+	if (!hull)
+		return NULL;
+	return common_constraints(hull, set, is_hull);
+}
+
+static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set)
+{
+	struct isl_basic_set *hull;
+	int is_hull;
+
+	hull = proto_hull(set, &is_hull);
+	if (hull && !is_hull) {
+		if (hull->n_ineq == 0)
+			hull = initial_hull(hull, set);
+		hull = extend(hull, set);
+	}
+	isl_set_free(set);
+
+	return hull;
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions.  Depending on whether the set is bounded,
+ * we pass control to the wrapping based convex hull or
+ * the Fourier-Motzkin elimination based convex hull.
+ * We also handle a few special cases before checking the boundedness.
+ */
+static struct isl_basic_set *uset_convex_hull(struct isl_set *set)
+{
+	struct isl_basic_set *convex_hull = NULL;
+	struct isl_basic_set *lin;
+
+	if (isl_set_n_dim(set) == 0)
+		return convex_hull_0d(set);
+
+	set = isl_set_coalesce(set);
+	set = isl_set_set_rational(set);
+
+	if (!set)
+		goto error;
+	if (!set)
+		return NULL;
+	if (set->n == 1) {
+		convex_hull = isl_basic_set_copy(set->p[0]);
+		isl_set_free(set);
+		return convex_hull;
+	}
+	if (isl_set_n_dim(set) == 1)
+		return convex_hull_1d(set);
+
+	if (isl_set_is_bounded(set) &&
+	    set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP)
+		return uset_convex_hull_wrap(set);
+
+	lin = uset_combined_lineality_space(isl_set_copy(set));
+	if (!lin)
+		goto error;
+	if (isl_basic_set_is_universe(lin)) {
+		isl_set_free(set);
+		return lin;
+	}
+	if (lin->n_eq < isl_basic_set_total_dim(lin))
+		return modulo_lineality(set, lin);
+	isl_basic_set_free(lin);
+
+	return uset_convex_hull_unbounded(set);
+error:
+	isl_set_free(set);
+	isl_basic_set_free(convex_hull);
+	return NULL;
+}
+
+/* This is the core procedure, where "set" is a "pure" set, i.e.,
+ * without parameters or divs and where the convex hull of set is
+ * known to be full-dimensional.
+ */
+static struct isl_basic_set *uset_convex_hull_wrap_bounded(struct isl_set *set)
+{
+	struct isl_basic_set *convex_hull = NULL;
+
+	if (!set)
+		goto error;
+
+	if (isl_set_n_dim(set) == 0) {
+		convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+		isl_set_free(set);
+		convex_hull = isl_basic_set_set_rational(convex_hull);
+		return convex_hull;
+	}
+
+	set = isl_set_set_rational(set);
+	set = isl_set_coalesce(set);
+	if (!set)
+		goto error;
+	if (set->n == 1) {
+		convex_hull = isl_basic_set_copy(set->p[0]);
+		isl_set_free(set);
+		convex_hull = isl_basic_map_remove_redundancies(convex_hull);
+		return convex_hull;
+	}
+	if (isl_set_n_dim(set) == 1)
+		return convex_hull_1d(set);
+
+	return uset_convex_hull_wrap(set);
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute the convex hull of set "set" with affine hull "affine_hull",
+ * We first remove the equalities (transforming the set), compute the
+ * convex hull of the transformed set and then add the equalities back
+ * (after performing the inverse transformation.
+ */
+static struct isl_basic_set *modulo_affine_hull(
+	struct isl_set *set, struct isl_basic_set *affine_hull)
+{
+	struct isl_mat *T;
+	struct isl_mat *T2;
+	struct isl_basic_set *dummy;
+	struct isl_basic_set *convex_hull;
+
+	dummy = isl_basic_set_remove_equalities(
+			isl_basic_set_copy(affine_hull), &T, &T2);
+	if (!dummy)
+		goto error;
+	isl_basic_set_free(dummy);
+	set = isl_set_preimage(set, T);
+	convex_hull = uset_convex_hull(set);
+	convex_hull = isl_basic_set_preimage(convex_hull, T2);
+	convex_hull = isl_basic_set_intersect(convex_hull, affine_hull);
+	return convex_hull;
+error:
+	isl_basic_set_free(affine_hull);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute the convex hull of a map.
+ *
+ * The implementation was inspired by "Extended Convex Hull" by Fukuda et al.,
+ * specifically, the wrapping of facets to obtain new facets.
+ */
+struct isl_basic_map *isl_map_convex_hull(struct isl_map *map)
+{
+	struct isl_basic_set *bset;
+	struct isl_basic_map *model = NULL;
+	struct isl_basic_set *affine_hull = NULL;
+	struct isl_basic_map *convex_hull = NULL;
+	struct isl_set *set = NULL;
+	struct isl_ctx *ctx;
+
+	map = isl_map_detect_equalities(map);
+	map = isl_map_align_divs(map);
+	if (!map)
+		goto error;
+
+	ctx = map->ctx;
+	if (map->n == 0) {
+		convex_hull = isl_basic_map_empty_like_map(map);
+		isl_map_free(map);
+		return convex_hull;
+	}
+
+	model = isl_basic_map_copy(map->p[0]);
+	set = isl_map_underlying_set(map);
+	if (!set)
+		goto error;
+
+	affine_hull = isl_set_affine_hull(isl_set_copy(set));
+	if (!affine_hull)
+		goto error;
+	if (affine_hull->n_eq != 0)
+		bset = modulo_affine_hull(set, affine_hull);
+	else {
+		isl_basic_set_free(affine_hull);
+		bset = uset_convex_hull(set);
+	}
+
+	convex_hull = isl_basic_map_overlying_set(bset, model);
+	if (!convex_hull)
+		return NULL;
+
+	ISL_F_SET(convex_hull, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(convex_hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+	ISL_F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL);
+	return convex_hull;
+error:
+	isl_set_free(set);
+	isl_basic_map_free(model);
+	return NULL;
+}
+
+struct isl_basic_set *isl_set_convex_hull(struct isl_set *set)
+{
+	return (struct isl_basic_set *)
+		isl_map_convex_hull((struct isl_map *)set);
+}
+
+__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map)
+{
+	isl_basic_map *hull;
+
+	hull = isl_map_convex_hull(map);
+	return isl_basic_map_remove_divs(hull);
+}
+
+__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set)
+{
+	return (isl_basic_set *)isl_map_polyhedral_hull((isl_map *)set);
+}
+
+struct sh_data_entry {
+	struct isl_hash_table	*table;
+	struct isl_tab		*tab;
+};
+
+/* Holds the data needed during the simple hull computation.
+ * In particular,
+ *	n		the number of basic sets in the original set
+ *	hull_table	a hash table of already computed constraints
+ *			in the simple hull
+ *	p		for each basic set,
+ *		table		a hash table of the constraints
+ *		tab		the tableau corresponding to the basic set
+ */
+struct sh_data {
+	struct isl_ctx		*ctx;
+	unsigned		n;
+	struct isl_hash_table	*hull_table;
+	struct sh_data_entry	p[1];
+};
+
+static void sh_data_free(struct sh_data *data)
+{
+	int i;
+
+	if (!data)
+		return;
+	isl_hash_table_free(data->ctx, data->hull_table);
+	for (i = 0; i < data->n; ++i) {
+		isl_hash_table_free(data->ctx, data->p[i].table);
+		isl_tab_free(data->p[i].tab);
+	}
+	free(data);
+}
+
+struct ineq_cmp_data {
+	unsigned	len;
+	isl_int		*p;
+};
+
+static int has_ineq(const void *entry, const void *val)
+{
+	isl_int *row = (isl_int *)entry;
+	struct ineq_cmp_data *v = (struct ineq_cmp_data *)val;
+
+	return isl_seq_eq(row + 1, v->p + 1, v->len) ||
+	       isl_seq_is_neg(row + 1, v->p + 1, v->len);
+}
+
+static int hash_ineq(struct isl_ctx *ctx, struct isl_hash_table *table,
+			isl_int *ineq, unsigned len)
+{
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+	struct isl_hash_table_entry *entry;
+
+	v.len = len;
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, has_ineq, &v, 1);
+	if (!entry)
+		return - 1;
+	entry->data = ineq;
+	return 0;
+}
+
+/* Fill hash table "table" with the constraints of "bset".
+ * Equalities are added as two inequalities.
+ * The value in the hash table is a pointer to the (in)equality of "bset".
+ */
+static int hash_basic_set(struct isl_hash_table *table,
+				struct isl_basic_set *bset)
+{
+	int i, j;
+	unsigned dim = isl_basic_set_total_dim(bset);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		for (j = 0; j < 2; ++j) {
+			isl_seq_neg(bset->eq[i], bset->eq[i], 1 + dim);
+			if (hash_ineq(bset->ctx, table, bset->eq[i], dim) < 0)
+				return -1;
+		}
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (hash_ineq(bset->ctx, table, bset->ineq[i], dim) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static struct sh_data *sh_data_alloc(struct isl_set *set, unsigned n_ineq)
+{
+	struct sh_data *data;
+	int i;
+
+	data = isl_calloc(set->ctx, struct sh_data,
+		sizeof(struct sh_data) +
+		(set->n - 1) * sizeof(struct sh_data_entry));
+	if (!data)
+		return NULL;
+	data->ctx = set->ctx;
+	data->n = set->n;
+	data->hull_table = isl_hash_table_alloc(set->ctx, n_ineq);
+	if (!data->hull_table)
+		goto error;
+	for (i = 0; i < set->n; ++i) {
+		data->p[i].table = isl_hash_table_alloc(set->ctx,
+				    2 * set->p[i]->n_eq + set->p[i]->n_ineq);
+		if (!data->p[i].table)
+			goto error;
+		if (hash_basic_set(data->p[i].table, set->p[i]) < 0)
+			goto error;
+	}
+	return data;
+error:
+	sh_data_free(data);
+	return NULL;
+}
+
+/* Check if inequality "ineq" is a bound for basic set "j" or if
+ * it can be relaxed (by increasing the constant term) to become
+ * a bound for that basic set.  In the latter case, the constant
+ * term is updated.
+ * Relaxation of the constant term is only allowed if "shift" is set.
+ *
+ * Return 1 if "ineq" is a bound
+ *	  0 if "ineq" may attain arbitrarily small values on basic set "j"
+ *	 -1 if some error occurred
+ */
+static int is_bound(struct sh_data *data, struct isl_set *set, int j,
+	isl_int *ineq, int shift)
+{
+	enum isl_lp_result res;
+	isl_int opt;
+
+	if (!data->p[j].tab) {
+		data->p[j].tab = isl_tab_from_basic_set(set->p[j], 0);
+		if (!data->p[j].tab)
+			return -1;
+	}
+
+	isl_int_init(opt);
+
+	res = isl_tab_min(data->p[j].tab, ineq, data->ctx->one,
+				&opt, NULL, 0);
+	if (res == isl_lp_ok && isl_int_is_neg(opt)) {
+		if (shift)
+			isl_int_sub(ineq[0], ineq[0], opt);
+		else
+			res = isl_lp_unbounded;
+	}
+
+	isl_int_clear(opt);
+
+	return (res == isl_lp_ok || res == isl_lp_empty) ? 1 :
+	       res == isl_lp_unbounded ? 0 : -1;
+}
+
+/* Check if inequality "ineq" from basic set "i" is or can be relaxed to
+ * become a bound on the whole set.  If so, add the (relaxed) inequality
+ * to "hull".  Relaxation is only allowed if "shift" is set.
+ *
+ * We first check if "hull" already contains a translate of the inequality.
+ * If so, we are done.
+ * Then, we check if any of the previous basic sets contains a translate
+ * of the inequality.  If so, then we have already considered this
+ * inequality and we are done.
+ * Otherwise, for each basic set other than "i", we check if the inequality
+ * is a bound on the basic set.
+ * For previous basic sets, we know that they do not contain a translate
+ * of the inequality, so we directly call is_bound.
+ * For following basic sets, we first check if a translate of the
+ * inequality appears in its description and if so directly update
+ * the inequality accordingly.
+ */
+static struct isl_basic_set *add_bound(struct isl_basic_set *hull,
+	struct sh_data *data, struct isl_set *set, int i, isl_int *ineq,
+	int shift)
+{
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+	struct isl_hash_table_entry *entry;
+	int j, k;
+
+	if (!hull)
+		return NULL;
+
+	v.len = isl_basic_set_total_dim(hull);
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+	entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+					has_ineq, &v, 0);
+	if (entry)
+		return hull;
+
+	for (j = 0; j < i; ++j) {
+		entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+						c_hash, has_ineq, &v, 0);
+		if (entry)
+			break;
+	}
+	if (j < i)
+		return hull;
+
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+	for (j = 0; j < i; ++j) {
+		int bound;
+		bound = is_bound(data, set, j, hull->ineq[k], shift);
+		if (bound < 0)
+			goto error;
+		if (!bound)
+			break;
+	}
+	if (j < i) {
+		isl_basic_set_free_inequality(hull, 1);
+		return hull;
+	}
+
+	for (j = i + 1; j < set->n; ++j) {
+		int bound, neg;
+		isl_int *ineq_j;
+		entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+						c_hash, has_ineq, &v, 0);
+		if (entry) {
+			ineq_j = entry->data;
+			neg = isl_seq_is_neg(ineq_j + 1,
+					     hull->ineq[k] + 1, v.len);
+			if (neg)
+				isl_int_neg(ineq_j[0], ineq_j[0]);
+			if (isl_int_gt(ineq_j[0], hull->ineq[k][0]))
+				isl_int_set(hull->ineq[k][0], ineq_j[0]);
+			if (neg)
+				isl_int_neg(ineq_j[0], ineq_j[0]);
+			continue;
+		}
+		bound = is_bound(data, set, j, hull->ineq[k], shift);
+		if (bound < 0)
+			goto error;
+		if (!bound)
+			break;
+	}
+	if (j < set->n) {
+		isl_basic_set_free_inequality(hull, 1);
+		return hull;
+	}
+
+	entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+					has_ineq, &v, 1);
+	if (!entry)
+		goto error;
+	entry->data = hull->ineq[k];
+
+	return hull;
+error:
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Check if any inequality from basic set "i" is or can be relaxed to
+ * become a bound on the whole set.  If so, add the (relaxed) inequality
+ * to "hull".  Relaxation is only allowed if "shift" is set.
+ */
+static struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
+	struct sh_data *data, struct isl_set *set, int i, int shift)
+{
+	int j, k;
+	unsigned dim = isl_basic_set_total_dim(bset);
+
+	for (j = 0; j < set->p[i]->n_eq; ++j) {
+		for (k = 0; k < 2; ++k) {
+			isl_seq_neg(set->p[i]->eq[j], set->p[i]->eq[j], 1+dim);
+			bset = add_bound(bset, data, set, i, set->p[i]->eq[j],
+					    shift);
+		}
+	}
+	for (j = 0; j < set->p[i]->n_ineq; ++j)
+		bset = add_bound(bset, data, set, i, set->p[i]->ineq[j], shift);
+	return bset;
+}
+
+/* Compute a superset of the convex hull of set that is described
+ * by only (translates of) the constraints in the constituents of set.
+ * Translation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_set *uset_simple_hull(__isl_take isl_set *set,
+	int shift)
+{
+	struct sh_data *data = NULL;
+	struct isl_basic_set *hull = NULL;
+	unsigned n_ineq;
+	int i;
+
+	if (!set)
+		return NULL;
+
+	n_ineq = 0;
+	for (i = 0; i < set->n; ++i) {
+		if (!set->p[i])
+			goto error;
+		n_ineq += 2 * set->p[i]->n_eq + set->p[i]->n_ineq;
+	}
+
+	hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+	if (!hull)
+		goto error;
+
+	data = sh_data_alloc(set, n_ineq);
+	if (!data)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		hull = add_bounds(hull, data, set, i, shift);
+
+	sh_data_free(data);
+	isl_set_free(set);
+
+	return hull;
+error:
+	sh_data_free(data);
+	isl_basic_set_free(hull);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only (translates of) the constraints in the constituents of map.
+ * Translation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_map *map_simple_hull(__isl_take isl_map *map,
+	int shift)
+{
+	struct isl_set *set = NULL;
+	struct isl_basic_map *model = NULL;
+	struct isl_basic_map *hull;
+	struct isl_basic_map *affine_hull;
+	struct isl_basic_set *bset = NULL;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0) {
+		hull = isl_basic_map_empty_like_map(map);
+		isl_map_free(map);
+		return hull;
+	}
+	if (map->n == 1) {
+		hull = isl_basic_map_copy(map->p[0]);
+		isl_map_free(map);
+		return hull;
+	}
+
+	map = isl_map_detect_equalities(map);
+	affine_hull = isl_map_affine_hull(isl_map_copy(map));
+	map = isl_map_align_divs(map);
+	model = map ? isl_basic_map_copy(map->p[0]) : NULL;
+
+	set = isl_map_underlying_set(map);
+
+	bset = uset_simple_hull(set, shift);
+
+	hull = isl_basic_map_overlying_set(bset, model);
+
+	hull = isl_basic_map_intersect(hull, affine_hull);
+	hull = isl_basic_map_remove_redundancies(hull);
+
+	if (!hull)
+		return NULL;
+	ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+
+	hull = isl_basic_map_finalize(hull);
+
+	return hull;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only translates of the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map)
+{
+	return map_simple_hull(map, 1);
+}
+
+struct isl_basic_set *isl_set_simple_hull(struct isl_set *set)
+{
+	return (struct isl_basic_set *)
+		isl_map_simple_hull((struct isl_map *)set);
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull(
+	__isl_take isl_map *map)
+{
+	return map_simple_hull(map, 0);
+}
+
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull(
+	__isl_take isl_set *set)
+{
+	return isl_map_unshifted_simple_hull(set);
+}
+
+/* Check if "ineq" is a bound on "set" and, if so, add it to "hull".
+ *
+ * For each basic set in "set", we first check if the basic set
+ * contains a translate of "ineq".  If this translate is more relaxed,
+ * then we assume that "ineq" is not a bound on this basic set.
+ * Otherwise, we know that it is a bound.
+ * If the basic set does not contain a translate of "ineq", then
+ * we call is_bound to perform the test.
+ */
+static __isl_give isl_basic_set *add_bound_from_constraint(
+	__isl_take isl_basic_set *hull, struct sh_data *data,
+	__isl_keep isl_set *set, isl_int *ineq)
+{
+	int i, k;
+	isl_ctx *ctx;
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+
+	if (!hull || !set)
+		return isl_basic_set_free(hull);
+
+	v.len = isl_basic_set_total_dim(hull);
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+	ctx = isl_basic_set_get_ctx(hull);
+	for (i = 0; i < set->n; ++i) {
+		int bound;
+		struct isl_hash_table_entry *entry;
+
+		entry = isl_hash_table_find(ctx, data->p[i].table,
+						c_hash, &has_ineq, &v, 0);
+		if (entry) {
+			isl_int *ineq_i = entry->data;
+			int neg, more_relaxed;
+
+			neg = isl_seq_is_neg(ineq_i + 1, ineq + 1, v.len);
+			if (neg)
+				isl_int_neg(ineq_i[0], ineq_i[0]);
+			more_relaxed = isl_int_gt(ineq_i[0], ineq[0]);
+			if (neg)
+				isl_int_neg(ineq_i[0], ineq_i[0]);
+			if (more_relaxed)
+				break;
+			else
+				continue;
+		}
+		bound = is_bound(data, set, i, ineq, 0);
+		if (bound < 0)
+			return isl_basic_set_free(hull);
+		if (!bound)
+			break;
+	}
+	if (i < set->n)
+		return hull;
+
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		return isl_basic_set_free(hull);
+	isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+	return hull;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only some of the "n_ineq" constraints in the list "ineq", where "set"
+ * has no parameters or integer divisions.
+ *
+ * The inequalities in "ineq" are assumed to have been sorted such
+ * that constraints with the same linear part appear together and
+ * that among constraints with the same linear part, those with
+ * smaller constant term appear first.
+ *
+ * We reuse the same data structure that is used by uset_simple_hull,
+ * but we do not need the hull table since we will not consider the
+ * same constraint more than once.  We therefore allocate it with zero size.
+ *
+ * We run through the constraints and try to add them one by one,
+ * skipping identical constraints.  If we have added a constraint and
+ * the next constraint is a more relaxed translate, then we skip this
+ * next constraint as well.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_constraints(
+	__isl_take isl_set *set, int n_ineq, isl_int **ineq)
+{
+	int i;
+	int last_added = 0;
+	struct sh_data *data = NULL;
+	isl_basic_set *hull = NULL;
+	unsigned dim;
+
+	hull = isl_basic_set_alloc_space(isl_set_get_space(set), 0, 0, n_ineq);
+	if (!hull)
+		goto error;
+
+	data = sh_data_alloc(set, 0);
+	if (!data)
+		goto error;
+
+	dim = isl_set_dim(set, isl_dim_set);
+	for (i = 0; i < n_ineq; ++i) {
+		int hull_n_ineq = hull->n_ineq;
+		int parallel;
+
+		parallel = i > 0 && isl_seq_eq(ineq[i - 1] + 1, ineq[i] + 1,
+						dim);
+		if (parallel &&
+		    (last_added || isl_int_eq(ineq[i - 1][0], ineq[i][0])))
+			continue;
+		hull = add_bound_from_constraint(hull, data, set, ineq[i]);
+		if (!hull)
+			goto error;
+		last_added = hull->n_ineq > hull_n_ineq;
+	}
+
+	sh_data_free(data);
+	isl_set_free(set);
+	return hull;
+error:
+	sh_data_free(data);
+	isl_set_free(set);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Collect pointers to all the inequalities in the elements of "list"
+ * in "ineq".  For equalities, store both a pointer to the equality and
+ * a pointer to its opposite, which is first copied to "mat".
+ * "ineq" and "mat" are assumed to have been preallocated to the right size
+ * (the number of inequalities + 2 times the number of equalites and
+ * the number of equalities, respectively).
+ */
+static __isl_give isl_mat *collect_inequalities(__isl_take isl_mat *mat,
+	__isl_keep isl_basic_set_list *list, isl_int **ineq)
+{
+	int i, j, n, n_eq, n_ineq;
+
+	if (!mat)
+		return NULL;
+
+	n_eq = 0;
+	n_ineq = 0;
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		if (!bset)
+			return isl_mat_free(mat);
+		for (j = 0; j < bset->n_eq; ++j) {
+			ineq[n_ineq++] = mat->row[n_eq];
+			ineq[n_ineq++] = bset->eq[j];
+			isl_seq_neg(mat->row[n_eq++], bset->eq[j], mat->n_col);
+		}
+		for (j = 0; j < bset->n_ineq; ++j)
+			ineq[n_ineq++] = bset->ineq[j];
+		isl_basic_set_free(bset);
+	}
+
+	return mat;
+}
+
+/* Comparison routine for use as an isl_sort callback.
+ *
+ * Constraints with the same linear part are sorted together and
+ * among constraints with the same linear part, those with smaller
+ * constant term are sorted first.
+ */
+static int cmp_ineq(const void *a, const void *b, void *arg)
+{
+	unsigned dim = *(unsigned *) arg;
+	isl_int * const *ineq1 = a;
+	isl_int * const *ineq2 = b;
+	int cmp;
+
+	cmp = isl_seq_cmp((*ineq1) + 1, (*ineq2) + 1, dim);
+	if (cmp != 0)
+		return cmp;
+	return isl_int_cmp((*ineq1)[0], (*ineq2)[0]);
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list", where "set" has
+ * no parameters or integer divisions.
+ *
+ * We collect all the constraints in those elements and then
+ * sort the constraints such that constraints with the same linear part
+ * are sorted together and that those with smaller constant term are
+ * sorted first.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_basic_set_list(
+	__isl_take isl_set *set, __isl_take isl_basic_set_list *list)
+{
+	int i, n, n_eq, n_ineq;
+	unsigned dim;
+	isl_ctx *ctx;
+	isl_mat *mat = NULL;
+	isl_int **ineq = NULL;
+	isl_basic_set *hull;
+
+	if (!set)
+		goto error;
+	ctx = isl_set_get_ctx(set);
+
+	n_eq = 0;
+	n_ineq = 0;
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		if (!bset)
+			goto error;
+		n_eq += bset->n_eq;
+		n_ineq += 2 * bset->n_eq + bset->n_ineq;
+		isl_basic_set_free(bset);
+	}
+
+	ineq = isl_alloc_array(ctx, isl_int *, n_ineq);
+	if (n_ineq > 0 && !ineq)
+		goto error;
+
+	dim = isl_set_dim(set, isl_dim_set);
+	mat = isl_mat_alloc(ctx, n_eq, 1 + dim);
+	mat = collect_inequalities(mat, list, ineq);
+	if (!mat)
+		goto error;
+
+	if (isl_sort(ineq, n_ineq, sizeof(ineq[0]), &cmp_ineq, &dim) < 0)
+		goto error;
+
+	hull = uset_unshifted_simple_hull_from_constraints(set, n_ineq, ineq);
+
+	isl_mat_free(mat);
+	free(ineq);
+	isl_basic_set_list_free(list);
+	return hull;
+error:
+	isl_mat_free(mat);
+	free(ineq);
+	isl_set_free(set);
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If the list is empty, then we can only describe the universe set.
+ * If the input set is empty, then all constraints are valid, so
+ * we return the intersection of the elements in "list".
+ *
+ * Otherwise, we align all divs and temporarily treat them
+ * as regular variables, computing the unshifted simple hull in
+ * uset_unshifted_simple_hull_from_basic_set_list.
+ */
+static __isl_give isl_basic_set *set_unshifted_simple_hull_from_basic_set_list(
+	__isl_take isl_set *set, __isl_take isl_basic_set_list *list)
+{
+	isl_basic_set *model;
+	isl_basic_set *hull;
+
+	if (!set || !list)
+		goto error;
+
+	if (isl_basic_set_list_n_basic_set(list) == 0) {
+		isl_space *space;
+
+		space = isl_set_get_space(set);
+		isl_set_free(set);
+		isl_basic_set_list_free(list);
+		return isl_basic_set_universe(space);
+	}
+	if (isl_set_plain_is_empty(set)) {
+		isl_set_free(set);
+		return isl_basic_set_list_intersect(list);
+	}
+
+	set = isl_set_align_divs_to_basic_set_list(set, list);
+	if (!set)
+		goto error;
+	list = isl_basic_set_list_align_divs_to_basic_set(list, set->p[0]);
+
+	model = isl_basic_set_list_get_basic_set(list, 0);
+
+	set = isl_set_to_underlying_set(set);
+	list = isl_basic_set_list_underlying_set(list);
+
+	hull = uset_unshifted_simple_hull_from_basic_set_list(set, list);
+	hull = isl_basic_map_overlying_set(hull, model);
+
+	return hull;
+error:
+	isl_set_free(set);
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Return a sequence of the basic sets that make up the sets in "list".
+ */
+static __isl_give isl_basic_set_list *collect_basic_sets(
+	__isl_take isl_set_list *list)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_basic_set_list *bset_list;
+
+	if (!list)
+		return NULL;
+	n = isl_set_list_n_set(list);
+	ctx = isl_set_list_get_ctx(list);
+	bset_list = isl_basic_set_list_alloc(ctx, 0);
+
+	for (i = 0; i < n; ++i) {
+		isl_set *set;
+		isl_basic_set_list *list_i;
+
+		set = isl_set_list_get_set(list, i);
+		set = isl_set_compute_divs(set);
+		list_i = isl_set_get_basic_set_list(set);
+		isl_set_free(set);
+		bset_list = isl_basic_set_list_concat(bset_list, list_i);
+	}
+
+	isl_set_list_free(list);
+	return bset_list;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If "set" is the universe, then the convex hull (and therefore
+ * any superset of the convexhull) is the universe as well.
+ *
+ * Otherwise, we collect all the basic sets in the set list and
+ * continue with set_unshifted_simple_hull_from_basic_set_list.
+ */
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list(
+	__isl_take isl_set *set, __isl_take isl_set_list *list)
+{
+	isl_basic_set_list *bset_list;
+	int is_universe;
+
+	is_universe = isl_set_plain_is_universe(set);
+	if (is_universe < 0)
+		set = isl_set_free(set);
+	if (is_universe < 0 || is_universe) {
+		isl_set_list_free(list);
+		return isl_set_unshifted_simple_hull(set);
+	}
+
+	bset_list = collect_basic_sets(list);
+	return set_unshifted_simple_hull_from_basic_set_list(set, bset_list);
+}
+
+/* Given a set "set", return parametric bounds on the dimension "dim".
+ */
+static struct isl_basic_set *set_bounds(struct isl_set *set, int dim)
+{
+	unsigned set_dim = isl_set_dim(set, isl_dim_set);
+	set = isl_set_copy(set);
+	set = isl_set_eliminate_dims(set, dim + 1, set_dim - (dim + 1));
+	set = isl_set_eliminate_dims(set, 0, dim);
+	return isl_set_convex_hull(set);
+}
+
+/* Computes a "simple hull" and then check if each dimension in the
+ * resulting hull is bounded by a symbolic constant.  If not, the
+ * hull is intersected with the corresponding bounds on the whole set.
+ */
+struct isl_basic_set *isl_set_bounded_simple_hull(struct isl_set *set)
+{
+	int i, j;
+	struct isl_basic_set *hull;
+	unsigned nparam, left;
+	int removed_divs = 0;
+
+	hull = isl_set_simple_hull(isl_set_copy(set));
+	if (!hull)
+		goto error;
+
+	nparam = isl_basic_set_dim(hull, isl_dim_param);
+	for (i = 0; i < isl_basic_set_dim(hull, isl_dim_set); ++i) {
+		int lower = 0, upper = 0;
+		struct isl_basic_set *bounds;
+
+		left = isl_basic_set_total_dim(hull) - nparam - i - 1;
+		for (j = 0; j < hull->n_eq; ++j) {
+			if (isl_int_is_zero(hull->eq[j][1 + nparam + i]))
+				continue;
+			if (isl_seq_first_non_zero(hull->eq[j]+1+nparam+i+1,
+						    left) == -1)
+				break;
+		}
+		if (j < hull->n_eq)
+			continue;
+
+		for (j = 0; j < hull->n_ineq; ++j) {
+			if (isl_int_is_zero(hull->ineq[j][1 + nparam + i]))
+				continue;
+			if (isl_seq_first_non_zero(hull->ineq[j]+1+nparam+i+1,
+						    left) != -1 ||
+			    isl_seq_first_non_zero(hull->ineq[j]+1+nparam,
+						    i) != -1)
+				continue;
+			if (isl_int_is_pos(hull->ineq[j][1 + nparam + i]))
+				lower = 1;
+			else
+				upper = 1;
+			if (lower && upper)
+				break;
+		}
+
+		if (lower && upper)
+			continue;
+
+		if (!removed_divs) {
+			set = isl_set_remove_divs(set);
+			if (!set)
+				goto error;
+			removed_divs = 1;
+		}
+		bounds = set_bounds(set, i);
+		hull = isl_basic_set_intersect(hull, bounds);
+		if (!hull)
+			goto error;
+	}
+
+	isl_set_free(set);
+	return hull;
+error:
+	isl_set_free(set);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_ctx.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ctx.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ctx.c (added)
+++ polly/trunk/lib/External/isl/isl_ctx.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl/vec.h>
+#include <isl_options_private.h>
+
+#define __isl_calloc(type,size)		((type *)calloc(1, size))
+#define __isl_calloc_type(type)		__isl_calloc(type,sizeof(type))
+
+/* Check that the result of an allocation ("p") is not NULL and
+ * complain if it is.
+ * The only exception is when allocation size ("size") is equal to zero.
+ */
+static void *check_non_null(isl_ctx *ctx, void *p, size_t size)
+{
+	if (p || size == 0)
+		return p;
+	isl_die(ctx, isl_error_alloc, "allocation failure", return NULL);
+}
+
+/* Prepare for performing the next "operation" in the context.
+ * Return 0 if we are allowed to perform this operation and
+ * return -1 if we should abort the computation.
+ *
+ * In particular, we should stop if the user has explicitly aborted
+ * the computation or if the maximal number of operations has been exceeded.
+ */
+int isl_ctx_next_operation(isl_ctx *ctx)
+{
+	if (!ctx)
+		return -1;
+	if (ctx->abort) {
+		isl_ctx_set_error(ctx, isl_error_abort);
+		return -1;
+	}
+	if (ctx->max_operations && ctx->operations >= ctx->max_operations)
+		isl_die(ctx, isl_error_quota,
+			"maximal number of operations exceeded", return -1);
+	ctx->operations++;
+	return 0;
+}
+
+/* Call malloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_malloc_or_die(isl_ctx *ctx, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, malloc(size), size) : NULL;
+}
+
+/* Call calloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, calloc(nmemb, size), nmemb) : NULL;
+}
+
+/* Call realloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, realloc(ptr, size), size) : NULL;
+}
+
+void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
+	const char *file, int line)
+{
+	if (!ctx)
+		return;
+
+	isl_ctx_set_error(ctx, error);
+
+	switch (ctx->opt->on_error) {
+	case ISL_ON_ERROR_WARN:
+		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+		return;
+	case ISL_ON_ERROR_CONTINUE:
+		return;
+	case ISL_ON_ERROR_ABORT:
+		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+		abort();
+		return;
+	}
+}
+
+static struct isl_options *find_nested_options(struct isl_args *args,
+	void *opt, struct isl_args *wanted)
+{
+	int i;
+	struct isl_options *options;
+
+	if (args == wanted)
+		return opt;
+
+	for (i = 0; args->args[i].type != isl_arg_end; ++i) {
+		struct isl_arg *arg = &args->args[i];
+		void *child;
+
+		if (arg->type != isl_arg_child)
+			continue;
+
+		if (arg->offset == (size_t) -1)
+			child = opt;
+		else
+			child = *(void **)(((char *)opt) + arg->offset);
+
+		options = find_nested_options(arg->u.child.child,
+						child, wanted);
+		if (options)
+			return options;
+	}
+
+	return NULL;
+}
+
+static struct isl_options *find_nested_isl_options(struct isl_args *args,
+	void *opt)
+{
+	return find_nested_options(args, opt, &isl_options_args);
+}
+
+void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args)
+{
+	if (!ctx)
+		return NULL;
+	if (args == &isl_options_args)
+		return ctx->opt;
+	return find_nested_options(ctx->user_args, ctx->user_opt, args);
+}
+
+isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt)
+{
+	struct isl_ctx *ctx = NULL;
+	struct isl_options *opt = NULL;
+	int opt_allocated = 0;
+
+	if (!user_opt)
+		return NULL;
+
+	opt = find_nested_isl_options(args, user_opt);
+	if (!opt) {
+		opt = isl_options_new_with_defaults();
+		if (!opt)
+			goto error;
+		opt_allocated = 1;
+	}
+
+	ctx = __isl_calloc_type(struct isl_ctx);
+	if (!ctx)
+		goto error;
+
+	if (isl_hash_table_init(ctx, &ctx->id_table, 0))
+		goto error;
+
+	ctx->stats = isl_calloc_type(ctx, struct isl_stats);
+	if (!ctx->stats)
+		goto error;
+
+	ctx->user_args = args;
+	ctx->user_opt = user_opt;
+	ctx->opt_allocated = opt_allocated;
+	ctx->opt = opt;
+	ctx->ref = 0;
+
+	isl_int_init(ctx->zero);
+	isl_int_set_si(ctx->zero, 0);
+
+	isl_int_init(ctx->one);
+	isl_int_set_si(ctx->one, 1);
+
+	isl_int_init(ctx->two);
+	isl_int_set_si(ctx->two, 2);
+
+	isl_int_init(ctx->negone);
+	isl_int_set_si(ctx->negone, -1);
+
+	isl_int_init(ctx->normalize_gcd);
+
+	ctx->n_cached = 0;
+	ctx->n_miss = 0;
+
+	ctx->error = isl_error_none;
+
+	ctx->operations = 0;
+	isl_ctx_set_max_operations(ctx, ctx->opt->max_operations);
+
+	return ctx;
+error:
+	isl_args_free(args, user_opt);
+	if (opt_allocated)
+		isl_options_free(opt);
+	free(ctx);
+	return NULL;
+}
+
+struct isl_ctx *isl_ctx_alloc()
+{
+	struct isl_options *opt;
+
+	opt = isl_options_new_with_defaults();
+
+	return isl_ctx_alloc_with_options(&isl_options_args, opt);
+}
+
+void isl_ctx_ref(struct isl_ctx *ctx)
+{
+	ctx->ref++;
+}
+
+void isl_ctx_deref(struct isl_ctx *ctx)
+{
+	isl_assert(ctx, ctx->ref > 0, return);
+	ctx->ref--;
+}
+
+/* Print statistics on usage.
+ */
+static void print_stats(isl_ctx *ctx)
+{
+	fprintf(stderr, "operations: %lu\n", ctx->operations);
+}
+
+void isl_ctx_free(struct isl_ctx *ctx)
+{
+	if (!ctx)
+		return;
+	if (ctx->ref != 0)
+		isl_die(ctx, isl_error_invalid,
+			"isl_ctx freed, but some objects still reference it",
+			return);
+
+	if (ctx->opt->print_stats)
+		print_stats(ctx);
+
+	isl_hash_table_clear(&ctx->id_table);
+	isl_blk_clear_cache(ctx);
+	isl_int_clear(ctx->zero);
+	isl_int_clear(ctx->one);
+	isl_int_clear(ctx->two);
+	isl_int_clear(ctx->negone);
+	isl_int_clear(ctx->normalize_gcd);
+	isl_args_free(ctx->user_args, ctx->user_opt);
+	if (ctx->opt_allocated)
+		isl_options_free(ctx->opt);
+	free(ctx->stats);
+	free(ctx);
+}
+
+struct isl_options *isl_ctx_options(isl_ctx *ctx)
+{
+	if (!ctx)
+		return NULL;
+	return ctx->opt;
+}
+
+enum isl_error isl_ctx_last_error(isl_ctx *ctx)
+{
+	return ctx->error;
+}
+
+void isl_ctx_reset_error(isl_ctx *ctx)
+{
+	ctx->error = isl_error_none;
+}
+
+void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error)
+{
+	if (ctx)
+		ctx->error = error;
+}
+
+void isl_ctx_abort(isl_ctx *ctx)
+{
+	if (ctx)
+		ctx->abort = 1;
+}
+
+void isl_ctx_resume(isl_ctx *ctx)
+{
+	if (ctx)
+		ctx->abort = 0;
+}
+
+int isl_ctx_aborted(isl_ctx *ctx)
+{
+	return ctx ? ctx->abort : -1;
+}
+
+int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags)
+{
+	if (!ctx)
+		return -1;
+	return isl_args_parse(ctx->user_args, argc, argv, ctx->user_opt, flags);
+}
+
+/* Set the maximal number of iterations of "ctx" to "max_operations".
+ */
+void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations)
+{
+	if (!ctx)
+		return;
+	ctx->max_operations = max_operations;
+}
+
+/* Return the maximal number of iterations of "ctx".
+ */
+unsigned long isl_ctx_get_max_operations(isl_ctx *ctx)
+{
+	return ctx ? ctx->max_operations : 0;
+}
+
+/* Reset the number of operations performed by "ctx".
+ */
+void isl_ctx_reset_operations(isl_ctx *ctx)
+{
+	if (!ctx)
+		return;
+	ctx->operations = 0;
+}

Added: polly/trunk/lib/External/isl/isl_ctx_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ctx_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ctx_private.h (added)
+++ polly/trunk/lib/External/isl/isl_ctx_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,34 @@
+#include <isl/ctx.h>
+#include <isl_blk.h>
+
+struct isl_ctx {
+	int			ref;
+
+	struct isl_stats	*stats;
+
+	int			 opt_allocated;
+	struct isl_options	*opt;
+	void			*user_opt;
+	struct isl_args		*user_args;
+
+	isl_int			zero;
+	isl_int			one;
+	isl_int			two;
+	isl_int			negone;
+
+	isl_int			normalize_gcd;
+
+	int			n_cached;
+	int			n_miss;
+	struct isl_blk		cache[ISL_BLK_CACHE_SIZE];
+	struct isl_hash_table	id_table;
+
+	enum isl_error		error;
+
+	int			abort;
+
+	unsigned long		operations;
+	unsigned long		max_operations;
+};
+
+int isl_ctx_next_operation(isl_ctx *ctx);

Added: polly/trunk/lib/External/isl/isl_deprecated.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_deprecated.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_deprecated.c (added)
+++ polly/trunk/lib/External/isl/isl_deprecated.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,10 @@
+#include <isl/set.h>
+
+/* This function was never documented and has been replaced by
+ * isl_basic_set_add_dims.
+ */
+__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned n)
+{
+	return isl_basic_set_add_dims(bset, type, n);
+}

Added: polly/trunk/lib/External/isl/isl_dim.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim.c (added)
+++ polly/trunk/lib/External/isl/isl_dim.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,258 @@
+#include <isl/dim.h>
+#include <isl/aff.h>
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl/polynomial.h>
+
+isl_ctx *isl_dim_get_ctx(__isl_keep isl_space *dim)
+{
+	return isl_space_get_ctx(dim);
+}
+
+__isl_give isl_space *isl_dim_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	return isl_space_alloc(ctx, nparam, n_in, n_out);
+}
+__isl_give isl_space *isl_dim_set_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned dim)
+{
+	return isl_space_set_alloc(ctx, nparam, dim);
+}
+__isl_give isl_space *isl_dim_copy(__isl_keep isl_space *dim)
+{
+	return isl_space_copy(dim);
+}
+void isl_dim_free(__isl_take isl_space *dim)
+{
+	isl_space_free(dim);
+}
+
+unsigned isl_dim_size(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	return isl_space_dim(dim, type);
+}
+
+__isl_give isl_space *isl_dim_set_dim_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	return isl_space_set_dim_id(dim, type, pos, id);
+}
+int isl_dim_has_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_space_has_dim_id(dim, type, pos);
+}
+__isl_give isl_id *isl_dim_get_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_space_get_dim_id(dim, type, pos);
+}
+
+int isl_dim_find_dim_by_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, __isl_keep isl_id *id)
+{
+	return isl_space_find_dim_by_id(dim, type, id);
+}
+
+__isl_give isl_space *isl_dim_set_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	return isl_space_set_tuple_id(dim, type, id);
+}
+__isl_give isl_space *isl_dim_reset_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type)
+{
+	return isl_space_reset_tuple_id(dim, type);
+}
+int isl_dim_has_tuple_id(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	return isl_space_has_tuple_id(dim, type);
+}
+__isl_give isl_id *isl_dim_get_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	return isl_space_get_tuple_id(dim, type);
+}
+
+__isl_give isl_space *isl_dim_set_name(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, __isl_keep const char *name)
+{
+	return isl_space_set_dim_name(dim, type, pos, name);
+}
+__isl_keep const char *isl_dim_get_name(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_space_get_dim_name(dim, type, pos);
+}
+
+__isl_give isl_space *isl_dim_set_tuple_name(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *s)
+{
+	return isl_space_set_tuple_name(dim, type, s);
+}
+const char *isl_dim_get_tuple_name(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	return isl_space_get_tuple_name(dim, type);
+}
+
+int isl_dim_is_wrapping(__isl_keep isl_space *dim)
+{
+	return isl_space_is_wrapping(dim);
+}
+__isl_give isl_space *isl_dim_wrap(__isl_take isl_space *dim)
+{
+	return isl_space_wrap(dim);
+}
+__isl_give isl_space *isl_dim_unwrap(__isl_take isl_space *dim)
+{
+	return isl_space_unwrap(dim);
+}
+
+__isl_give isl_space *isl_dim_domain(__isl_take isl_space *dim)
+{
+	return isl_space_domain(dim);
+}
+__isl_give isl_space *isl_dim_from_domain(__isl_take isl_space *dim)
+{
+	return isl_space_from_domain(dim);
+}
+__isl_give isl_space *isl_dim_range(__isl_take isl_space *dim)
+{
+	return isl_space_range(dim);
+}
+__isl_give isl_space *isl_dim_from_range(__isl_take isl_space *dim)
+{
+	return isl_space_from_range(dim);
+}
+__isl_give isl_space *isl_dim_reverse(__isl_take isl_space *dim)
+{
+	return isl_space_reverse(dim);
+}
+__isl_give isl_space *isl_dim_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	return isl_space_join(left, right);
+}
+__isl_give isl_space *isl_dim_align_params(__isl_take isl_space *dim1,
+	__isl_take isl_space *dim2)
+{
+	return isl_space_align_params(dim1, dim2);
+}
+__isl_give isl_space *isl_dim_insert(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	return isl_space_insert_dims(dim, type, pos, n);
+}
+__isl_give isl_space *isl_dim_add(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned n)
+{
+	return isl_space_add_dims(dim, type, n);
+}
+__isl_give isl_space *isl_dim_drop(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_space_drop_dims(dim, type, first, n);
+}
+__isl_give isl_space *isl_dim_move(__isl_take isl_space *dim,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	return isl_space_move_dims(dim, dst_type, dst_pos, src_type, src_pos, n);
+}
+__isl_give isl_space *isl_dim_map_from_set(__isl_take isl_space *dim)
+{
+	return isl_space_map_from_set(dim);
+}
+__isl_give isl_space *isl_dim_zip(__isl_take isl_space *dim)
+{
+	return isl_space_zip(dim);
+}
+
+__isl_give isl_local_space *isl_local_space_from_dim(
+	__isl_take isl_space *dim)
+{
+	return isl_local_space_from_space(dim);
+}
+__isl_give isl_space *isl_local_space_get_dim(
+	__isl_keep isl_local_space *ls)
+{
+	return isl_local_space_get_space(ls);
+}
+
+__isl_give isl_space *isl_aff_get_dim(__isl_keep isl_aff *aff)
+{
+	return isl_aff_get_space(aff);
+}
+__isl_give isl_space *isl_pw_aff_get_dim(__isl_keep isl_pw_aff *pwaff)
+{
+	return isl_pw_aff_get_space(pwaff);
+}
+
+__isl_give isl_space *isl_constraint_get_dim(
+	__isl_keep isl_constraint *constraint)
+{
+	return isl_constraint_get_space(constraint);
+}
+
+__isl_give isl_space *isl_basic_map_get_dim(__isl_keep isl_basic_map *bmap)
+{
+	return isl_basic_map_get_space(bmap);
+}
+__isl_give isl_space *isl_map_get_dim(__isl_keep isl_map *map)
+{
+	return isl_map_get_space(map);
+}
+__isl_give isl_space *isl_union_map_get_dim(__isl_keep isl_union_map *umap)
+{
+	return isl_union_map_get_space(umap);
+}
+
+__isl_give isl_space *isl_basic_set_get_dim(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_get_space(bset);
+}
+__isl_give isl_space *isl_set_get_dim(__isl_keep isl_set *set)
+{
+	return isl_set_get_space(set);
+}
+__isl_give isl_space *isl_union_set_get_dim(__isl_keep isl_union_set *uset)
+{
+	return isl_union_set_get_space(uset);
+}
+
+__isl_give isl_space *isl_point_get_dim(__isl_keep isl_point *pnt)
+{
+	return isl_point_get_space(pnt);
+}
+
+__isl_give isl_space *isl_qpolynomial_get_dim(__isl_keep isl_qpolynomial *qp)
+{
+	return isl_qpolynomial_get_space(qp);
+}
+__isl_give isl_space *isl_pw_qpolynomial_get_dim(
+	__isl_keep isl_pw_qpolynomial *pwqp)
+{
+	return isl_pw_qpolynomial_get_space(pwqp);
+}
+__isl_give isl_space *isl_qpolynomial_fold_get_dim(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	return isl_qpolynomial_fold_get_space(fold);
+}
+__isl_give isl_space *isl_pw_qpolynomial_fold_get_dim(
+	__isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	return isl_pw_qpolynomial_fold_get_space(pwf);
+}
+__isl_give isl_space *isl_union_pw_qpolynomial_get_dim(
+	__isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+	return isl_union_pw_qpolynomial_get_space(upwqp);
+}
+__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_dim(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	return isl_union_pw_qpolynomial_fold_get_space(upwf);
+}

Added: polly/trunk/lib/External/isl/isl_dim_map.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim_map.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim_map.c (added)
+++ polly/trunk/lib/External/isl/isl_dim_map.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_space_private.h>
+#include <isl_dim_map.h>
+#include <isl_reordering.h>
+
+struct isl_dim_map_entry {
+	int pos;
+	int sgn;
+};
+
+/* Maps dst positions to src positions */
+struct isl_dim_map {
+	unsigned len;
+	struct isl_dim_map_entry m[1];
+};
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len)
+{
+	int i;
+	struct isl_dim_map *dim_map;
+	dim_map = isl_alloc(ctx, struct isl_dim_map,
+	    sizeof(struct isl_dim_map) + len * sizeof(struct isl_dim_map_entry));
+	if (!dim_map)
+		return NULL;
+	dim_map->len = 1 + len;
+	dim_map->m[0].pos = 0;
+	dim_map->m[0].sgn = 1;
+	for (i = 0; i < len; ++i)
+		dim_map->m[1 + i].sgn = 0;
+	return dim_map;
+}
+
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+	unsigned dst_pos, unsigned dst_stride,
+	unsigned src_pos, unsigned src_stride,
+	unsigned n, int sign)
+{
+	int i;
+
+	if (!dim_map)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		unsigned d = 1 + dst_pos + dst_stride * i;
+		unsigned s = 1 + src_pos + src_stride * i;
+		dim_map->m[d].pos = s;
+		dim_map->m[d].sgn = sign;
+	}
+}
+
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, unsigned dst_pos)
+{
+	int i;
+	unsigned src_pos;
+
+	if (!dim_map || !dim)
+		return;
+	
+	src_pos = 1 + isl_space_offset(dim, type);
+	for (i = 0; i < n; ++i) {
+		dim_map->m[1 + dst_pos + i].pos = src_pos + first + i;
+		dim_map->m[1 + dst_pos + i].sgn = 1;
+	}
+}
+
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned dst_pos)
+{
+	isl_dim_map_dim_range(dim_map, dim, type,
+			      0, isl_space_dim(dim, type), dst_pos);
+}
+
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap, unsigned dst_pos)
+{
+	int i;
+	unsigned src_pos;
+
+	if (!dim_map || !bmap)
+		return;
+	
+	src_pos = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+	for (i = 0; i < bmap->n_div; ++i) {
+		dim_map->m[1 + dst_pos + i].pos = src_pos + i;
+		dim_map->m[1 + dst_pos + i].sgn = 1;
+	}
+}
+
+void isl_dim_map_dump(struct isl_dim_map *dim_map)
+{
+	int i;
+
+	for (i = 0; i < dim_map->len; ++i)
+		fprintf(stderr, "%d -> %d * %d; ", i,
+			dim_map->m[i].sgn, dim_map->m[i].pos);
+	fprintf(stderr, "\n");
+}
+
+static void copy_constraint_dim_map(isl_int *dst, isl_int *src,
+					struct isl_dim_map *dim_map)
+{
+	int i;
+
+	for (i = 0; i < dim_map->len; ++i) {
+		if (dim_map->m[i].sgn == 0)
+			isl_int_set_si(dst[i], 0);
+		else if (dim_map->m[i].sgn > 0)
+			isl_int_set(dst[i], src[dim_map->m[i].pos]);
+		else
+			isl_int_neg(dst[i], src[dim_map->m[i].pos]);
+	}
+}
+
+static void copy_div_dim_map(isl_int *dst, isl_int *src,
+					struct isl_dim_map *dim_map)
+{
+	isl_int_set(dst[0], src[0]);
+	copy_constraint_dim_map(dst+1, src+1, dim_map);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+	__isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+	__isl_take isl_dim_map *dim_map)
+{
+	int i;
+
+	if (!src || !dst || !dim_map)
+		goto error;
+
+	for (i = 0; i < src->n_eq; ++i) {
+		int i1 = isl_basic_map_alloc_equality(dst);
+		if (i1 < 0)
+			goto error;
+		copy_constraint_dim_map(dst->eq[i1], src->eq[i], dim_map);
+	}
+
+	for (i = 0; i < src->n_ineq; ++i) {
+		int i1 = isl_basic_map_alloc_inequality(dst);
+		if (i1 < 0)
+			goto error;
+		copy_constraint_dim_map(dst->ineq[i1], src->ineq[i], dim_map);
+	}
+
+	for (i = 0; i < src->n_div; ++i) {
+		int i1 = isl_basic_map_alloc_div(dst);
+		if (i1 < 0)
+			goto error;
+		copy_div_dim_map(dst->div[i1], src->div[i], dim_map);
+	}
+
+	free(dim_map);
+	isl_basic_map_free(src);
+
+	return dst;
+error:
+	free(dim_map);
+	isl_basic_map_free(src);
+	isl_basic_map_free(dst);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+	__isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+	__isl_take isl_dim_map *dim_map)
+{
+	return isl_basic_map_add_constraints_dim_map(dst, src, dim_map);
+}
+
+/* Extend the given dim_map with mappings for the divs in bmap.
+ */
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	struct isl_dim_map *res;
+	int offset;
+
+	offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	res = isl_dim_map_alloc(bmap->ctx, dim_map->len - 1 + bmap->n_div);
+	if (!res)
+		return NULL;
+
+	for (i = 0; i < dim_map->len; ++i)
+		res->m[i] = dim_map->m[i];
+	for (i = 0; i < bmap->n_div; ++i) {
+		res->m[dim_map->len + i].pos = offset + i;
+		res->m[dim_map->len + i].sgn = 1;
+	}
+
+	return res;
+}
+
+/* Extract a dim_map from a reordering.
+ * We essentially need to reverse the mapping, and add an offset
+ * of 1 for the constant term.
+ */
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+	__isl_keep isl_reordering *exp)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_dim_map *dim_map;
+
+	if (!exp)
+		return NULL;
+
+	ctx = isl_space_get_ctx(exp->dim);
+	dim_map = isl_dim_map_alloc(ctx, isl_space_dim(exp->dim, isl_dim_all));
+	if (!dim_map)
+		return NULL;
+
+	for (i = 0; i < exp->len; ++i) {
+		dim_map->m[1 + exp->pos[i]].pos = 1 + i;
+		dim_map->m[1 + exp->pos[i]].sgn = 1;
+	}
+
+	return dim_map;
+}

Added: polly/trunk/lib/External/isl/isl_dim_map.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim_map.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim_map.h (added)
+++ polly/trunk/lib/External/isl/isl_dim_map.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,36 @@
+#ifndef ISL_DIM_MAP_H
+#define ISL_DIM_MAP_H
+
+#include <isl/ctx.h>
+#include <isl/space.h>
+#include <isl/map.h>
+
+struct isl_dim_map;
+typedef struct isl_dim_map isl_dim_map;
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len);
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+	unsigned dst_pos, unsigned dst_stride,
+	unsigned src_pos, unsigned src_stride,
+	unsigned n, int sign);
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+	isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, unsigned dst_pos);
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned dst_pos);
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap, unsigned dst_pos);
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+	__isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+	__isl_take isl_dim_map *dim_map);
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+	__isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+	__isl_take isl_dim_map *dim_map);
+
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+	__isl_keep isl_reordering *exp);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_equalities.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_equalities.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_equalities.c (added)
+++ polly/trunk/lib/External/isl/isl_equalities.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,782 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+#include "isl_map_private.h"
+#include "isl_equalities.h"
+#include <isl_val_private.h>
+
+/* Given a set of modulo constraints
+ *
+ *		c + A y = 0 mod d
+ *
+ * this function computes a particular solution y_0
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ *
+ * The output is matrix containing the solution y_0 or
+ * a zero-column matrix if the constraints admit no integer solution.
+ *
+ * The given set of constrains is equivalent to
+ *
+ *		c + A y = -D x
+ *
+ * with D = diag d and x a fresh set of variables.
+ * Reducing both c and A modulo d does not change the
+ * value of y in the solution and may lead to smaller coefficients.
+ * Let M = [ D A ] and [ H 0 ] = M U, the Hermite normal form of M.
+ * Then
+ *		  [ x ]
+ *		M [ y ] = - c
+ * and so
+ *		               [ x ]
+ *		[ H 0 ] U^{-1} [ y ] = - c
+ * Let
+ *		[ A ]          [ x ]
+ *		[ B ] = U^{-1} [ y ]
+ * then
+ *		H A + 0 B = -c
+ *
+ * so B may be chosen arbitrarily, e.g., B = 0, and then
+ *
+ *		       [ x ] = [ -c ]
+ *		U^{-1} [ y ] = [  0 ]
+ * or
+ *		[ x ]     [ -c ]
+ *		[ y ] = U [  0 ]
+ * specifically,
+ *
+ *		y = U_{2,1} (-c)
+ *
+ * If any of the coordinates of this y are non-integer
+ * then the constraints admit no integer solution and
+ * a zero-column matrix is returned.
+ */
+static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d)
+{
+	int i, j;
+	struct isl_mat *M = NULL;
+	struct isl_mat *C = NULL;
+	struct isl_mat *U = NULL;
+	struct isl_mat *H = NULL;
+	struct isl_mat *cst = NULL;
+	struct isl_mat *T = NULL;
+
+	M = isl_mat_alloc(B->ctx, B->n_row, B->n_row + B->n_col - 1);
+	C = isl_mat_alloc(B->ctx, 1 + B->n_row, 1);
+	if (!M || !C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_clr(M->row[i], B->n_row);
+		isl_int_set(M->row[i][i], d->block.data[i]);
+		isl_int_neg(C->row[1 + i][0], B->row[i][0]);
+		isl_int_fdiv_r(C->row[1+i][0], C->row[1+i][0], M->row[i][i]);
+		for (j = 0; j < B->n_col - 1; ++j)
+			isl_int_fdiv_r(M->row[i][B->n_row + j],
+					B->row[i][1 + j], M->row[i][i]);
+	}
+	M = isl_mat_left_hermite(M, 0, &U, NULL);
+	if (!M || !U)
+		goto error;
+	H = isl_mat_sub_alloc(M, 0, B->n_row, 0, B->n_row);
+	H = isl_mat_lin_to_aff(H);
+	C = isl_mat_inverse_product(H, C);
+	if (!C)
+		goto error;
+	for (i = 0; i < B->n_row; ++i) {
+		if (!isl_int_is_divisible_by(C->row[1+i][0], C->row[0][0]))
+			break;
+		isl_int_divexact(C->row[1+i][0], C->row[1+i][0], C->row[0][0]);
+	}
+	if (i < B->n_row)
+		cst = isl_mat_alloc(B->ctx, B->n_row, 0);
+	else
+		cst = isl_mat_sub_alloc(C, 1, B->n_row, 0, 1);
+	T = isl_mat_sub_alloc(U, B->n_row, B->n_col - 1, 0, B->n_row);
+	cst = isl_mat_product(T, cst);
+	isl_mat_free(M);
+	isl_mat_free(C);
+	isl_mat_free(U);
+	return cst;
+error:
+	isl_mat_free(M);
+	isl_mat_free(C);
+	isl_mat_free(U);
+	return NULL;
+}
+
+/* Compute and return the matrix
+ *
+ *		U_1^{-1} diag(d_1, 1, ..., 1)
+ *
+ * with U_1 the unimodular completion of the first (and only) row of B.
+ * The columns of this matrix generate the lattice that satisfies
+ * the single (linear) modulo constraint.
+ */
+static struct isl_mat *parameter_compression_1(
+			struct isl_mat *B, struct isl_vec *d)
+{
+	struct isl_mat *U;
+
+	U = isl_mat_alloc(B->ctx, B->n_col - 1, B->n_col - 1);
+	if (!U)
+		return NULL;
+	isl_seq_cpy(U->row[0], B->row[0] + 1, B->n_col - 1);
+	U = isl_mat_unimodular_complete(U, 1);
+	U = isl_mat_right_inverse(U);
+	if (!U)
+		return NULL;
+	isl_mat_col_mul(U, 0, d->block.data[0], 0);
+	U = isl_mat_lin_to_aff(U);
+	return U;
+}
+
+/* Compute a common lattice of solutions to the linear modulo
+ * constraints specified by B and d.
+ * See also the documentation of isl_mat_parameter_compression.
+ * We put the matrix
+ * 
+ *		A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * on a common denominator.  This denominator D is the lcm of modulos d.
+ * Since L_i = U_i^{-1} diag(d_i, 1, ... 1), we have
+ * L_i^{-T} = U_i^T diag(d_i, 1, ... 1)^{-T} = U_i^T diag(1/d_i, 1, ..., 1).
+ * Putting this on the common denominator, we have
+ * D * L_i^{-T} = U_i^T diag(D/d_i, D, ..., D).
+ */
+static struct isl_mat *parameter_compression_multi(
+			struct isl_mat *B, struct isl_vec *d)
+{
+	int i, j, k;
+	isl_int D;
+	struct isl_mat *A = NULL, *U = NULL;
+	struct isl_mat *T;
+	unsigned size;
+
+	isl_int_init(D);
+
+	isl_vec_lcm(d, &D);
+
+	size = B->n_col - 1;
+	A = isl_mat_alloc(B->ctx, size, B->n_row * size);
+	U = isl_mat_alloc(B->ctx, size, size);
+	if (!U || !A)
+		goto error;
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_cpy(U->row[0], B->row[i] + 1, size);
+		U = isl_mat_unimodular_complete(U, 1);
+		if (!U)
+			goto error;
+		isl_int_divexact(D, D, d->block.data[i]);
+		for (k = 0; k < U->n_col; ++k)
+			isl_int_mul(A->row[k][i*size+0], D, U->row[0][k]);
+		isl_int_mul(D, D, d->block.data[i]);
+		for (j = 1; j < U->n_row; ++j)
+			for (k = 0; k < U->n_col; ++k)
+				isl_int_mul(A->row[k][i*size+j],
+						D, U->row[j][k]);
+	}
+	A = isl_mat_left_hermite(A, 0, NULL, NULL);
+	T = isl_mat_sub_alloc(A, 0, A->n_row, 0, A->n_row);
+	T = isl_mat_lin_to_aff(T);
+	if (!T)
+		goto error;
+	isl_int_set(T->row[0][0], D);
+	T = isl_mat_right_inverse(T);
+	if (!T)
+		goto error;
+	isl_assert(T->ctx, isl_int_is_one(T->row[0][0]), goto error);
+	T = isl_mat_transpose(T);
+	isl_mat_free(A);
+	isl_mat_free(U);
+
+	isl_int_clear(D);
+	return T;
+error:
+	isl_mat_free(A);
+	isl_mat_free(U);
+	isl_int_clear(D);
+	return NULL;
+}
+
+/* Given a set of modulo constraints
+ *
+ *		c + A y = 0 mod d
+ *
+ * this function returns an affine transformation T,
+ *
+ *		y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints.
+ *
+ * This function is inspired by Section 2.5.3
+ * of B. Meister, "Stating and Manipulating Periodicity in the Polytope
+ * Model.  Applications to Program Analysis and Optimization".
+ * However, the implementation only follows the algorithm of that
+ * section for computing a particular solution and not for computing
+ * a general homogeneous solution.  The latter is incomplete and
+ * may remove some valid solutions.
+ * Instead, we use an adaptation of the algorithm in Section 7 of
+ * B. Meister, S. Verdoolaege, "Polynomial Approximations in the Polytope
+ * Model: Bringing the Power of Quasi-Polynomials to the Masses".
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ * Each element of the vector d corresponds to a row in B.
+ * The output is a lower triangular matrix.
+ * If no integer vector y satisfies the given constraints then
+ * a matrix with zero columns is returned.
+ *
+ * We first compute a particular solution y_0 to the given set of
+ * modulo constraints in particular_solution.  If no such solution
+ * exists, then we return a zero-columned transformation matrix.
+ * Otherwise, we compute the generic solution to
+ *
+ *		A y = 0 mod d
+ *
+ * That is we want to compute G such that
+ *
+ *		y = G y''
+ *
+ * with y'' integer, describes the set of solutions.
+ *
+ * We first remove the common factors of each row.
+ * In particular if gcd(A_i,d_i) != 1, then we divide the whole
+ * row i (including d_i) by this common factor.  If afterwards gcd(A_i) != 1,
+ * then we divide this row of A by the common factor, unless gcd(A_i) = 0.
+ * In the later case, we simply drop the row (in both A and d).
+ *
+ * If there are no rows left in A, then G is the identity matrix. Otherwise,
+ * for each row i, we now determine the lattice of integer vectors
+ * that satisfies this row.  Let U_i be the unimodular extension of the
+ * row A_i.  This unimodular extension exists because gcd(A_i) = 1.
+ * The first component of
+ *
+ *		y' = U_i y
+ *
+ * needs to be a multiple of d_i.  Let y' = diag(d_i, 1, ..., 1) y''.
+ * Then,
+ *
+ *		y = U_i^{-1} diag(d_i, 1, ..., 1) y''
+ *
+ * for arbitrary integer vectors y''.  That is, y belongs to the lattice
+ * generated by the columns of L_i = U_i^{-1} diag(d_i, 1, ..., 1).
+ * If there is only one row, then G = L_1.
+ *
+ * If there is more than one row left, we need to compute the intersection
+ * of the lattices.  That is, we need to compute an L such that
+ *
+ *		L = L_i L_i'	for all i
+ *
+ * with L_i' some integer matrices.  Let A be constructed as follows
+ *
+ *		A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * and computed the Hermite Normal Form of A = [ H 0 ] U
+ * Then,
+ *
+ *		L_i^{-T} = H U_{1,i}
+ *
+ * or
+ *
+ *		H^{-T} = L_i U_{1,i}^T
+ *
+ * In other words G = L = H^{-T}.
+ * To ensure that G is lower triangular, we compute and use its Hermite
+ * normal form.
+ *
+ * The affine transformation matrix returned is then
+ *
+ *		[  1   0  ]
+ *		[ y_0  G  ]
+ *
+ * as any y = y_0 + G y' with y' integer is a solution to the original
+ * modulo constraints.
+ */
+struct isl_mat *isl_mat_parameter_compression(
+			struct isl_mat *B, struct isl_vec *d)
+{
+	int i;
+	struct isl_mat *cst = NULL;
+	struct isl_mat *T = NULL;
+	isl_int D;
+
+	if (!B || !d)
+		goto error;
+	isl_assert(B->ctx, B->n_row == d->size, goto error);
+	cst = particular_solution(B, d);
+	if (!cst)
+		goto error;
+	if (cst->n_col == 0) {
+		T = isl_mat_alloc(B->ctx, B->n_col, 0);
+		isl_mat_free(cst);
+		isl_mat_free(B);
+		isl_vec_free(d);
+		return T;
+	}
+	isl_int_init(D);
+	/* Replace a*g*row = 0 mod g*m by row = 0 mod m */
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_gcd(B->row[i] + 1, B->n_col - 1, &D);
+		if (isl_int_is_one(D))
+			continue;
+		if (isl_int_is_zero(D)) {
+			B = isl_mat_drop_rows(B, i, 1);
+			d = isl_vec_cow(d);
+			if (!B || !d)
+				goto error2;
+			isl_seq_cpy(d->block.data+i, d->block.data+i+1,
+							d->size - (i+1));
+			d->size--;
+			i--;
+			continue;
+		}
+		B = isl_mat_cow(B);
+		if (!B)
+			goto error2;
+		isl_seq_scale_down(B->row[i] + 1, B->row[i] + 1, D, B->n_col-1);
+		isl_int_gcd(D, D, d->block.data[i]);
+		d = isl_vec_cow(d);
+		if (!d)
+			goto error2;
+		isl_int_divexact(d->block.data[i], d->block.data[i], D);
+	}
+	isl_int_clear(D);
+	if (B->n_row == 0)
+		T = isl_mat_identity(B->ctx, B->n_col);
+	else if (B->n_row == 1)
+		T = parameter_compression_1(B, d);
+	else
+		T = parameter_compression_multi(B, d);
+	T = isl_mat_left_hermite(T, 0, NULL, NULL);
+	if (!T)
+		goto error;
+	isl_mat_sub_copy(T->ctx, T->row + 1, cst->row, cst->n_row, 0, 0, 1);
+	isl_mat_free(cst);
+	isl_mat_free(B);
+	isl_vec_free(d);
+	return T;
+error2:
+	isl_int_clear(D);
+error:
+	isl_mat_free(cst);
+	isl_mat_free(B);
+	isl_vec_free(d);
+	return NULL;
+}
+
+/* Given a set of equalities
+ *
+ *		B(y) + A x = 0						(*)
+ *
+ * compute and return an affine transformation T,
+ *
+ *		y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints for some value of x.
+ *
+ * Let [H 0] be the Hermite Normal Form of A, i.e.,
+ *
+ *		A = [H 0] Q
+ *
+ * Then y is a solution of (*) iff
+ *
+ *		H^-1 B(y) (= - [I 0] Q x)
+ *
+ * is an integer vector.  Let d be the common denominator of H^-1.
+ * We impose
+ *
+ *		d H^-1 B(y) = 0 mod d
+ *
+ * and compute the solution using isl_mat_parameter_compression.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+	__isl_take isl_mat *A)
+{
+	isl_ctx *ctx;
+	isl_vec *d;
+	int n_row, n_col;
+
+	if (!A)
+		return isl_mat_free(B);
+
+	ctx = isl_mat_get_ctx(A);
+	n_row = A->n_row;
+	n_col = A->n_col;
+	A = isl_mat_left_hermite(A, 0, NULL, NULL);
+	A = isl_mat_drop_cols(A, n_row, n_col - n_row);
+	A = isl_mat_lin_to_aff(A);
+	A = isl_mat_right_inverse(A);
+	d = isl_vec_alloc(ctx, n_row);
+	if (A)
+		d = isl_vec_set(d, A->row[0][0]);
+	A = isl_mat_drop_rows(A, 0, 1);
+	A = isl_mat_drop_cols(A, 0, 1);
+	B = isl_mat_product(A, B);
+
+	return isl_mat_parameter_compression(B, d);
+}
+
+/* Given a set of equalities
+ *
+ *		M x - c = 0
+ *
+ * this function computes a unimodular transformation from a lower-dimensional
+ * space to the original space that bijectively maps the integer points x'
+ * in the lower-dimensional space to the integer points x in the original
+ * space that satisfy the equalities.
+ *
+ * The input is given as a matrix B = [ -c M ] and the output is a
+ * matrix that maps [1 x'] to [1 x].
+ * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x'].
+ *
+ * First compute the (left) Hermite normal form of M,
+ *
+ *		M [U1 U2] = M U = H = [H1 0]
+ * or
+ *		              M = H Q = [H1 0] [Q1]
+ *                                             [Q2]
+ *
+ * with U, Q unimodular, Q = U^{-1} (and H lower triangular).
+ * Define the transformed variables as
+ *
+ *		x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x
+ *		            [ x2' ]           [Q2]
+ *
+ * The equalities then become
+ *
+ *		H1 x1' - c = 0   or   x1' = H1^{-1} c = c'
+ *
+ * If any of the c' is non-integer, then the original set has no
+ * integer solutions (since the x' are a unimodular transformation
+ * of the x) and a zero-column matrix is returned.
+ * Otherwise, the transformation is given by
+ *
+ *		x = U1 H1^{-1} c + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *		x2' = Q2 x
+ */
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2)
+{
+	int i;
+	struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
+	unsigned dim;
+
+	if (T2)
+		*T2 = NULL;
+	if (!B)
+		goto error;
+
+	dim = B->n_col - 1;
+	H = isl_mat_sub_alloc(B, 0, B->n_row, 1, dim);
+	H = isl_mat_left_hermite(H, 0, &U, T2);
+	if (!H || !U || (T2 && !*T2))
+		goto error;
+	if (T2) {
+		*T2 = isl_mat_drop_rows(*T2, 0, B->n_row);
+		*T2 = isl_mat_lin_to_aff(*T2);
+		if (!*T2)
+			goto error;
+	}
+	C = isl_mat_alloc(B->ctx, 1+B->n_row, 1);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_mat_sub_neg(C->ctx, C->row+1, B->row, B->n_row, 0, 0, 1);
+	H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+	H1 = isl_mat_lin_to_aff(H1);
+	TC = isl_mat_inverse_product(H1, C);
+	if (!TC)
+		goto error;
+	isl_mat_free(H);
+	if (!isl_int_is_one(TC->row[0][0])) {
+		for (i = 0; i < B->n_row; ++i) {
+			if (!isl_int_is_divisible_by(TC->row[1+i][0], TC->row[0][0])) {
+				struct isl_ctx *ctx = B->ctx;
+				isl_mat_free(B);
+				isl_mat_free(TC);
+				isl_mat_free(U);
+				if (T2) {
+					isl_mat_free(*T2);
+					*T2 = NULL;
+				}
+				return isl_mat_alloc(ctx, 1 + dim, 0);
+			}
+			isl_seq_scale_down(TC->row[1+i], TC->row[1+i], TC->row[0][0], 1);
+		}
+		isl_int_set_si(TC->row[0][0], 1);
+	}
+	U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, B->n_row);
+	U1 = isl_mat_lin_to_aff(U1);
+	U2 = isl_mat_sub_alloc(U, 0, U->n_row, B->n_row, U->n_row - B->n_row);
+	U2 = isl_mat_lin_to_aff(U2);
+	isl_mat_free(U);
+	TC = isl_mat_product(U1, TC);
+	TC = isl_mat_aff_direct_sum(TC, U2);
+
+	isl_mat_free(B);
+
+	return TC;
+error:
+	isl_mat_free(B);
+	isl_mat_free(H);
+	isl_mat_free(U);
+	if (T2) {
+		isl_mat_free(*T2);
+		*T2 = NULL;
+	}
+	return NULL;
+}
+
+/* Use the n equalities of bset to unimodularly transform the
+ * variables x such that n transformed variables x1' have a constant value
+ * and rewrite the constraints of bset in terms of the remaining
+ * transformed variables x2'.  The matrix pointed to by T maps
+ * the new variables x2' back to the original variables x, while T2
+ * maps the original variables to the new variables.
+ */
+static struct isl_basic_set *compress_variables(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+	struct isl_mat *B, *TC;
+	unsigned dim;
+
+	if (T)
+		*T = NULL;
+	if (T2)
+		*T2 = NULL;
+	if (!bset)
+		goto error;
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_n_dim(bset);
+	isl_assert(bset->ctx, bset->n_eq <= dim, goto error);
+	if (bset->n_eq == 0)
+		return bset;
+
+	B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
+	TC = isl_mat_variable_compression(B, T2);
+	if (!TC)
+		goto error;
+	if (TC->n_col == 0) {
+		isl_mat_free(TC);
+		if (T2) {
+			isl_mat_free(*T2);
+			*T2 = NULL;
+		}
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	bset = isl_basic_set_preimage(bset, T ? isl_mat_copy(TC) : TC);
+	if (T)
+		*T = TC;
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_remove_equalities(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+	if (T)
+		*T = NULL;
+	if (T2)
+		*T2 = NULL;
+	if (!bset)
+		return NULL;
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	bset = isl_basic_set_gauss(bset, NULL);
+	if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+		return bset;
+	bset = compress_variables(bset, T, T2);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	*T = NULL;
+	return NULL;
+}
+
+/* Check if dimension dim belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	struct isl_ctx *ctx;
+	struct isl_mat *H = NULL, *U = NULL, *C, *H1, *U1;
+	unsigned total;
+	unsigned nparam;
+
+	if (!bset || !modulo || !residue)
+		return -1;
+
+	if (isl_basic_set_plain_dim_is_fixed(bset, pos, residue)) {
+		isl_int_set_si(*modulo, 0);
+		return 0;
+	}
+
+	ctx = bset->ctx;
+	total = isl_basic_set_total_dim(bset);
+	nparam = isl_basic_set_n_param(bset);
+	H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
+	H = isl_mat_left_hermite(H, 0, &U, NULL);
+	if (!H)
+		return -1;
+
+	isl_seq_gcd(U->row[nparam + pos]+bset->n_eq,
+			total-bset->n_eq, modulo);
+	if (isl_int_is_zero(*modulo))
+		isl_int_set_si(*modulo, 1);
+	if (isl_int_is_one(*modulo)) {
+		isl_int_set_si(*residue, 0);
+		isl_mat_free(H);
+		isl_mat_free(U);
+		return 0;
+	}
+
+	C = isl_mat_alloc(bset->ctx, 1+bset->n_eq, 1);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_mat_sub_neg(C->ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
+	H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+	H1 = isl_mat_lin_to_aff(H1);
+	C = isl_mat_inverse_product(H1, C);
+	isl_mat_free(H);
+	U1 = isl_mat_sub_alloc(U, nparam+pos, 1, 0, bset->n_eq);
+	U1 = isl_mat_lin_to_aff(U1);
+	isl_mat_free(U);
+	C = isl_mat_product(U1, C);
+	if (!C)
+		return -1;
+	if (!isl_int_is_divisible_by(C->row[1][0], C->row[0][0])) {
+		bset = isl_basic_set_copy(bset);
+		bset = isl_basic_set_set_to_empty(bset);
+		isl_basic_set_free(bset);
+		isl_int_set_si(*modulo, 1);
+		isl_int_set_si(*residue, 0);
+		return 0;
+	}
+	isl_int_divexact(*residue, C->row[1][0], C->row[0][0]);
+	isl_int_fdiv_r(*residue, *residue, *modulo);
+	isl_mat_free(C);
+	return 0;
+error:
+	isl_mat_free(H);
+	isl_mat_free(U);
+	return -1;
+}
+
+/* Check if dimension dim belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class(struct isl_set *set,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	isl_int m;
+	isl_int r;
+	int i;
+
+	if (!set || !modulo || !residue)
+		return -1;
+
+	if (set->n == 0) {
+		isl_int_set_si(*modulo, 0);
+		isl_int_set_si(*residue, 0);
+		return 0;
+	}
+
+	if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0)
+		return -1;
+
+	if (set->n == 1)
+		return 0;
+
+	if (isl_int_is_one(*modulo))
+		return 0;
+
+	isl_int_init(m);
+	isl_int_init(r);
+
+	for (i = 1; i < set->n; ++i) {
+		if (isl_basic_set_dim_residue_class(set->p[i], pos, &m, &r) < 0)
+			goto error;
+		isl_int_gcd(*modulo, *modulo, m);
+		isl_int_sub(m, *residue, r);
+		isl_int_gcd(*modulo, *modulo, m);
+		if (!isl_int_is_zero(*modulo))
+			isl_int_fdiv_r(*residue, *residue, *modulo);
+		if (isl_int_is_one(*modulo))
+			break;
+	}
+
+	isl_int_clear(m);
+	isl_int_clear(r);
+
+	return 0;
+error:
+	isl_int_clear(m);
+	isl_int_clear(r);
+	return -1;
+}
+
+/* Check if dimension "dim" belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class_val(__isl_keep isl_set *set,
+	int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue)
+{
+	*modulo = NULL;
+	*residue = NULL;
+	if (!set)
+		return -1;
+	*modulo = isl_val_alloc(isl_set_get_ctx(set));
+	*residue = isl_val_alloc(isl_set_get_ctx(set));
+	if (!*modulo || !*residue)
+		goto error;
+	if (isl_set_dim_residue_class(set, pos,
+					&(*modulo)->n, &(*residue)->n) < 0)
+		goto error;
+	isl_int_set_si((*modulo)->d, 1);
+	isl_int_set_si((*residue)->d, 1);
+	return 0;
+error:
+	isl_val_free(*modulo);
+	isl_val_free(*residue);
+	return -1;
+}

Added: polly/trunk/lib/External/isl/isl_equalities.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_equalities.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_equalities.h (added)
+++ polly/trunk/lib/External/isl/isl_equalities.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_EQUALITIES_H
+#define ISL_EQUALITIES_H
+
+#include <isl/set.h>
+#include <isl/mat.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2);
+struct isl_mat *isl_mat_parameter_compression(
+			struct isl_mat *B, struct isl_vec *d);
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+	__isl_take isl_mat *A);
+struct isl_basic_set *isl_basic_set_remove_equalities(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

Added: polly/trunk/lib/External/isl/isl_factorization.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_factorization.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_factorization.c (added)
+++ polly/trunk/lib/External/isl/isl_factorization.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_factorization.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+
+static __isl_give isl_factorizer *isl_factorizer_alloc(
+	__isl_take isl_morph *morph, int n_group)
+{
+	isl_factorizer *f = NULL;
+	int *len = NULL;
+
+	if (!morph)
+		return NULL;
+
+	if (n_group > 0) {
+		len = isl_alloc_array(morph->dom->ctx, int, n_group);
+		if (!len)
+			goto error;
+	}
+
+	f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer);
+	if (!f)
+		goto error;
+
+	f->morph = morph;
+	f->n_group = n_group;
+	f->len = len;
+
+	return f;
+error:
+	free(len);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+void isl_factorizer_free(__isl_take isl_factorizer *f)
+{
+	if (!f)
+		return;
+
+	isl_morph_free(f->morph);
+	free(f->len);
+	free(f);
+}
+
+void isl_factorizer_dump(__isl_take isl_factorizer *f)
+{
+	int i;
+
+	if (!f)
+		return;
+
+	isl_morph_print_internal(f->morph, stderr);
+	fprintf(stderr, "[");
+	for (i = 0; i < f->n_group; ++i) {
+		if (i)
+			fprintf(stderr, ", ");
+		fprintf(stderr, "%d", f->len[i]);
+	}
+	fprintf(stderr, "]\n");
+}
+
+__isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset)
+{
+	return isl_factorizer_alloc(isl_morph_identity(bset), 0);
+}
+
+__isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset,
+	__isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len)
+{
+	int i;
+	unsigned nvar;
+	unsigned ovar;
+	isl_space *dim;
+	isl_basic_set *dom;
+	isl_basic_set *ran;
+	isl_morph *morph;
+	isl_factorizer *f;
+	isl_mat *id;
+
+	if (!bset || !Q || !U)
+		goto error;
+
+	ovar = 1 + isl_space_offset(bset->dim, isl_dim_set);
+	id = isl_mat_identity(bset->ctx, ovar);
+	Q = isl_mat_diagonal(isl_mat_copy(id), Q);
+	U = isl_mat_diagonal(id, U);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	dim = isl_basic_set_get_space(bset);
+	dom = isl_basic_set_universe(isl_space_copy(dim));
+	dim = isl_space_drop_dims(dim, isl_dim_set, 0, nvar);
+	dim = isl_space_add_dims(dim, isl_dim_set, nvar);
+	ran = isl_basic_set_universe(dim);
+	morph = isl_morph_alloc(dom, ran, Q, U);
+	f = isl_factorizer_alloc(morph, n);
+	if (!f)
+		return NULL;
+	for (i = 0; i < n; ++i)
+		f->len[i] = len[i];
+	return f;
+error:
+	isl_mat_free(Q);
+	isl_mat_free(U);
+	return NULL;
+}
+
+struct isl_factor_groups {
+	int *pos;		/* for each column: row position of pivot */
+	int *group;		/* group to which a column belongs */
+	int *cnt;		/* number of columns in the group */
+	int *rowgroup;		/* group to which a constraint belongs */
+};
+
+/* Initialize isl_factor_groups structure: find pivot row positions,
+ * each column initially belongs to its own group and the groups
+ * of the constraints are still unknown.
+ */
+static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+	int i, j;
+
+	if (!H)
+		return -1;
+
+	g->pos = isl_alloc_array(H->ctx, int, H->n_col);
+	g->group = isl_alloc_array(H->ctx, int, H->n_col);
+	g->cnt = isl_alloc_array(H->ctx, int, H->n_col);
+	g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row);
+
+	if (!g->pos || !g->group || !g->cnt || !g->rowgroup)
+		return -1;
+
+	for (i = 0; i < H->n_row; ++i)
+		g->rowgroup[i] = -1;
+	for (i = 0, j = 0; i < H->n_col; ++i) {
+		for ( ; j < H->n_row; ++j)
+			if (!isl_int_is_zero(H->row[j][i]))
+				break;
+		g->pos[i] = j;
+	}
+	for (i = 0; i < H->n_col; ++i) {
+		g->group[i] = i;
+		g->cnt[i] = 1;
+	}
+
+	return 0;
+}
+
+/* Update group[k] to the group column k belongs to.
+ * When merging two groups, only the group of the current
+ * group leader is changed.  Here we change the group of
+ * the other members to also point to the group that the
+ * old group leader now points to.
+ */
+static void update_group(struct isl_factor_groups *g, int k)
+{
+	int p = g->group[k];
+	while (g->cnt[p] == 0)
+		p = g->group[p];
+	g->group[k] = p;
+}
+
+/* Merge group i with all groups of the subsequent columns
+ * with non-zero coefficients in row j of H.
+ * (The previous columns are all zero; otherwise we would have handled
+ * the row before.)
+ */
+static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j,
+	__isl_keep isl_mat *H)
+{
+	int k;
+
+	g->rowgroup[j] = g->group[i];
+	for (k = i + 1; k < H->n_col && j >= g->pos[k]; ++k) {
+		update_group(g, k);
+		update_group(g, i);
+		if (g->group[k] != g->group[i] &&
+		    !isl_int_is_zero(H->row[j][k])) {
+			isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1);
+			isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1);
+			if (g->group[i] < g->group[k]) {
+				g->cnt[g->group[i]] += g->cnt[g->group[k]];
+				g->cnt[g->group[k]] = 0;
+				g->group[g->group[k]] = g->group[i];
+			} else {
+				g->cnt[g->group[k]] += g->cnt[g->group[i]];
+				g->cnt[g->group[i]] = 0;
+				g->group[g->group[i]] = g->group[k];
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Update the group information based on the constraint matrix.
+ */
+static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+	int i, j;
+
+	for (i = 0; i < H->n_col && g->cnt[0] < H->n_col; ++i) {
+		if (g->pos[i] == H->n_row)
+			continue; /* A line direction */
+		if (g->rowgroup[g->pos[i]] == -1)
+			g->rowgroup[g->pos[i]] = i;
+		for (j = g->pos[i] + 1; j < H->n_row; ++j) {
+			if (isl_int_is_zero(H->row[j][i]))
+				continue;
+			if (g->rowgroup[j] != -1)
+				continue;
+			if (update_group_i_with_row_j(g, i, j, H) < 0)
+				return -1;
+		}
+	}
+	for (i = 1; i < H->n_col; ++i)
+		update_group(g, i);
+
+	return 0;
+}
+
+static void clear_groups(struct isl_factor_groups *g)
+{
+	if (!g)
+		return;
+	free(g->pos);
+	free(g->group);
+	free(g->cnt);
+	free(g->rowgroup);
+}
+
+/* Determine if the set variables of the basic set can be factorized and
+ * return the results in an isl_factorizer.
+ *
+ * The algorithm works by first computing the Hermite normal form
+ * and then grouping columns linked by one or more constraints together,
+ * where a constraints "links" two or more columns if the constraint
+ * has nonzero coefficients in the columns.
+ */
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+	__isl_keep isl_basic_set *bset)
+{
+	int i, j, n, done;
+	isl_mat *H, *U, *Q;
+	unsigned nvar;
+	struct isl_factor_groups g = { 0 };
+	isl_factorizer *f;
+
+	if (!bset)
+		return NULL;
+
+	isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0,
+		return NULL);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	if (nvar <= 1)
+		return isl_factorizer_identity(bset);
+
+	H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar);
+	if (!H)
+		return NULL;
+	isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq,
+		0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+	isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq,
+		0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+
+	if (init_groups(&g, H) < 0)
+		goto error;
+	if (update_groups(&g, H) < 0)
+		goto error;
+
+	if (g.cnt[0] == nvar) {
+		isl_mat_free(H);
+		isl_mat_free(U);
+		isl_mat_free(Q);
+		clear_groups(&g);
+
+		return isl_factorizer_identity(bset);
+	}
+
+	done = 0;
+	n = 0;
+	while (done != nvar) {
+		int group = g.group[done];
+		for (i = 1; i < g.cnt[group]; ++i) {
+			if (g.group[done + i] == group)
+				continue;
+			for (j = done + g.cnt[group]; j < nvar; ++j)
+				if (g.group[j] == group)
+					break;
+			if (j == nvar)
+				isl_die(bset->ctx, isl_error_internal,
+					"internal error", goto error);
+			g.group[j] = g.group[done + i];
+			Q = isl_mat_swap_rows(Q, done + i, j);
+			U = isl_mat_swap_cols(U, done + i, j);
+		}
+		done += g.cnt[group];
+		g.pos[n++] = g.cnt[group];
+	}
+
+	f = isl_factorizer_groups(bset, Q, U, n, g.pos);
+
+	isl_mat_free(H);
+	clear_groups(&g);
+
+	return f;
+error:
+	isl_mat_free(H);
+	isl_mat_free(U);
+	isl_mat_free(Q);
+	clear_groups(&g);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_factorization.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_factorization.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_factorization.h (added)
+++ polly/trunk/lib/External/isl/isl_factorization.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,29 @@
+#include <isl/set.h>
+#include <isl_morph.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Data for factorizing a particular basic set.
+ * After applying "morph" to the basic set, there are "n_group"
+ * groups of consecutive set variables, each of length "len[i]",
+ * with 0 <= i < n_group.
+ * If no factorization is possible, then "n_group" is set to 0.
+ */
+struct isl_factorizer {
+	isl_morph	*morph;
+	int		n_group;
+	int		*len;
+};
+typedef struct isl_factorizer isl_factorizer;
+
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+	__isl_keep isl_basic_set *bset);
+
+void isl_factorizer_free(__isl_take isl_factorizer *f);
+void isl_factorizer_dump(__isl_take isl_factorizer *f);
+
+#if defined(__cplusplus)
+}
+#endif

Added: polly/trunk/lib/External/isl/isl_farkas.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_farkas.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_farkas.c (added)
+++ polly/trunk/lib/External/isl/isl_farkas.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,403 @@
+/*
+ * 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_map_private.h>
+#include <isl/set.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+
+/*
+ * Let C be a cone and define
+ *
+ *	C' := { y | forall x in C : y x >= 0 }
+ *
+ * C' contains the coefficients of all linear constraints
+ * that are valid for C.
+ * Furthermore, C'' = C.
+ *
+ * If C is defined as { x | A x >= 0 }
+ * then any element in C' must be a non-negative combination
+ * of the rows of A, i.e., y = t A with t >= 0.  That is,
+ *
+ *	C' = { y | exists t >= 0 : y = t A }
+ *
+ * If any of the rows in A actually represents an equality, then
+ * also negative combinations of this row are allowed and so the
+ * non-negativity constraint on the corresponding element of t
+ * can be dropped.
+ *
+ * A polyhedron P = { x | b + A x >= 0 } can be represented
+ * in homogeneous coordinates by the cone
+ * C = { [z,x] | b z + A x >= and z >= 0 }
+ * The valid linear constraints on C correspond to the valid affine
+ * constraints on P.
+ * This is essentially Farkas' lemma.
+ *
+ * Since
+ *				  [ 1 0 ]
+ *		[ w y ] = [t_0 t] [ b A ]
+ *
+ * we have
+ *
+ *	C' = { w, y | exists t_0, t >= 0 : y = t A and w = t_0 + t b }
+ * or
+ *
+ *	C' = { w, y | exists t >= 0 : y = t A and w - t b >= 0 }
+ *
+ * In practice, we introduce an extra variable (w), shifting all
+ * other variables to the right, and an extra inequality
+ * (w - t b >= 0) corresponding to the positivity constraint on
+ * the homogeneous coordinate.
+ *
+ * When going back from coefficients to solutions, we immediately
+ * plug in 1 for z, which corresponds to shifting all variables
+ * to the left, with the leftmost ending up in the constant position.
+ */
+
+/* Add the given prefix to all named isl_dim_set dimensions in "dim".
+ */
+static __isl_give isl_space *isl_space_prefix(__isl_take isl_space *dim,
+	const char *prefix)
+{
+	int i;
+	isl_ctx *ctx;
+	unsigned nvar;
+	size_t prefix_len = strlen(prefix);
+
+	if (!dim)
+		return NULL;
+
+	ctx = isl_space_get_ctx(dim);
+	nvar = isl_space_dim(dim, isl_dim_set);
+
+	for (i = 0; i < nvar; ++i) {
+		const char *name;
+		char *prefix_name;
+
+		name = isl_space_get_dim_name(dim, isl_dim_set, i);
+		if (!name)
+			continue;
+
+		prefix_name = isl_alloc_array(ctx, char,
+					      prefix_len + strlen(name) + 1);
+		if (!prefix_name)
+			goto error;
+		memcpy(prefix_name, prefix, prefix_len);
+		strcpy(prefix_name + prefix_len, name);
+
+		dim = isl_space_set_dim_name(dim, isl_dim_set, i, prefix_name);
+		free(prefix_name);
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Given a dimension specification of the solutions space, construct
+ * a dimension specification for the space of coefficients.
+ *
+ * In particular transform
+ *
+ *	[params] -> { S }
+ *
+ * to
+ *
+ *	{ coefficients[[cst, params] -> S] }
+ *
+ * and prefix each dimension name with "c_".
+ */
+static __isl_give isl_space *isl_space_coefficients(__isl_take isl_space *dim)
+{
+	isl_space *dim_param;
+	unsigned nvar;
+	unsigned nparam;
+
+	nvar = isl_space_dim(dim, isl_dim_set);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	dim_param = isl_space_copy(dim);
+	dim_param = isl_space_drop_dims(dim_param, isl_dim_set, 0, nvar);
+	dim_param = isl_space_move_dims(dim_param, isl_dim_set, 0,
+				 isl_dim_param, 0, nparam);
+	dim_param = isl_space_prefix(dim_param, "c_");
+	dim_param = isl_space_insert_dims(dim_param, isl_dim_set, 0, 1);
+	dim_param = isl_space_set_dim_name(dim_param, isl_dim_set, 0, "c_cst");
+	dim = isl_space_drop_dims(dim, isl_dim_param, 0, nparam);
+	dim = isl_space_prefix(dim, "c_");
+	dim = isl_space_join(isl_space_from_domain(dim_param),
+			   isl_space_from_range(dim));
+	dim = isl_space_wrap(dim);
+	dim = isl_space_set_tuple_name(dim, isl_dim_set, "coefficients");
+
+	return dim;
+}
+
+/* Drop the given prefix from all named dimensions of type "type" in "dim".
+ */
+static __isl_give isl_space *isl_space_unprefix(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *prefix)
+{
+	int i;
+	unsigned n;
+	size_t prefix_len = strlen(prefix);
+
+	n = isl_space_dim(dim, type);
+
+	for (i = 0; i < n; ++i) {
+		const char *name;
+
+		name = isl_space_get_dim_name(dim, type, i);
+		if (!name)
+			continue;
+		if (strncmp(name, prefix, prefix_len))
+			continue;
+
+		dim = isl_space_set_dim_name(dim, type, i, name + prefix_len);
+	}
+
+	return dim;
+}
+
+/* Given a dimension specification of the space of coefficients, construct
+ * a dimension specification for the space of solutions.
+ *
+ * In particular transform
+ *
+ *	{ coefficients[[cst, params] -> S] }
+ *
+ * to
+ *
+ *	[params] -> { S }
+ *
+ * and drop the "c_" prefix from the dimension names.
+ */
+static __isl_give isl_space *isl_space_solutions(__isl_take isl_space *dim)
+{
+	unsigned nparam;
+
+	dim = isl_space_unwrap(dim);
+	dim = isl_space_drop_dims(dim, isl_dim_in, 0, 1);
+	dim = isl_space_unprefix(dim, isl_dim_in, "c_");
+	dim = isl_space_unprefix(dim, isl_dim_out, "c_");
+	nparam = isl_space_dim(dim, isl_dim_in);
+	dim = isl_space_move_dims(dim, isl_dim_param, 0, isl_dim_in, 0, nparam);
+	dim = isl_space_range(dim);
+
+	return dim;
+}
+
+/* Return the rational universe basic set in the given space.
+ */
+static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space)
+{
+	isl_basic_set *bset;
+
+	bset = isl_basic_set_universe(space);
+	bset = isl_basic_set_set_rational(bset);
+
+	return bset;
+}
+
+/* Compute the dual of "bset" by applying Farkas' lemma.
+ * As explained above, we add an extra dimension to represent
+ * the coefficient of the constant term when going from solutions
+ * to coefficients (shift == 1) and we drop the extra dimension when going
+ * in the opposite direction (shift == -1).  "dim" is the space in which
+ * the dual should be created.
+ *
+ * If "bset" is (obviously) empty, then the way this emptiness
+ * is represented by the constraints does not allow for the application
+ * of the standard farkas algorithm.  We therefore handle this case
+ * specifically and return the universe basic set.
+ */
+static __isl_give isl_basic_set *farkas(__isl_take isl_space *space,
+	__isl_take isl_basic_set *bset, int shift)
+{
+	int i, j, k;
+	isl_basic_set *dual = NULL;
+	unsigned total;
+
+	if (isl_basic_set_plain_is_empty(bset)) {
+		isl_basic_set_free(bset);
+		return rational_universe(space);
+	}
+
+	total = isl_basic_set_total_dim(bset);
+
+	dual = isl_basic_set_alloc_space(space, bset->n_eq + bset->n_ineq,
+					total, bset->n_ineq + (shift > 0));
+	dual = isl_basic_set_set_rational(dual);
+
+	for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_div(dual);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(dual->div[k][0], 0);
+	}
+
+	for (i = 0; i < total; ++i) {
+		k = isl_basic_set_alloc_equality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->eq[k], 1 + shift + total);
+		isl_int_set_si(dual->eq[k][1 + shift + i], -1);
+		for (j = 0; j < bset->n_eq; ++j)
+			isl_int_set(dual->eq[k][1 + shift + total + j],
+				    bset->eq[j][1 + i]);
+		for (j = 0; j < bset->n_ineq; ++j)
+			isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
+				    bset->ineq[j][1 + i]);
+	}
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->ineq[k],
+			    1 + shift + total + bset->n_eq + bset->n_ineq);
+		isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
+	}
+
+	if (shift > 0) {
+		k = isl_basic_set_alloc_inequality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->ineq[k], 2 + total);
+		isl_int_set_si(dual->ineq[k][1], 1);
+		for (j = 0; j < bset->n_eq; ++j)
+			isl_int_neg(dual->ineq[k][2 + total + j],
+				    bset->eq[j][0]);
+		for (j = 0; j < bset->n_ineq; ++j)
+			isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
+				    bset->ineq[j][0]);
+	}
+
+	dual = isl_basic_set_remove_divs(dual);
+	isl_basic_set_simplify(dual);
+	isl_basic_set_finalize(dual);
+
+	isl_basic_set_free(bset);
+	return dual;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(dual);
+	return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_div)
+		isl_die(bset->ctx, isl_error_invalid,
+			"input set not allowed to have local variables",
+			goto error);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_coefficients(dim);
+
+	return farkas(dim, bset, 1);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_solutions(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_div)
+		isl_die(bset->ctx, isl_error_invalid,
+			"input set not allowed to have local variables",
+			goto error);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_solutions(dim);
+
+	return farkas(dim, bset, -1);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given set.
+ */
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
+{
+	int i;
+	isl_basic_set *coeff;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *space = isl_set_get_space(set);
+		space = isl_space_coefficients(space);
+		isl_set_free(set);
+		return rational_universe(space);
+	}
+
+	coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
+
+	for (i = 1; i < set->n; ++i) {
+		isl_basic_set *bset, *coeff_i;
+		bset = isl_basic_set_copy(set->p[i]);
+		coeff_i = isl_basic_set_coefficients(bset);
+		coeff = isl_basic_set_intersect(coeff, coeff_i);
+	}
+
+	isl_set_free(set);
+	return coeff;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given set.
+ */
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
+{
+	int i;
+	isl_basic_set *sol;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *space = isl_set_get_space(set);
+		space = isl_space_solutions(space);
+		isl_set_free(set);
+		return rational_universe(space);
+	}
+
+	sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
+
+	for (i = 1; i < set->n; ++i) {
+		isl_basic_set *bset, *sol_i;
+		bset = isl_basic_set_copy(set->p[i]);
+		sol_i = isl_basic_set_solutions(bset);
+		sol = isl_basic_set_intersect(sol, sol_i);
+	}
+
+	isl_set_free(set);
+	return sol;
+}

Added: polly/trunk/lib/External/isl/isl_flow.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_flow.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_flow.c (added)
+++ polly/trunk/lib/External/isl/isl_flow.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1496 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Universiteit Leiden
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/flow.h>
+#include <isl_sort.h>
+
+enum isl_restriction_type {
+	isl_restriction_type_empty,
+	isl_restriction_type_none,
+	isl_restriction_type_input,
+	isl_restriction_type_output
+};
+
+struct isl_restriction {
+	enum isl_restriction_type type;
+
+	isl_set *source;
+	isl_set *sink;
+};
+
+/* Create a restriction of the given type.
+ */
+static __isl_give isl_restriction *isl_restriction_alloc(
+	__isl_take isl_map *source_map, enum isl_restriction_type type)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_map)
+		return NULL;
+
+	ctx = isl_map_get_ctx(source_map);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = type;
+
+	isl_map_free(source_map);
+	return restr;
+error:
+	isl_map_free(source_map);
+	return NULL;
+}
+
+/* Create a restriction that doesn't restrict anything.
+ */
+__isl_give isl_restriction *isl_restriction_none(__isl_take isl_map *source_map)
+{
+	return isl_restriction_alloc(source_map, isl_restriction_type_none);
+}
+
+/* Create a restriction that removes everything.
+ */
+__isl_give isl_restriction *isl_restriction_empty(
+	__isl_take isl_map *source_map)
+{
+	return isl_restriction_alloc(source_map, isl_restriction_type_empty);
+}
+
+/* Create a restriction on the input of the maximization problem
+ * based on the given source and sink restrictions.
+ */
+__isl_give isl_restriction *isl_restriction_input(
+	__isl_take isl_set *source_restr, __isl_take isl_set *sink_restr)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_restr || !sink_restr)
+		goto error;
+
+	ctx = isl_set_get_ctx(source_restr);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = isl_restriction_type_input;
+	restr->source = source_restr;
+	restr->sink = sink_restr;
+
+	return restr;
+error:
+	isl_set_free(source_restr);
+	isl_set_free(sink_restr);
+	return NULL;
+}
+
+/* Create a restriction on the output of the maximization problem
+ * based on the given source restriction.
+ */
+__isl_give isl_restriction *isl_restriction_output(
+	__isl_take isl_set *source_restr)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_restr)
+		return NULL;
+
+	ctx = isl_set_get_ctx(source_restr);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = isl_restriction_type_output;
+	restr->source = source_restr;
+
+	return restr;
+error:
+	isl_set_free(source_restr);
+	return NULL;
+}
+
+__isl_null isl_restriction *isl_restriction_free(
+	__isl_take isl_restriction *restr)
+{
+	if (!restr)
+		return NULL;
+
+	isl_set_free(restr->source);
+	isl_set_free(restr->sink);
+	free(restr);
+	return NULL;
+}
+
+isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr)
+{
+	return restr ? isl_set_get_ctx(restr->source) : NULL;
+}
+
+/* A private structure to keep track of a mapping together with
+ * a user-specified identifier and a boolean indicating whether
+ * the map represents a must or may access/dependence.
+ */
+struct isl_labeled_map {
+	struct isl_map	*map;
+	void		*data;
+	int		must;
+};
+
+/* A structure containing the input for dependence analysis:
+ * - a sink
+ * - n_must + n_may (<= max_source) sources
+ * - a function for determining the relative order of sources and sink
+ * The must sources are placed before the may sources.
+ *
+ * domain_map is an auxiliary map that maps the sink access relation
+ * to the domain of this access relation.
+ *
+ * restrict_fn is a callback that (if not NULL) will be called
+ * right before any lexicographical maximization.
+ */
+struct isl_access_info {
+	isl_map				*domain_map;
+	struct isl_labeled_map		sink;
+	isl_access_level_before		level_before;
+
+	isl_access_restrict		restrict_fn;
+	void				*restrict_user;
+
+	int		    		max_source;
+	int		    		n_must;
+	int		    		n_may;
+	struct isl_labeled_map		source[1];
+};
+
+/* A structure containing the output of dependence analysis:
+ * - n_source dependences
+ * - a wrapped subset of the sink for which definitely no source could be found
+ * - a wrapped subset of the sink for which possibly no source could be found
+ */
+struct isl_flow {
+	isl_set			*must_no_source;
+	isl_set			*may_no_source;
+	int			n_source;
+	struct isl_labeled_map	*dep;
+};
+
+/* Construct an isl_access_info structure and fill it up with
+ * the given data.  The number of sources is set to 0.
+ */
+__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink,
+	void *sink_user, isl_access_level_before fn, int max_source)
+{
+	isl_ctx *ctx;
+	struct isl_access_info *acc;
+
+	if (!sink)
+		return NULL;
+
+	ctx = isl_map_get_ctx(sink);
+	isl_assert(ctx, max_source >= 0, goto error);
+
+	acc = isl_calloc(ctx, struct isl_access_info,
+			sizeof(struct isl_access_info) +
+			(max_source - 1) * sizeof(struct isl_labeled_map));
+	if (!acc)
+		goto error;
+
+	acc->sink.map = sink;
+	acc->sink.data = sink_user;
+	acc->level_before = fn;
+	acc->max_source = max_source;
+	acc->n_must = 0;
+	acc->n_may = 0;
+
+	return acc;
+error:
+	isl_map_free(sink);
+	return NULL;
+}
+
+/* Free the given isl_access_info structure.
+ */
+__isl_null isl_access_info *isl_access_info_free(
+	__isl_take isl_access_info *acc)
+{
+	int i;
+
+	if (!acc)
+		return NULL;
+	isl_map_free(acc->domain_map);
+	isl_map_free(acc->sink.map);
+	for (i = 0; i < acc->n_must + acc->n_may; ++i)
+		isl_map_free(acc->source[i].map);
+	free(acc);
+	return NULL;
+}
+
+isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc)
+{
+	return acc ? isl_map_get_ctx(acc->sink.map) : NULL;
+}
+
+__isl_give isl_access_info *isl_access_info_set_restrict(
+	__isl_take isl_access_info *acc, isl_access_restrict fn, void *user)
+{
+	if (!acc)
+		return NULL;
+	acc->restrict_fn = fn;
+	acc->restrict_user = user;
+	return acc;
+}
+
+/* Add another source to an isl_access_info structure, making
+ * sure the "must" sources are placed before the "may" sources.
+ * This function may be called at most max_source times on a
+ * given isl_access_info structure, with max_source as specified
+ * in the call to isl_access_info_alloc that constructed the structure.
+ */
+__isl_give isl_access_info *isl_access_info_add_source(
+	__isl_take isl_access_info *acc, __isl_take isl_map *source,
+	int must, void *source_user)
+{
+	isl_ctx *ctx;
+
+	if (!acc)
+		goto error;
+	ctx = isl_map_get_ctx(acc->sink.map);
+	isl_assert(ctx, acc->n_must + acc->n_may < acc->max_source, goto error);
+	
+	if (must) {
+		if (acc->n_may)
+			acc->source[acc->n_must + acc->n_may] =
+				acc->source[acc->n_must];
+		acc->source[acc->n_must].map = source;
+		acc->source[acc->n_must].data = source_user;
+		acc->source[acc->n_must].must = 1;
+		acc->n_must++;
+	} else {
+		acc->source[acc->n_must + acc->n_may].map = source;
+		acc->source[acc->n_must + acc->n_may].data = source_user;
+		acc->source[acc->n_must + acc->n_may].must = 0;
+		acc->n_may++;
+	}
+
+	return acc;
+error:
+	isl_map_free(source);
+	isl_access_info_free(acc);
+	return NULL;
+}
+
+/* Return -n, 0 or n (with n a positive value), depending on whether
+ * the source access identified by p1 should be sorted before, together
+ * or after that identified by p2.
+ *
+ * If p1 appears before p2, then it should be sorted first.
+ * For more generic initial schedules, it is possible that neither
+ * p1 nor p2 appears before the other, or at least not in any obvious way.
+ * We therefore also check if p2 appears before p1, in which case p2
+ * should be sorted first.
+ * If not, we try to order the two statements based on the description
+ * of the iteration domains.  This results in an arbitrary, but fairly
+ * stable ordering.
+ */
+static int access_sort_cmp(const void *p1, const void *p2, void *user)
+{
+	isl_access_info *acc = user;
+	const struct isl_labeled_map *i1, *i2;
+	int level1, level2;
+	uint32_t h1, h2;
+	i1 = (const struct isl_labeled_map *) p1;
+	i2 = (const struct isl_labeled_map *) p2;
+
+	level1 = acc->level_before(i1->data, i2->data);
+	if (level1 % 2)
+		return -1;
+
+	level2 = acc->level_before(i2->data, i1->data);
+	if (level2 % 2)
+		return 1;
+
+	h1 = isl_map_get_hash(i1->map);
+	h2 = isl_map_get_hash(i2->map);
+	return h1 > h2 ? 1 : h1 < h2 ? -1 : 0;
+}
+
+/* Sort the must source accesses in their textual order.
+ */
+static __isl_give isl_access_info *isl_access_info_sort_sources(
+	__isl_take isl_access_info *acc)
+{
+	if (!acc)
+		return NULL;
+	if (acc->n_must <= 1)
+		return acc;
+
+	if (isl_sort(acc->source, acc->n_must, sizeof(struct isl_labeled_map),
+		    access_sort_cmp, acc) < 0)
+		return isl_access_info_free(acc);
+
+	return acc;
+}
+
+/* Align the parameters of the two spaces if needed and then call
+ * isl_space_join.
+ */
+static __isl_give isl_space *space_align_and_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	if (isl_space_match(left, isl_dim_param, right, isl_dim_param))
+		return isl_space_join(left, right);
+
+	left = isl_space_align_params(left, isl_space_copy(right));
+	right = isl_space_align_params(right, isl_space_copy(left));
+	return isl_space_join(left, right);
+}
+
+/* Initialize an empty isl_flow structure corresponding to a given
+ * isl_access_info structure.
+ * For each must access, two dependences are created (initialized
+ * to the empty relation), one for the resulting must dependences
+ * and one for the resulting may dependences.  May accesses can
+ * only lead to may dependences, so only one dependence is created
+ * for each of them.
+ * This function is private as isl_flow structures are only supposed
+ * to be created by isl_access_info_compute_flow.
+ */
+static __isl_give isl_flow *isl_flow_alloc(__isl_keep isl_access_info *acc)
+{
+	int i, n;
+	struct isl_ctx *ctx;
+	struct isl_flow *dep;
+
+	if (!acc)
+		return NULL;
+
+	ctx = isl_map_get_ctx(acc->sink.map);
+	dep = isl_calloc_type(ctx, struct isl_flow);
+	if (!dep)
+		return NULL;
+
+	n = 2 * acc->n_must + acc->n_may;
+	dep->dep = isl_calloc_array(ctx, struct isl_labeled_map, n);
+	if (n && !dep->dep)
+		goto error;
+
+	dep->n_source = n;
+	for (i = 0; i < acc->n_must; ++i) {
+		isl_space *dim;
+		dim = space_align_and_join(
+			isl_map_get_space(acc->source[i].map),
+			isl_space_reverse(isl_map_get_space(acc->sink.map)));
+		dep->dep[2 * i].map = isl_map_empty(dim);
+		dep->dep[2 * i + 1].map = isl_map_copy(dep->dep[2 * i].map);
+		dep->dep[2 * i].data = acc->source[i].data;
+		dep->dep[2 * i + 1].data = acc->source[i].data;
+		dep->dep[2 * i].must = 1;
+		dep->dep[2 * i + 1].must = 0;
+		if (!dep->dep[2 * i].map || !dep->dep[2 * i + 1].map)
+			goto error;
+	}
+	for (i = acc->n_must; i < acc->n_must + acc->n_may; ++i) {
+		isl_space *dim;
+		dim = space_align_and_join(
+			isl_map_get_space(acc->source[i].map),
+			isl_space_reverse(isl_map_get_space(acc->sink.map)));
+		dep->dep[acc->n_must + i].map = isl_map_empty(dim);
+		dep->dep[acc->n_must + i].data = acc->source[i].data;
+		dep->dep[acc->n_must + i].must = 0;
+		if (!dep->dep[acc->n_must + i].map)
+			goto error;
+	}
+
+	return dep;
+error:
+	isl_flow_free(dep);
+	return NULL;
+}
+
+/* Iterate over all sources and for each resulting flow dependence
+ * that is not empty, call the user specfied function.
+ * The second argument in this function call identifies the source,
+ * while the third argument correspond to the final argument of
+ * the isl_flow_foreach call.
+ */
+int isl_flow_foreach(__isl_keep isl_flow *deps,
+	int (*fn)(__isl_take isl_map *dep, int must, void *dep_user, void *user),
+	void *user)
+{
+	int i;
+
+	if (!deps)
+		return -1;
+
+	for (i = 0; i < deps->n_source; ++i) {
+		if (isl_map_plain_is_empty(deps->dep[i].map))
+			continue;
+		if (fn(isl_map_copy(deps->dep[i].map), deps->dep[i].must,
+				deps->dep[i].data, user) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Return a copy of the subset of the sink for which no source could be found.
+ */
+__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must)
+{
+	if (!deps)
+		return NULL;
+	
+	if (must)
+		return isl_set_unwrap(isl_set_copy(deps->must_no_source));
+	else
+		return isl_set_unwrap(isl_set_copy(deps->may_no_source));
+}
+
+void isl_flow_free(__isl_take isl_flow *deps)
+{
+	int i;
+
+	if (!deps)
+		return;
+	isl_set_free(deps->must_no_source);
+	isl_set_free(deps->may_no_source);
+	if (deps->dep) {
+		for (i = 0; i < deps->n_source; ++i)
+			isl_map_free(deps->dep[i].map);
+		free(deps->dep);
+	}
+	free(deps);
+}
+
+isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps)
+{
+	return deps ? isl_set_get_ctx(deps->must_no_source) : NULL;
+}
+
+/* Return a map that enforces that the domain iteration occurs after
+ * the range iteration at the given level.
+ * If level is odd, then the domain iteration should occur after
+ * the target iteration in their shared level/2 outermost loops.
+ * In this case we simply need to enforce that these outermost
+ * loop iterations are the same.
+ * If level is even, then the loop iterator of the domain should
+ * be greater than the loop iterator of the range at the last
+ * of the level/2 shared loops, i.e., loop level/2 - 1.
+ */
+static __isl_give isl_map *after_at_level(__isl_take isl_space *dim, int level)
+{
+	struct isl_basic_map *bmap;
+
+	if (level % 2)
+		bmap = isl_basic_map_equal(dim, level/2);
+	else
+		bmap = isl_basic_map_more_at(dim, level/2 - 1);
+
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Compute the partial lexicographic maximum of "dep" on domain "sink",
+ * but first check if the user has set acc->restrict_fn and if so
+ * update either the input or the output of the maximization problem
+ * with respect to the resulting restriction.
+ *
+ * Since the user expects a mapping from sink iterations to source iterations,
+ * whereas the domain of "dep" is a wrapped map, mapping sink iterations
+ * to accessed array elements, we first need to project out the accessed
+ * sink array elements by applying acc->domain_map.
+ * Similarly, the sink restriction specified by the user needs to be
+ * converted back to the wrapped map.
+ */
+static __isl_give isl_map *restricted_partial_lexmax(
+	__isl_keep isl_access_info *acc, __isl_take isl_map *dep,
+	int source, __isl_take isl_set *sink, __isl_give isl_set **empty)
+{
+	isl_map *source_map;
+	isl_restriction *restr;
+	isl_set *sink_domain;
+	isl_set *sink_restr;
+	isl_map *res;
+
+	if (!acc->restrict_fn)
+		return isl_map_partial_lexmax(dep, sink, empty);
+
+	source_map = isl_map_copy(dep);
+	source_map = isl_map_apply_domain(source_map,
+					    isl_map_copy(acc->domain_map));
+	sink_domain = isl_set_copy(sink);
+	sink_domain = isl_set_apply(sink_domain, isl_map_copy(acc->domain_map));
+	restr = acc->restrict_fn(source_map, sink_domain,
+				acc->source[source].data, acc->restrict_user);
+	isl_set_free(sink_domain);
+	isl_map_free(source_map);
+
+	if (!restr)
+		goto error;
+	if (restr->type == isl_restriction_type_input) {
+		dep = isl_map_intersect_range(dep, isl_set_copy(restr->source));
+		sink_restr = isl_set_copy(restr->sink);
+		sink_restr = isl_set_apply(sink_restr,
+				isl_map_reverse(isl_map_copy(acc->domain_map)));
+		sink = isl_set_intersect(sink, sink_restr);
+	} else if (restr->type == isl_restriction_type_empty) {
+		isl_space *space = isl_map_get_space(dep);
+		isl_map_free(dep);
+		dep = isl_map_empty(space);
+	}
+
+	res = isl_map_partial_lexmax(dep, sink, empty);
+
+	if (restr->type == isl_restriction_type_output)
+		res = isl_map_intersect_range(res, isl_set_copy(restr->source));
+
+	isl_restriction_free(restr);
+	return res;
+error:
+	isl_map_free(dep);
+	isl_set_free(sink);
+	*empty = NULL;
+	return NULL;
+}
+
+/* Compute the last iteration of must source j that precedes the sink
+ * at the given level for sink iterations in set_C.
+ * The subset of set_C for which no such iteration can be found is returned
+ * in *empty.
+ */
+static struct isl_map *last_source(struct isl_access_info *acc, 
+				    struct isl_set *set_C,
+				    int j, int level, struct isl_set **empty)
+{
+	struct isl_map *read_map;
+	struct isl_map *write_map;
+	struct isl_map *dep_map;
+	struct isl_map *after;
+	struct isl_map *result;
+
+	read_map = isl_map_copy(acc->sink.map);
+	write_map = isl_map_copy(acc->source[j].map);
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	after = after_at_level(isl_map_get_space(dep_map), level);
+	dep_map = isl_map_intersect(dep_map, after);
+	result = restricted_partial_lexmax(acc, dep_map, j, set_C, empty);
+	result = isl_map_reverse(result);
+
+	return result;
+}
+
+/* For a given mapping between iterations of must source j and iterations
+ * of the sink, compute the last iteration of must source k preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source j at level
+ * after_level.
+ */
+static struct isl_map *last_later_source(struct isl_access_info *acc,
+					 struct isl_map *old_map,
+					 int j, int before_level,
+					 int k, int after_level,
+					 struct isl_set **empty)
+{
+	isl_space *dim;
+	struct isl_set *set_C;
+	struct isl_map *read_map;
+	struct isl_map *write_map;
+	struct isl_map *dep_map;
+	struct isl_map *after_write;
+	struct isl_map *before_read;
+	struct isl_map *result;
+
+	set_C = isl_map_range(isl_map_copy(old_map));
+	read_map = isl_map_copy(acc->sink.map);
+	write_map = isl_map_copy(acc->source[k].map);
+
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	dim = space_align_and_join(isl_map_get_space(acc->source[k].map),
+		    isl_space_reverse(isl_map_get_space(acc->source[j].map)));
+	after_write = after_at_level(dim, after_level);
+	after_write = isl_map_apply_range(after_write, old_map);
+	after_write = isl_map_reverse(after_write);
+	dep_map = isl_map_intersect(dep_map, after_write);
+	before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+	dep_map = isl_map_intersect(dep_map, before_read);
+	result = restricted_partial_lexmax(acc, dep_map, k, set_C, empty);
+	result = isl_map_reverse(result);
+
+	return result;
+}
+
+/* Given a shared_level between two accesses, return 1 if the
+ * the first can precede the second at the requested target_level.
+ * If the target level is odd, i.e., refers to a statement level
+ * dimension, then first needs to precede second at the requested
+ * level, i.e., shared_level must be equal to target_level.
+ * If the target level is odd, then the two loops should share
+ * at least the requested number of outer loops.
+ */
+static int can_precede_at_level(int shared_level, int target_level)
+{
+	if (shared_level < target_level)
+		return 0;
+	if ((target_level % 2) && shared_level > target_level)
+		return 0;
+	return 1;
+}
+
+/* Given a possible flow dependence temp_rel[j] between source j and the sink
+ * at level sink_level, remove those elements for which
+ * there is an iteration of another source k < j that is closer to the sink.
+ * The flow dependences temp_rel[k] are updated with the improved sources.
+ * Any improved source needs to precede the sink at the same level
+ * and needs to follow source j at the same or a deeper level.
+ * The lower this level, the later the execution date of source k.
+ * We therefore consider lower levels first.
+ *
+ * If temp_rel[j] is empty, then there can be no improvement and
+ * we return immediately.
+ */
+static int intermediate_sources(__isl_keep isl_access_info *acc,
+	struct isl_map **temp_rel, int j, int sink_level)
+{
+	int k, level;
+	int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1;
+
+	if (isl_map_plain_is_empty(temp_rel[j]))
+		return 0;
+
+	for (k = j - 1; k >= 0; --k) {
+		int plevel, plevel2;
+		plevel = acc->level_before(acc->source[k].data, acc->sink.data);
+		if (!can_precede_at_level(plevel, sink_level))
+			continue;
+
+		plevel2 = acc->level_before(acc->source[j].data,
+						acc->source[k].data);
+
+		for (level = sink_level; level <= depth; ++level) {
+			struct isl_map *T;
+			struct isl_set *trest;
+			struct isl_map *copy;
+
+			if (!can_precede_at_level(plevel2, level))
+				continue;
+
+			copy = isl_map_copy(temp_rel[j]);
+			T = last_later_source(acc, copy, j, sink_level, k,
+					      level, &trest);
+			if (isl_map_plain_is_empty(T)) {
+				isl_set_free(trest);
+				isl_map_free(T);
+				continue;
+			}
+			temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest);
+			temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T);
+		}
+	}
+
+	return 0;
+}
+
+/* Compute all iterations of may source j that precedes the sink at the given
+ * level for sink iterations in set_C.
+ */
+static __isl_give isl_map *all_sources(__isl_keep isl_access_info *acc,
+				    __isl_take isl_set *set_C, int j, int level)
+{
+	isl_map *read_map;
+	isl_map *write_map;
+	isl_map *dep_map;
+	isl_map *after;
+
+	read_map = isl_map_copy(acc->sink.map);
+	read_map = isl_map_intersect_domain(read_map, set_C);
+	write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	after = after_at_level(isl_map_get_space(dep_map), level);
+	dep_map = isl_map_intersect(dep_map, after);
+
+	return isl_map_reverse(dep_map);
+}
+
+/* For a given mapping between iterations of must source k and iterations
+ * of the sink, compute the all iteration of may source j preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source k at level
+ * after_level.
+ */
+static __isl_give isl_map *all_later_sources(__isl_keep isl_access_info *acc,
+	__isl_take isl_map *old_map,
+	int j, int before_level, int k, int after_level)
+{
+	isl_space *dim;
+	isl_set *set_C;
+	isl_map *read_map;
+	isl_map *write_map;
+	isl_map *dep_map;
+	isl_map *after_write;
+	isl_map *before_read;
+
+	set_C = isl_map_range(isl_map_copy(old_map));
+	read_map = isl_map_copy(acc->sink.map);
+	read_map = isl_map_intersect_domain(read_map, set_C);
+	write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	dim = isl_space_join(isl_map_get_space(acc->source[acc->n_must + j].map),
+		    isl_space_reverse(isl_map_get_space(acc->source[k].map)));
+	after_write = after_at_level(dim, after_level);
+	after_write = isl_map_apply_range(after_write, old_map);
+	after_write = isl_map_reverse(after_write);
+	dep_map = isl_map_intersect(dep_map, after_write);
+	before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+	dep_map = isl_map_intersect(dep_map, before_read);
+	return isl_map_reverse(dep_map);
+}
+
+/* Given the must and may dependence relations for the must accesses
+ * for level sink_level, check if there are any accesses of may access j
+ * that occur in between and return their union.
+ * If some of these accesses are intermediate with respect to
+ * (previously thought to be) must dependences, then these
+ * must dependences are turned into may dependences.
+ */
+static __isl_give isl_map *all_intermediate_sources(
+	__isl_keep isl_access_info *acc, __isl_take isl_map *map,
+	struct isl_map **must_rel, struct isl_map **may_rel,
+	int j, int sink_level)
+{
+	int k, level;
+	int depth = 2 * isl_map_dim(acc->source[acc->n_must + j].map,
+					isl_dim_in) + 1;
+
+	for (k = 0; k < acc->n_must; ++k) {
+		int plevel;
+
+		if (isl_map_plain_is_empty(may_rel[k]) &&
+		    isl_map_plain_is_empty(must_rel[k]))
+			continue;
+
+		plevel = acc->level_before(acc->source[k].data,
+					acc->source[acc->n_must + j].data);
+
+		for (level = sink_level; level <= depth; ++level) {
+			isl_map *T;
+			isl_map *copy;
+			isl_set *ran;
+
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			copy = isl_map_copy(may_rel[k]);
+			T = all_later_sources(acc, copy, j, sink_level, k, level);
+			map = isl_map_union(map, T);
+
+			copy = isl_map_copy(must_rel[k]);
+			T = all_later_sources(acc, copy, j, sink_level, k, level);
+			ran = isl_map_range(isl_map_copy(T));
+			map = isl_map_union(map, T);
+			may_rel[k] = isl_map_union_disjoint(may_rel[k],
+			    isl_map_intersect_range(isl_map_copy(must_rel[k]),
+						    isl_set_copy(ran)));
+			T = isl_map_from_domain_and_range(
+			    isl_set_universe(
+				isl_space_domain(isl_map_get_space(must_rel[k]))),
+			    ran);
+			must_rel[k] = isl_map_subtract(must_rel[k], T);
+		}
+	}
+
+	return map;
+}
+
+/* Compute dependences for the case where all accesses are "may"
+ * accesses, which boils down to computing memory based dependences.
+ * The generic algorithm would also work in this case, but it would
+ * be overkill to use it.
+ */
+static __isl_give isl_flow *compute_mem_based_dependences(
+	__isl_keep isl_access_info *acc)
+{
+	int i;
+	isl_set *mustdo;
+	isl_set *maydo;
+	isl_flow *res;
+
+	res = isl_flow_alloc(acc);
+	if (!res)
+		return NULL;
+
+	mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+	maydo = isl_set_copy(mustdo);
+
+	for (i = 0; i < acc->n_may; ++i) {
+		int plevel;
+		int is_before;
+		isl_space *dim;
+		isl_map *before;
+		isl_map *dep;
+
+		plevel = acc->level_before(acc->source[i].data, acc->sink.data);
+		is_before = plevel & 1;
+		plevel >>= 1;
+
+		dim = isl_map_get_space(res->dep[i].map);
+		if (is_before)
+			before = isl_map_lex_le_first(dim, plevel);
+		else
+			before = isl_map_lex_lt_first(dim, plevel);
+		dep = isl_map_apply_range(isl_map_copy(acc->source[i].map),
+			isl_map_reverse(isl_map_copy(acc->sink.map)));
+		dep = isl_map_intersect(dep, before);
+		mustdo = isl_set_subtract(mustdo,
+					    isl_map_range(isl_map_copy(dep)));
+		res->dep[i].map = isl_map_union(res->dep[i].map, dep);
+	}
+
+	res->may_no_source = isl_set_subtract(maydo, isl_set_copy(mustdo));
+	res->must_no_source = mustdo;
+
+	return res;
+}
+
+/* Compute dependences for the case where there is at least one
+ * "must" access.
+ *
+ * The core algorithm considers all levels in which a source may precede
+ * the sink, where a level may either be a statement level or a loop level.
+ * The outermost statement level is 1, the first loop level is 2, etc...
+ * The algorithm basically does the following:
+ * for all levels l of the read access from innermost to outermost
+ *	for all sources w that may precede the sink access at that level
+ *	    compute the last iteration of the source that precedes the sink access
+ *					    at that level
+ *	    add result to possible last accesses at level l of source w
+ *	    for all sources w2 that we haven't considered yet at this level that may
+ *					    also precede the sink access
+ *		for all levels l2 of w from l to innermost
+ *		    for all possible last accesses dep of w at l
+ *			compute last iteration of w2 between the source and sink
+ *								of dep
+ *			add result to possible last accesses at level l of write w2
+ *			and replace possible last accesses dep by the remainder
+ *
+ *
+ * The above algorithm is applied to the must access.  During the course
+ * of the algorithm, we keep track of sink iterations that still
+ * need to be considered.  These iterations are split into those that
+ * haven't been matched to any source access (mustdo) and those that have only
+ * been matched to may accesses (maydo).
+ * At the end of each level, we also consider the may accesses.
+ * In particular, we consider may accesses that precede the remaining
+ * sink iterations, moving elements from mustdo to maydo when appropriate,
+ * and may accesses that occur between a must source and a sink of any 
+ * dependences found at the current level, turning must dependences into
+ * may dependences when appropriate.
+ * 
+ */
+static __isl_give isl_flow *compute_val_based_dependences(
+	__isl_keep isl_access_info *acc)
+{
+	isl_ctx *ctx;
+	isl_flow *res;
+	isl_set *mustdo = NULL;
+	isl_set *maydo = NULL;
+	int level, j;
+	int depth;
+	isl_map **must_rel = NULL;
+	isl_map **may_rel = NULL;
+
+	if (!acc)
+		return NULL;
+
+	res = isl_flow_alloc(acc);
+	if (!res)
+		goto error;
+	ctx = isl_map_get_ctx(acc->sink.map);
+
+	depth = 2 * isl_map_dim(acc->sink.map, isl_dim_in) + 1;
+	mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+	maydo = isl_set_empty_like(mustdo);
+	if (!mustdo || !maydo)
+		goto error;
+	if (isl_set_plain_is_empty(mustdo))
+		goto done;
+
+	must_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_must);
+	may_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_must);
+	if (!must_rel || !may_rel)
+		goto error;
+
+	for (level = depth; level >= 1; --level) {
+		for (j = acc->n_must-1; j >=0; --j) {
+			must_rel[j] = isl_map_empty_like(res->dep[2 * j].map);
+			may_rel[j] = isl_map_copy(must_rel[j]);
+		}
+
+		for (j = acc->n_must - 1; j >= 0; --j) {
+			struct isl_map *T;
+			struct isl_set *rest;
+			int plevel;
+
+			plevel = acc->level_before(acc->source[j].data,
+						     acc->sink.data);
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			T = last_source(acc, mustdo, j, level, &rest);
+			must_rel[j] = isl_map_union_disjoint(must_rel[j], T);
+			mustdo = rest;
+
+			intermediate_sources(acc, must_rel, j, level);
+
+			T = last_source(acc, maydo, j, level, &rest);
+			may_rel[j] = isl_map_union_disjoint(may_rel[j], T);
+			maydo = rest;
+
+			intermediate_sources(acc, may_rel, j, level);
+
+			if (isl_set_plain_is_empty(mustdo) &&
+			    isl_set_plain_is_empty(maydo))
+				break;
+		}
+		for (j = j - 1; j >= 0; --j) {
+			int plevel;
+
+			plevel = acc->level_before(acc->source[j].data,
+						     acc->sink.data);
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			intermediate_sources(acc, must_rel, j, level);
+			intermediate_sources(acc, may_rel, j, level);
+		}
+
+		for (j = 0; j < acc->n_may; ++j) {
+			int plevel;
+			isl_map *T;
+			isl_set *ran;
+
+			plevel = acc->level_before(acc->source[acc->n_must + j].data,
+						     acc->sink.data);
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			T = all_sources(acc, isl_set_copy(maydo), j, level);
+			res->dep[2 * acc->n_must + j].map =
+			    isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+			T = all_sources(acc, isl_set_copy(mustdo), j, level);
+			ran = isl_map_range(isl_map_copy(T));
+			res->dep[2 * acc->n_must + j].map =
+			    isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+			mustdo = isl_set_subtract(mustdo, isl_set_copy(ran));
+			maydo = isl_set_union_disjoint(maydo, ran);
+
+			T = res->dep[2 * acc->n_must + j].map;
+			T = all_intermediate_sources(acc, T, must_rel, may_rel,
+							j, level);
+			res->dep[2 * acc->n_must + j].map = T;
+		}
+
+		for (j = acc->n_must - 1; j >= 0; --j) {
+			res->dep[2 * j].map =
+				isl_map_union_disjoint(res->dep[2 * j].map,
+							     must_rel[j]);
+			res->dep[2 * j + 1].map =
+				isl_map_union_disjoint(res->dep[2 * j + 1].map,
+							     may_rel[j]);
+		}
+
+		if (isl_set_plain_is_empty(mustdo) &&
+		    isl_set_plain_is_empty(maydo))
+			break;
+	}
+
+	free(must_rel);
+	free(may_rel);
+done:
+	res->must_no_source = mustdo;
+	res->may_no_source = maydo;
+	return res;
+error:
+	isl_flow_free(res);
+	isl_set_free(mustdo);
+	isl_set_free(maydo);
+	free(must_rel);
+	free(may_rel);
+	return NULL;
+}
+
+/* Given a "sink" access, a list of n "source" accesses,
+ * compute for each iteration of the sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a list of n relations between source and sink
+ * iterations and a subset of the domain of the sink access,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * To deal with multi-valued sink access relations, the sink iteration
+ * domain is first extended with dimensions that correspond to the data
+ * space.  After the computation is finished, these extra dimensions are
+ * projected out again.
+ */
+__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc)
+{
+	int j;
+	struct isl_flow *res = NULL;
+
+	if (!acc)
+		return NULL;
+
+	acc->domain_map = isl_map_domain_map(isl_map_copy(acc->sink.map));
+	acc->sink.map = isl_map_range_map(acc->sink.map);
+	if (!acc->sink.map)
+		goto error;
+
+	if (acc->n_must == 0)
+		res = compute_mem_based_dependences(acc);
+	else {
+		acc = isl_access_info_sort_sources(acc);
+		res = compute_val_based_dependences(acc);
+	}
+	if (!res)
+		goto error;
+
+	for (j = 0; j < res->n_source; ++j) {
+		res->dep[j].map = isl_map_apply_range(res->dep[j].map,
+					isl_map_copy(acc->domain_map));
+		if (!res->dep[j].map)
+			goto error;
+	}
+	if (!res->must_no_source || !res->may_no_source)
+		goto error;
+
+	isl_access_info_free(acc);
+	return res;
+error:
+	isl_access_info_free(acc);
+	isl_flow_free(res);
+	return NULL;
+}
+
+
+/* Keep track of some information about a schedule for a given
+ * access.  In particular, keep track of which dimensions
+ * have a constant value and of the actual constant values.
+ */
+struct isl_sched_info {
+	int *is_cst;
+	isl_vec *cst;
+};
+
+static void sched_info_free(__isl_take struct isl_sched_info *info)
+{
+	if (!info)
+		return;
+	isl_vec_free(info->cst);
+	free(info->is_cst);
+	free(info);
+}
+
+/* Extract information on the constant dimensions of the schedule
+ * for a given access.  The "map" is of the form
+ *
+ *	[S -> D] -> A
+ *
+ * with S the schedule domain, D the iteration domain and A the data domain.
+ */
+static __isl_give struct isl_sched_info *sched_info_alloc(
+	__isl_keep isl_map *map)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	struct isl_sched_info *info;
+	int i, n;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_space_unwrap(isl_space_domain(isl_map_get_space(map)));
+	if (!dim)
+		return NULL;
+	n = isl_space_dim(dim, isl_dim_in);
+	isl_space_free(dim);
+
+	ctx = isl_map_get_ctx(map);
+	info = isl_alloc_type(ctx, struct isl_sched_info);
+	if (!info)
+		return NULL;
+	info->is_cst = isl_alloc_array(ctx, int, n);
+	info->cst = isl_vec_alloc(ctx, n);
+	if (n && (!info->is_cst || !info->cst))
+		goto error;
+
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+
+		v = isl_map_plain_get_val_if_fixed(map, isl_dim_in, i);
+		if (!v)
+			goto error;
+		info->is_cst[i] = !isl_val_is_nan(v);
+		if (info->is_cst[i])
+			info->cst = isl_vec_set_element_val(info->cst, i, v);
+		else
+			isl_val_free(v);
+	}
+
+	return info;
+error:
+	sched_info_free(info);
+	return NULL;
+}
+
+struct isl_compute_flow_data {
+	isl_union_map *must_source;
+	isl_union_map *may_source;
+	isl_union_map *must_dep;
+	isl_union_map *may_dep;
+	isl_union_map *must_no_source;
+	isl_union_map *may_no_source;
+
+	int count;
+	int must;
+	isl_space *dim;
+	struct isl_sched_info *sink_info;
+	struct isl_sched_info **source_info;
+	isl_access_info *accesses;
+};
+
+static int count_matching_array(__isl_take isl_map *map, void *user)
+{
+	int eq;
+	isl_space *dim;
+	struct isl_compute_flow_data *data;
+
+	data = (struct isl_compute_flow_data *)user;
+
+	dim = isl_space_range(isl_map_get_space(map));
+
+	eq = isl_space_is_equal(dim, data->dim);
+
+	isl_space_free(dim);
+	isl_map_free(map);
+
+	if (eq < 0)
+		return -1;
+	if (eq)
+		data->count++;
+
+	return 0;
+}
+
+static int collect_matching_array(__isl_take isl_map *map, void *user)
+{
+	int eq;
+	isl_space *dim;
+	struct isl_sched_info *info;
+	struct isl_compute_flow_data *data;
+
+	data = (struct isl_compute_flow_data *)user;
+
+	dim = isl_space_range(isl_map_get_space(map));
+
+	eq = isl_space_is_equal(dim, data->dim);
+
+	isl_space_free(dim);
+
+	if (eq < 0)
+		goto error;
+	if (!eq) {
+		isl_map_free(map);
+		return 0;
+	}
+
+	info = sched_info_alloc(map);
+	data->source_info[data->count] = info;
+
+	data->accesses = isl_access_info_add_source(data->accesses,
+						    map, data->must, info);
+
+	data->count++;
+
+	return 0;
+error:
+	isl_map_free(map);
+	return -1;
+}
+
+/* Determine the shared nesting level and the "textual order" of
+ * the given accesses.
+ *
+ * We first determine the minimal schedule dimension for both accesses.
+ *
+ * If among those dimensions, we can find one where both have a fixed
+ * value and if moreover those values are different, then the previous
+ * dimension is the last shared nesting level and the textual order
+ * is determined based on the order of the fixed values.
+ * If no such fixed values can be found, then we set the shared
+ * nesting level to the minimal schedule dimension, with no textual ordering.
+ */
+static int before(void *first, void *second)
+{
+	struct isl_sched_info *info1 = first;
+	struct isl_sched_info *info2 = second;
+	int n1, n2;
+	int i;
+
+	n1 = isl_vec_size(info1->cst);
+	n2 = isl_vec_size(info2->cst);
+
+	if (n2 < n1)
+		n1 = n2;
+
+	for (i = 0; i < n1; ++i) {
+		int r;
+		int cmp;
+
+		if (!info1->is_cst[i])
+			continue;
+		if (!info2->is_cst[i])
+			continue;
+		cmp = isl_vec_cmp_element(info1->cst, info2->cst, i);
+		if (cmp == 0)
+			continue;
+
+		r = 2 * i + (cmp < 0);
+
+		return r;
+	}
+
+	return 2 * n1;
+}
+
+/* Given a sink access, look for all the source accesses that access
+ * the same array and perform dataflow analysis on them using
+ * isl_access_info_compute_flow.
+ */
+static int compute_flow(__isl_take isl_map *map, void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_compute_flow_data *data;
+	isl_flow *flow;
+
+	data = (struct isl_compute_flow_data *)user;
+
+	ctx = isl_map_get_ctx(map);
+
+	data->accesses = NULL;
+	data->sink_info = NULL;
+	data->source_info = NULL;
+	data->count = 0;
+	data->dim = isl_space_range(isl_map_get_space(map));
+
+	if (isl_union_map_foreach_map(data->must_source,
+					&count_matching_array, data) < 0)
+		goto error;
+	if (isl_union_map_foreach_map(data->may_source,
+					&count_matching_array, data) < 0)
+		goto error;
+
+	data->sink_info = sched_info_alloc(map);
+	data->source_info = isl_calloc_array(ctx, struct isl_sched_info *,
+					     data->count);
+
+	data->accesses = isl_access_info_alloc(isl_map_copy(map),
+				data->sink_info, &before, data->count);
+	if (!data->sink_info || (data->count && !data->source_info) ||
+	    !data->accesses)
+		goto error;
+	data->count = 0;
+	data->must = 1;
+	if (isl_union_map_foreach_map(data->must_source,
+					&collect_matching_array, data) < 0)
+		goto error;
+	data->must = 0;
+	if (isl_union_map_foreach_map(data->may_source,
+					&collect_matching_array, data) < 0)
+		goto error;
+
+	flow = isl_access_info_compute_flow(data->accesses);
+	data->accesses = NULL;
+
+	if (!flow)
+		goto error;
+
+	data->must_no_source = isl_union_map_union(data->must_no_source,
+		    isl_union_map_from_map(isl_flow_get_no_source(flow, 1)));
+	data->may_no_source = isl_union_map_union(data->may_no_source,
+		    isl_union_map_from_map(isl_flow_get_no_source(flow, 0)));
+
+	for (i = 0; i < flow->n_source; ++i) {
+		isl_union_map *dep;
+		dep = isl_union_map_from_map(isl_map_copy(flow->dep[i].map));
+		if (flow->dep[i].must)
+			data->must_dep = isl_union_map_union(data->must_dep, dep);
+		else
+			data->may_dep = isl_union_map_union(data->may_dep, dep);
+	}
+
+	isl_flow_free(flow);
+
+	sched_info_free(data->sink_info);
+	if (data->source_info) {
+		for (i = 0; i < data->count; ++i)
+			sched_info_free(data->source_info[i]);
+		free(data->source_info);
+	}
+	isl_space_free(data->dim);
+	isl_map_free(map);
+
+	return 0;
+error:
+	isl_access_info_free(data->accesses);
+	sched_info_free(data->sink_info);
+	if (data->source_info) {
+		for (i = 0; i < data->count; ++i)
+			sched_info_free(data->source_info[i]);
+		free(data->source_info);
+	}
+	isl_space_free(data->dim);
+	isl_map_free(map);
+
+	return -1;
+}
+
+/* Given a collection of "sink" and "source" accesses,
+ * compute for each iteration of a sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a relations between source and sink
+ * iterations and a subset of the domain of the sink accesses,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * We first prepend the schedule dimensions to the domain
+ * of the accesses so that we can easily compare their relative order.
+ * Then we consider each sink access individually in compute_flow.
+ */
+int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
+	__isl_take isl_union_map *must_source,
+	__isl_take isl_union_map *may_source,
+	__isl_take isl_union_map *schedule,
+	__isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep,
+	__isl_give isl_union_map **must_no_source,
+	__isl_give isl_union_map **may_no_source)
+{
+	isl_space *dim;
+	isl_union_map *range_map = NULL;
+	struct isl_compute_flow_data data;
+
+	sink = isl_union_map_align_params(sink,
+					    isl_union_map_get_space(must_source));
+	sink = isl_union_map_align_params(sink,
+					    isl_union_map_get_space(may_source));
+	sink = isl_union_map_align_params(sink,
+					    isl_union_map_get_space(schedule));
+	dim = isl_union_map_get_space(sink);
+	must_source = isl_union_map_align_params(must_source, isl_space_copy(dim));
+	may_source = isl_union_map_align_params(may_source, isl_space_copy(dim));
+	schedule = isl_union_map_align_params(schedule, isl_space_copy(dim));
+
+	schedule = isl_union_map_reverse(schedule);
+	range_map = isl_union_map_range_map(schedule);
+	schedule = isl_union_map_reverse(isl_union_map_copy(range_map));
+	sink = isl_union_map_apply_domain(sink, isl_union_map_copy(schedule));
+	must_source = isl_union_map_apply_domain(must_source,
+						isl_union_map_copy(schedule));
+	may_source = isl_union_map_apply_domain(may_source, schedule);
+
+	data.must_source = must_source;
+	data.may_source = may_source;
+	data.must_dep = must_dep ?
+		isl_union_map_empty(isl_space_copy(dim)) : NULL;
+	data.may_dep = may_dep ? isl_union_map_empty(isl_space_copy(dim)) : NULL;
+	data.must_no_source = must_no_source ?
+		isl_union_map_empty(isl_space_copy(dim)) : NULL;
+	data.may_no_source = may_no_source ?
+		isl_union_map_empty(isl_space_copy(dim)) : NULL;
+
+	isl_space_free(dim);
+
+	if (isl_union_map_foreach_map(sink, &compute_flow, &data) < 0)
+		goto error;
+
+	isl_union_map_free(sink);
+	isl_union_map_free(must_source);
+	isl_union_map_free(may_source);
+
+	if (must_dep) {
+		data.must_dep = isl_union_map_apply_domain(data.must_dep,
+					isl_union_map_copy(range_map));
+		data.must_dep = isl_union_map_apply_range(data.must_dep,
+					isl_union_map_copy(range_map));
+		*must_dep = data.must_dep;
+	}
+	if (may_dep) {
+		data.may_dep = isl_union_map_apply_domain(data.may_dep,
+					isl_union_map_copy(range_map));
+		data.may_dep = isl_union_map_apply_range(data.may_dep,
+					isl_union_map_copy(range_map));
+		*may_dep = data.may_dep;
+	}
+	if (must_no_source) {
+		data.must_no_source = isl_union_map_apply_domain(
+			data.must_no_source, isl_union_map_copy(range_map));
+		*must_no_source = data.must_no_source;
+	}
+	if (may_no_source) {
+		data.may_no_source = isl_union_map_apply_domain(
+			data.may_no_source, isl_union_map_copy(range_map));
+		*may_no_source = data.may_no_source;
+	}
+
+	isl_union_map_free(range_map);
+
+	return 0;
+error:
+	isl_union_map_free(range_map);
+	isl_union_map_free(sink);
+	isl_union_map_free(must_source);
+	isl_union_map_free(may_source);
+	isl_union_map_free(data.must_dep);
+	isl_union_map_free(data.may_dep);
+	isl_union_map_free(data.must_no_source);
+	isl_union_map_free(data.may_no_source);
+
+	if (must_dep)
+		*must_dep = NULL;
+	if (may_dep)
+		*may_dep = NULL;
+	if (must_no_source)
+		*must_no_source = NULL;
+	if (may_no_source)
+		*may_no_source = NULL;
+	return -1;
+}

Added: polly/trunk/lib/External/isl/isl_fold.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_fold.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_fold.c (added)
+++ polly/trunk/lib/External/isl/isl_fold.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1711 @@
+/*
+ * 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 
+ */
+
+#define ISL_DIM_H
+#include <isl_map_private.h>
+#include <isl_union_map_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_point_private.h>
+#include <isl_space_private.h>
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_config.h>
+#include <isl/deprecated/polynomial_int.h>
+
+enum isl_fold isl_fold_type_negate(enum isl_fold type)
+{
+	switch (type) {
+	case isl_fold_min:
+		return isl_fold_max;
+	case isl_fold_max:
+		return isl_fold_min;
+	case isl_fold_list:
+		return isl_fold_list;
+	}
+
+	isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
+}
+
+static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
+	enum isl_fold type, __isl_take isl_space *dim, int n)
+{
+	isl_qpolynomial_fold *fold;
+
+	if (!dim)
+		goto error;
+
+	isl_assert(dim->ctx, n >= 0, goto error);
+	fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold,
+			sizeof(struct isl_qpolynomial_fold) +
+			(n - 1) * sizeof(struct isl_qpolynomial *));
+	if (!fold)
+		goto error;
+
+	fold->ref = 1;
+	fold->size = n;
+	fold->n = 0;
+	fold->type = type;
+	fold->dim = dim;
+
+	return fold;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
+{
+	return fold ? fold->dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	return fold ? isl_space_copy(fold->dim) : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_space(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	isl_space *space;
+	if (!fold)
+		return NULL;
+	space = isl_space_copy(fold->dim);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	return space;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold || !dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
+							isl_space_copy(dim));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_space_free(fold->dim);
+	fold->dim = dim;
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reset the space of "fold".  This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain.  It therefore passes along both.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	isl_space_free(space);
+	return isl_qpolynomial_fold_reset_domain_space(fold, domain);
+}
+
+int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!fold)
+		return -1;
+	if (fold->n == 0 || n == 0)
+		return 0;
+
+	for (i = 0; i < fold->n; ++i) {
+		int involves = isl_qpolynomial_involves_dims(fold->qp[i],
+							    type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+	return 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
+							    type, pos, s);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!fold)
+		return NULL;
+	if (n == 0)
+		return fold;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
+							    type, first, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!fold)
+		return NULL;
+	if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_insert_dims(fold->dim, type, first, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
+							    type, first, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	if (!cst)
+		return 0;
+
+	return isl_int_sgn(cst->n) < 0 ? -1 : 1;
+}
+
+static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	enum isl_lp_result res;
+	isl_vec *aff;
+	isl_int opt;
+	int sgn = 0;
+
+	aff = isl_qpolynomial_extract_affine(qp);
+	if (!aff)
+		return 0;
+
+	isl_int_init(opt);
+
+	res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
+				&opt, NULL, NULL);
+	if (res == isl_lp_error)
+		goto done;
+	if (res == isl_lp_empty ||
+	    (res == isl_lp_ok && !isl_int_is_neg(opt))) {
+		sgn = 1;
+		goto done;
+	}
+
+	res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
+				&opt, NULL, NULL);
+	if (res == isl_lp_ok && !isl_int_is_pos(opt))
+		sgn = -1;
+
+done:
+	isl_int_clear(opt);
+	isl_vec_free(aff);
+	return sgn;
+}
+
+/* Determine, if possible, the sign of the quasipolynomial "qp" on
+ * the domain "set".
+ *
+ * If qp is a constant, then the problem is trivial.
+ * If qp is linear, then we check if the minimum of the corresponding
+ * affine constraint is non-negative or if the maximum is non-positive.
+ *
+ * Otherwise, we check if the outermost variable "v" has a lower bound "l"
+ * in "set".  If so, we write qp(v,v') as
+ *
+ *	q(v,v') * (v - l) + r(v')
+ *
+ * if q(v,v') and r(v') have the same known sign, then the original
+ * quasipolynomial has the same sign as well.
+ *
+ * Return
+ *	-1 if qp <= 0
+ *	 1 if qp >= 0
+ *	 0 if unknown
+ */
+static int isl_qpolynomial_sign(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	int d;
+	int i;
+	int is;
+	struct isl_upoly_rec *rec;
+	isl_vec *v;
+	isl_int l;
+	enum isl_lp_result res;
+	int sgn = 0;
+
+	is = isl_qpolynomial_is_cst(qp, NULL, NULL);
+	if (is < 0)
+		return 0;
+	if (is)
+		return isl_qpolynomial_cst_sign(qp);
+
+	is = isl_qpolynomial_is_affine(qp);
+	if (is < 0)
+		return 0;
+	if (is)
+		return isl_qpolynomial_aff_sign(set, qp);
+
+	if (qp->div->n_row > 0)
+		return 0;
+
+	rec = isl_upoly_as_rec(qp->upoly);
+	if (!rec)
+		return 0;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	v = isl_vec_alloc(set->ctx, 2 + d);
+	if (!v)
+		return 0;
+
+	isl_seq_clr(v->el + 1, 1 + d);
+	isl_int_set_si(v->el[0], 1);
+	isl_int_set_si(v->el[2 + qp->upoly->var], 1);
+
+	isl_int_init(l);
+
+	res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
+	if (res == isl_lp_ok) {
+		isl_qpolynomial *min;
+		isl_qpolynomial *base;
+		isl_qpolynomial *r, *q;
+		isl_qpolynomial *t;
+
+		min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
+		base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
+						qp->upoly->var, 1);
+
+		r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+					  isl_upoly_copy(rec->p[rec->n - 1]));
+		q = isl_qpolynomial_copy(r);
+
+		for (i = rec->n - 2; i >= 0; --i) {
+			r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
+			t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+						  isl_upoly_copy(rec->p[i]));
+			r = isl_qpolynomial_add(r, t);
+			if (i == 0)
+				break;
+			q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
+			q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
+		}
+
+		if (isl_qpolynomial_is_zero(q))
+			sgn = isl_qpolynomial_sign(set, r);
+		else if (isl_qpolynomial_is_zero(r))
+			sgn = isl_qpolynomial_sign(set, q);
+		else {
+			int sgn_q, sgn_r;
+			sgn_r = isl_qpolynomial_sign(set, r);
+			sgn_q = isl_qpolynomial_sign(set, q);
+			if (sgn_r == sgn_q)
+				sgn = sgn_r;
+		}
+
+		isl_qpolynomial_free(min);
+		isl_qpolynomial_free(base);
+		isl_qpolynomial_free(q);
+		isl_qpolynomial_free(r);
+	}
+
+	isl_int_clear(l);
+
+	isl_vec_free(v);
+
+	return sgn;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
+	__isl_keep isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i, j;
+	int n1;
+	struct isl_qpolynomial_fold *res = NULL;
+	int better;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+	isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+			goto error);
+
+	better = fold1->type == isl_fold_max ? -1 : 1;
+
+	if (isl_qpolynomial_fold_is_empty(fold1)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+					fold1->n + fold2->n);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < fold1->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+	n1 = res->n;
+
+	for (i = 0; i < fold2->n; ++i) {
+		for (j = n1 - 1; j >= 0; --j) {
+			isl_qpolynomial *d;
+			int sgn;
+			d = isl_qpolynomial_sub(
+				isl_qpolynomial_copy(res->qp[j]),
+				isl_qpolynomial_copy(fold2->qp[i]));
+			sgn = isl_qpolynomial_sign(set, d);
+			isl_qpolynomial_free(d);
+			if (sgn == 0)
+				continue;
+			if (sgn != better)
+				break;
+			isl_qpolynomial_free(res->qp[j]);
+			if (j != n1 - 1)
+				res->qp[j] = res->qp[n1 - 1];
+			n1--;
+			if (n1 != res->n - 1)
+				res->qp[n1] = res->qp[res->n - 1];
+			res->n--;
+		}
+		if (j >= 0)
+			continue;
+		res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
+{
+	int i;
+
+	if (!fold || !qp)
+		goto error;
+
+	if (isl_qpolynomial_is_zero(qp)) {
+		isl_qpolynomial_free(qp);
+		return fold;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
+						isl_qpolynomial_copy(qp));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_qpolynomial_free(qp);
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i;
+	isl_qpolynomial_fold *res = NULL;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	if (isl_qpolynomial_fold_is_empty(fold1)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	if (fold1->n == 1 && fold2->n != 1)
+		return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
+
+	if (fold2->n == 1) {
+		res = isl_qpolynomial_fold_add_qpolynomial(fold1,
+					isl_qpolynomial_copy(fold2->qp[0]));
+		isl_qpolynomial_fold_free(fold2);
+		return res;
+	}
+
+	res = isl_qpolynomial_fold_add_qpolynomial(
+				isl_qpolynomial_fold_copy(fold1),
+				isl_qpolynomial_copy(fold2->qp[0]));
+
+	for (i = 1; i < fold2->n; ++i) {
+		isl_qpolynomial_fold *res_i;
+		res_i = isl_qpolynomial_fold_add_qpolynomial(
+					isl_qpolynomial_fold_copy(fold1),
+					isl_qpolynomial_copy(fold2->qp[i]));
+		res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
+{
+	int i;
+
+	if (!fold || !eq)
+		goto error;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
+							isl_basic_set_copy(eq));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_basic_set_free(eq);
+	return fold;
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+	int i;
+
+	if (!fold || !context)
+		goto error;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
+							isl_set_copy(context));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_set_free(context);
+	return fold;
+error:
+	isl_set_free(context);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+	isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+	isl_set *dom_context = isl_set_universe(space);
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return isl_qpolynomial_fold_gist(fold, dom_context);
+}
+
+#define HAS_TYPE
+
+#undef PW
+#define PW isl_pw_qpolynomial_fold
+#undef EL
+#define EL isl_qpolynomial_fold
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_empty
+#undef ZERO
+#define ZERO zero
+#undef IS_ZERO
+#define IS_ZERO is_zero
+#undef FIELD
+#define FIELD fold
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 1
+
+#define NO_NEG
+#define NO_PULLBACK
+
+#include <isl_pw_templ.c>
+
+#undef UNION
+#define UNION isl_union_pw_qpolynomial_fold
+#undef PART
+#define PART isl_pw_qpolynomial_fold
+#undef PARTS
+#define PARTS pw_qpolynomial_fold
+#define ALIGN_DOMAIN
+
+#define NO_SUB
+
+#include <isl_union_templ.c>
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
+	__isl_take isl_space *dim)
+{
+	return qpolynomial_fold_alloc(type, dim, 0);
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
+	enum isl_fold type, __isl_take isl_qpolynomial *qp)
+{
+	isl_qpolynomial_fold *fold;
+
+	if (!qp)
+		return NULL;
+
+	fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1);
+	if (!fold)
+		goto error;
+
+	fold->qp[0] = qp;
+	fold->n++;
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return NULL;
+
+	fold->ref++;
+	return fold;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	int i;
+	isl_qpolynomial_fold *dup;
+
+	if (!fold)
+		return NULL;
+	dup = qpolynomial_fold_alloc(fold->type,
+					isl_space_copy(fold->dim), fold->n);
+	if (!dup)
+		return NULL;
+	
+	dup->n = fold->n;
+	for (i = 0; i < fold->n; ++i) {
+		dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
+		if (!dup->qp[i])
+			goto error;
+	}
+
+	return dup;
+error:
+	isl_qpolynomial_fold_free(dup);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
+	__isl_take isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return NULL;
+
+	if (fold->ref == 1)
+		return fold;
+	fold->ref--;
+	return isl_qpolynomial_fold_dup(fold);
+}
+
+void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold)
+{
+	int i;
+
+	if (!fold)
+		return;
+	if (--fold->ref > 0)
+		return;
+
+	for (i = 0; i < fold->n; ++i)
+		isl_qpolynomial_free(fold->qp[i]);
+	isl_space_free(fold->dim);
+	free(fold);
+}
+
+int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return -1;
+
+	return fold->n == 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i;
+	struct isl_qpolynomial_fold *res = NULL;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+	isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+			goto error);
+
+	if (isl_qpolynomial_fold_is_empty(fold1)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+					fold1->n + fold2->n);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < fold1->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	for (i = 0; i < fold2->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
+	__isl_take isl_pw_qpolynomial_fold *pw1,
+	__isl_take isl_pw_qpolynomial_fold *pw2)
+{
+	int i, j, n;
+	struct isl_pw_qpolynomial_fold *res;
+	isl_set *set;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
+		isl_pw_qpolynomial_fold_free(pw1);
+		return pw2;
+	}
+
+	if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
+		isl_pw_qpolynomial_fold_free(pw2);
+		return pw1;
+	}
+
+	if (pw1->type != pw2->type)
+		isl_die(pw1->dim->ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+
+	n = (pw1->n + 1) * (pw2->n + 1);
+	res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
+						pw1->type, n);
+
+	for (i = 0; i < pw1->n; ++i) {
+		set = isl_set_copy(pw1->p[i].set);
+		for (j = 0; j < pw2->n; ++j) {
+			struct isl_set *common;
+			isl_qpolynomial_fold *sum;
+			set = isl_set_subtract(set,
+					isl_set_copy(pw2->p[j].set));
+			common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
+						isl_set_copy(pw2->p[j].set));
+			if (isl_set_plain_is_empty(common)) {
+				isl_set_free(common);
+				continue;
+			}
+
+			sum = isl_qpolynomial_fold_fold_on_domain(common,
+			       isl_qpolynomial_fold_copy(pw1->p[i].fold),
+			       isl_qpolynomial_fold_copy(pw2->p[j].fold));
+
+			res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
+		}
+		res = isl_pw_qpolynomial_fold_add_piece(res, set,
+			isl_qpolynomial_fold_copy(pw1->p[i].fold));
+	}
+
+	for (j = 0; j < pw2->n; ++j) {
+		set = isl_set_copy(pw2->p[j].set);
+		for (i = 0; i < pw1->n; ++i)
+			set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
+		res = isl_pw_qpolynomial_fold_add_piece(res, set,
+				    isl_qpolynomial_fold_copy(pw2->p[j].fold));
+	}
+
+	isl_pw_qpolynomial_fold_free(pw1);
+	isl_pw_qpolynomial_fold_free(pw2);
+
+	return res;
+error:
+	isl_pw_qpolynomial_fold_free(pw1);
+	isl_pw_qpolynomial_fold_free(pw2);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *u,
+	__isl_take isl_pw_qpolynomial_fold *part)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	u = isl_union_pw_qpolynomial_fold_cow(u);
+
+	if (!part || !u)
+		goto error;
+
+	isl_assert(u->space->ctx,
+	    isl_space_match(part->dim, isl_dim_param, u->space, isl_dim_param),
+	    goto error);
+
+	hash = isl_space_get_hash(part->dim);
+	entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
+				    &has_same_domain_space, part->dim, 1);
+	if (!entry)
+		goto error;
+
+	if (!entry->data)
+		entry->data = part;
+	else {
+		entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
+					    isl_pw_qpolynomial_fold_copy(part));
+		if (!entry->data)
+			goto error;
+		isl_pw_qpolynomial_fold_free(part);
+	}
+
+	return u;
+error:
+	isl_pw_qpolynomial_fold_free(part);
+	isl_union_pw_qpolynomial_fold_free(u);
+	return NULL;
+}
+
+static int fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
+{
+	isl_union_pw_qpolynomial_fold **u;
+	u = (isl_union_pw_qpolynomial_fold **)user;
+
+	*u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
+
+	return 0;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *u1,
+	__isl_take isl_union_pw_qpolynomial_fold *u2)
+{
+	u1 = isl_union_pw_qpolynomial_fold_cow(u1);
+
+	if (!u1 || !u2)
+		goto error;
+
+	if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
+							&fold_part, &u1) < 0)
+		goto error;
+
+	isl_union_pw_qpolynomial_fold_free(u2);
+
+	return u1;
+error:
+	isl_union_pw_qpolynomial_fold_free(u1);
+	isl_union_pw_qpolynomial_fold_free(u2);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
+	enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
+{
+	int i;
+	isl_pw_qpolynomial_fold *pwf;
+
+	if (!pwqp)
+		return NULL;
+	
+	pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
+						type, pwqp->n);
+
+	for (i = 0; i < pwqp->n; ++i)
+		pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
+			isl_set_copy(pwqp->p[i].set),
+			isl_qpolynomial_fold_alloc(type,
+				isl_qpolynomial_copy(pwqp->p[i].qp)));
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return pwf;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
+	__isl_take isl_pw_qpolynomial_fold *pwf1,
+	__isl_take isl_pw_qpolynomial_fold *pwf2)
+{
+	return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
+}
+
+int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2)
+{
+	int i;
+
+	if (!fold1 || !fold2)
+		return -1;
+
+	if (fold1->n != fold2->n)
+		return 0;
+
+	/* We probably want to sort the qps first... */
+	for (i = 0; i < fold1->n; ++i) {
+		int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
+		if (eq < 0 || !eq)
+			return eq;
+	}
+
+	return 1;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_eval(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!fold || !pnt)
+		goto error;
+	ctx = isl_point_get_ctx(pnt);
+	isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
+	isl_assert(pnt->dim->ctx,
+		fold->type == isl_fold_max || fold->type == isl_fold_min,
+		goto error);
+
+	if (fold->n == 0)
+		v = isl_val_zero(ctx);
+	else {
+		int i;
+		v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
+						isl_point_copy(pnt));
+		for (i = 1; i < fold->n; ++i) {
+			isl_val *v_i;
+			v_i = isl_qpolynomial_eval(
+					    isl_qpolynomial_copy(fold->qp[i]),
+					    isl_point_copy(pnt));
+			if (fold->type == isl_fold_max)
+				v = isl_val_max(v, v_i);
+			else
+				v = isl_val_min(v, v_i);
+		}
+	}
+	isl_qpolynomial_fold_free(fold);
+	isl_point_free(pnt);
+
+	return v;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	int i;
+	size_t n = 0;
+
+	for (i = 0; i < pwf->n; ++i)
+		n += pwf->p[i].fold->n;
+
+	return n;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
+{
+	int i;
+	isl_val *opt;
+
+	if (!set || !fold)
+		goto error;
+
+	if (fold->n == 0) {
+		opt = isl_val_zero(isl_set_get_ctx(set));
+		isl_set_free(set);
+		isl_qpolynomial_fold_free(fold);
+		return opt;
+	}
+
+	opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
+						isl_set_copy(set), max);
+	for (i = 1; i < fold->n; ++i) {
+		isl_val *opt_i;
+		opt_i = isl_qpolynomial_opt_on_domain(
+				isl_qpolynomial_copy(fold->qp[i]),
+				isl_set_copy(set), max);
+		if (max)
+			opt = isl_val_max(opt, opt_i);
+		else
+			opt = isl_val_min(opt, opt_i);
+	}
+
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+
+	return opt;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Check whether for each quasi-polynomial in "fold2" there is
+ * a quasi-polynomial in "fold1" that dominates it on "set".
+ */
+static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2)
+{
+	int i, j;
+	int covers;
+
+	if (!set || !fold1 || !fold2)
+		return -1;
+
+	covers = fold1->type == isl_fold_max ? 1 : -1;
+
+	for (i = 0; i < fold2->n; ++i) {
+		for (j = 0; j < fold1->n; ++j) {
+			isl_qpolynomial *d;
+			int sgn;
+
+			d = isl_qpolynomial_sub(
+				isl_qpolynomial_copy(fold1->qp[j]),
+				isl_qpolynomial_copy(fold2->qp[i]));
+			sgn = isl_qpolynomial_sign(set, d);
+			isl_qpolynomial_free(d);
+			if (sgn == covers)
+				break;
+		}
+		if (j >= fold1->n)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
+ * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
+ * that of pwf2.
+ */
+int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2)
+{
+	int i, j;
+	isl_set *dom1, *dom2;
+	int is_subset;
+
+	if (!pwf1 || !pwf2)
+		return -1;
+
+	if (pwf2->n == 0)
+		return 1;
+	if (pwf1->n == 0)
+		return 0;
+
+	dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
+	dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
+	is_subset = isl_set_is_subset(dom2, dom1);
+	isl_set_free(dom1);
+	isl_set_free(dom2);
+
+	if (is_subset < 0 || !is_subset)
+		return is_subset;
+
+	for (i = 0; i < pwf2->n; ++i) {
+		for (j = 0; j < pwf1->n; ++j) {
+			int is_empty;
+			isl_set *common;
+			int covers;
+
+			common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
+						   isl_set_copy(pwf2->p[i].set));
+			is_empty = isl_set_is_empty(common);
+			if (is_empty < 0 || is_empty) {
+				isl_set_free(common);
+				if (is_empty < 0)
+					return -1;
+				continue;
+			}
+			covers = qpolynomial_fold_covers_on_domain(common,
+					pwf1->p[j].fold, pwf2->p[i].fold);
+			isl_set_free(common);
+			if (covers < 0 || !covers)
+				return covers;
+		}
+	}
+
+	return 1;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!fold || !morph)
+		goto error;
+
+	ctx = fold->dim->ctx;
+	isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error);
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	isl_space_free(fold->dim);
+	fold->dim = isl_space_copy(morph->ran->dim);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
+						isl_morph_copy(morph));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return isl_fold_list;
+	return fold->type;
+}
+
+enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	if (!upwf)
+		return isl_fold_list;
+	return upwf->type;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+	int i;
+
+	if (!fold || !dim)
+		goto error;
+
+	if (isl_space_is_equal(fold->dim, dim)) {
+		isl_space_free(dim);
+		return fold;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	isl_space_free(fold->dim);
+	fold->dim = isl_space_copy(dim);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
+						isl_space_copy(dim));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_space_free(dim);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_space_free(dim);
+	return NULL;
+}
+
+int isl_qpolynomial_fold_foreach_qpolynomial(
+	__isl_keep isl_qpolynomial_fold *fold,
+	int (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
+{
+	int i;
+
+	if (!fold)
+		return -1;
+
+	for (i = 0; i < fold->n; ++i)
+		if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
+			return -1;
+
+	return 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	fold->dim = isl_space_move_dims(fold->dim, dst_type, dst_pos,
+						src_type, src_pos, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
+				dst_type, dst_pos, src_type, src_pos, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* For each 0 <= i < "n", replace variable "first" + i of type "type"
+ * in fold->qp[k] by subs[i].
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs)
+{
+	int i;
+
+	if (n == 0)
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
+				type, first, n, subs);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+static int add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	isl_ctx *ctx;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_union_pw_qpolynomial_fold **upwf;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	upwf = (isl_union_pw_qpolynomial_fold **)user;
+
+	ctx = pwqp->dim->ctx;
+	hash = isl_space_get_hash(pwqp->dim);
+	entry = isl_hash_table_find(ctx, &(*upwf)->table, hash,
+				     &has_same_domain_space, pwqp->dim, 1);
+	if (!entry)
+		goto error;
+
+	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
+	if (!entry->data)
+		entry->data = pwf;
+	else {
+		entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
+		if (!entry->data)
+			return -1;
+		if (isl_pw_qpolynomial_fold_is_zero(entry->data)) {
+			isl_pw_qpolynomial_fold_free(entry->data);
+			isl_hash_table_remove(ctx, &(*upwf)->table, entry);
+		}
+	}
+
+	return 0;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return -1;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_pw_qpolynomial *upwqp)
+{
+	upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+				isl_union_pw_qpolynomial_get_space(upwqp));
+	upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
+				isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+	upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
+	if (!upwf || !upwqp)
+		goto error;
+
+	if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
+							 &upwf) < 0)
+		goto error;
+
+	isl_union_pw_qpolynomial_free(upwqp);
+
+	return upwf;
+error:
+	isl_union_pw_qpolynomial_fold_free(upwf);
+	isl_union_pw_qpolynomial_free(upwqp);
+	return NULL;
+}
+
+static int join_compatible(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
+{
+	int m;
+	m = isl_space_match(dim1, isl_dim_param, dim2, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(dim1, isl_dim_out, dim2, isl_dim_in);
+}
+
+/* Compute the intersection of the range of the map and the domain
+ * of the piecewise quasipolynomial reduction and then compute a bound
+ * on the associated quasipolynomial reduction over all elements
+ * in this intersection.
+ *
+ * We first introduce some unconstrained dimensions in the
+ * piecewise quasipolynomial, intersect the resulting domain
+ * with the wrapped map and the compute the sum.
+ */
+__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
+	__isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight)
+{
+	isl_ctx *ctx;
+	isl_set *dom;
+	isl_space *map_dim;
+	isl_space *pwf_dim;
+	unsigned n_in;
+	int ok;
+
+	ctx = isl_map_get_ctx(map);
+	if (!ctx)
+		goto error;
+
+	map_dim = isl_map_get_space(map);
+	pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+	ok = join_compatible(map_dim, pwf_dim);
+	isl_space_free(map_dim);
+	isl_space_free(pwf_dim);
+	if (!ok)
+		isl_die(ctx, isl_error_invalid, "incompatible dimensions",
+			goto error);
+
+	n_in = isl_map_dim(map, isl_dim_in);
+	pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
+
+	dom = isl_map_wrap(map);
+	pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
+						isl_set_get_space(dom));
+
+	pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
+	pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
+	
+	return pwf;
+error:
+	isl_map_free(map);
+	isl_pw_qpolynomial_fold_free(pwf);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
+	__isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight)
+{
+	return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
+}
+
+struct isl_apply_fold_data {
+	isl_union_pw_qpolynomial_fold *upwf;
+	isl_union_pw_qpolynomial_fold *res;
+	isl_map *map;
+	int tight;
+};
+
+static int pw_qpolynomial_fold_apply(__isl_take isl_pw_qpolynomial_fold *pwf,
+	void *user)
+{
+	isl_space *map_dim;
+	isl_space *pwf_dim;
+	struct isl_apply_fold_data *data = user;
+	int ok;
+
+	map_dim = isl_map_get_space(data->map);
+	pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+	ok = join_compatible(map_dim, pwf_dim);
+	isl_space_free(map_dim);
+	isl_space_free(pwf_dim);
+
+	if (ok) {
+		pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
+				    pwf, data->tight ? &data->tight : NULL);
+		data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+							data->res, pwf);
+	} else
+		isl_pw_qpolynomial_fold_free(pwf);
+
+	return 0;
+}
+
+static int map_apply(__isl_take isl_map *map, void *user)
+{
+	struct isl_apply_fold_data *data = user;
+	int r;
+
+	data->map = map;
+	r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
+				data->upwf, &pw_qpolynomial_fold_apply, data);
+
+	isl_map_free(map);
+	return r;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+	isl_space *dim;
+	enum isl_fold type;
+	struct isl_apply_fold_data data;
+
+	upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+				isl_union_map_get_space(umap));
+	umap = isl_union_map_align_params(umap,
+				isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+	data.upwf = upwf;
+	data.tight = tight ? 1 : 0;
+	dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
+	type = isl_union_pw_qpolynomial_fold_get_type(upwf);
+	data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
+	if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap);
+	isl_union_pw_qpolynomial_fold_free(upwf);
+
+	if (tight)
+		*tight = data.tight;
+
+	return data.res;
+error:
+	isl_union_map_free(umap);
+	isl_union_pw_qpolynomial_fold_free(upwf);
+	isl_union_pw_qpolynomial_fold_free(data.res);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_set *uset,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+	return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
+}
+
+/* Reorder the dimension of "fold" according to the given reordering.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold || !r)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
+						    isl_reordering_copy(r));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	fold = isl_qpolynomial_fold_reset_domain_space(fold,
+						    isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+	int i;
+
+	if (isl_int_is_one(v))
+		return fold;
+	if (fold && isl_int_is_zero(v)) {
+		isl_qpolynomial_fold *zero;
+		isl_space *dim = isl_space_copy(fold->dim);
+		zero = isl_qpolynomial_fold_empty(fold->type, dim);
+		isl_qpolynomial_fold_free(fold);
+		return zero;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	if (isl_int_is_neg(v))
+		fold->type = isl_fold_type_negate(fold->type);
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+	return isl_qpolynomial_fold_mul_isl_int(fold, v);
+}
+
+/* Multiply "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!fold || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return fold;
+	}
+	if (isl_val_is_zero(v)) {
+		isl_qpolynomial_fold *zero;
+		isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+		zero = isl_qpolynomial_fold_empty(fold->type, space);
+		isl_qpolynomial_fold_free(fold);
+		isl_val_free(v);
+		return zero;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	if (isl_val_is_neg(v))
+		fold->type = isl_fold_type_negate(fold->type);
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
+							isl_val_copy(v));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return fold;
+error:
+	isl_val_free(v);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Divide "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+	if (!fold || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return fold;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_fold_get_ctx(fold), 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);
+
+	return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
+error:
+	isl_val_free(v);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_gmp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_gmp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_gmp.c (added)
+++ polly/trunk/lib/External/isl/isl_gmp.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_int.h>
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash)
+{
+	int sa = v[0]._mp_size;
+	int abs_sa = sa < 0 ? -sa : sa;
+	unsigned char *data = (unsigned char *)v[0]._mp_d;
+	unsigned char *end = data + abs_sa * sizeof(v[0]._mp_d[0]);
+
+	if (sa < 0)
+		isl_hash_byte(hash, 0xFF);
+	for (; data < end; ++data)
+		isl_hash_byte(hash, *data);
+	return hash;
+}

Added: polly/trunk/lib/External/isl/isl_hash.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hash.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hash.c (added)
+++ polly/trunk/lib/External/isl/isl_hash.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <isl/hash.h>
+#include <isl/ctx.h>
+#include "isl_config.h"
+
+uint32_t isl_hash_string(uint32_t hash, const char *s)
+{
+	for (; *s; s++)
+		isl_hash_byte(hash, *s);
+	return hash;
+}
+
+uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
+{
+	int i;
+	const char *s = p;
+	for (i = 0; i < len; ++i)
+		isl_hash_byte(hash, s[i]);
+	return hash;
+}
+
+static unsigned int round_up(unsigned int v)
+{
+	int old_v = v;
+
+	while (v) {
+		old_v = v;
+		v ^= v & -v;
+	}
+	return old_v << 1;
+}
+
+int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
+			int min_size)
+{
+	size_t size;
+
+	if (!table)
+		return -1;
+
+	if (min_size < 2)
+		min_size = 2;
+	table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
+	table->n = 0;
+
+	size = 1 << table->bits;
+	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+					  size);
+	if (!table->entries)
+		return -1;
+
+	return 0;
+}
+
+/* Dummy comparison function that always returns false.
+ */
+static int no(const void *entry, const void *val)
+{
+	return 0;
+}
+
+/* Extend "table" to twice its size.
+ * Return 0 on success and -1 on error.
+ *
+ * We reuse isl_hash_table_find to create entries in the extended table.
+ * Since all entries in the original table are assumed to be different,
+ * there is no need to compare them against each other.
+ */
+static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+	int n;
+	size_t old_size, size;
+	struct isl_hash_table_entry *entries;
+	uint32_t h;
+
+	entries = table->entries;
+	old_size = 1 << table->bits;
+	size = 2 * old_size;
+	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+					  size);
+	if (!table->entries) {
+		table->entries = entries;
+		return -1;
+	}
+
+	n = table->n;
+	table->n = 0;
+	table->bits++;
+
+	for (h = 0; h < old_size; ++h) {
+		struct isl_hash_table_entry *entry;
+
+		if (!entries[h].data)
+			continue;
+
+		entry = isl_hash_table_find(ctx, table, entries[h].hash,
+					    &no, NULL, 1);
+		if (!entry) {
+			table->bits--;
+			free(table->entries);
+			table->entries = entries;
+			table->n = n;
+			return -1;
+		}
+
+		*entry = entries[h];
+	}
+
+	free(entries);
+
+	return 0;
+}
+
+struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
+{
+	struct isl_hash_table *table = NULL;
+
+	table = isl_alloc_type(ctx, struct isl_hash_table);
+	if (isl_hash_table_init(ctx, table, min_size))
+		goto error;
+	return table;
+error:
+	isl_hash_table_free(ctx, table);
+	return NULL;
+}
+
+void isl_hash_table_clear(struct isl_hash_table *table)
+{
+	if (!table)
+		return;
+	free(table->entries);
+}
+
+void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+	if (!table)
+		return;
+	isl_hash_table_clear(table);
+	free(table);
+}
+
+struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				uint32_t key_hash,
+				int (*eq)(const void *entry, const void *val),
+				const void *val, int reserve)
+{
+	size_t size;
+	uint32_t h, key_bits;
+
+	key_bits = isl_hash_bits(key_hash, table->bits);
+	size = 1 << table->bits;
+	for (h = key_bits; table->entries[h].data; h = (h+1) % size)
+		if (table->entries[h].hash == key_hash &&
+		    eq(table->entries[h].data, val))
+			return &table->entries[h];
+
+	if (!reserve)
+		return NULL;
+
+	if (4 * table->n >= 3 * size) {
+		if (grow_table(ctx, table) < 0)
+			return NULL;
+		return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
+	}
+
+	table->n++;
+	table->entries[h].hash = key_hash;
+
+	return &table->entries[h];
+}
+
+int isl_hash_table_foreach(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				int (*fn)(void **entry, void *user), void *user)
+{
+	size_t size;
+	uint32_t h;
+
+	if (!table->entries)
+		return -1;
+
+	size = 1 << table->bits;
+	for (h = 0; h < size; ++ h)
+		if (table->entries[h].data &&
+		    fn(&table->entries[h].data, user) < 0)
+			return -1;
+	
+	return 0;
+}
+
+void isl_hash_table_remove(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				struct isl_hash_table_entry *entry)
+{
+	int h, h2;
+	size_t size;
+
+	if (!table || !entry)
+		return;
+
+	size = 1 << table->bits;
+	h = entry - table->entries;
+	isl_assert(ctx, h >= 0 && h < size, return);
+
+	for (h2 = h+1; table->entries[h2 % size].data; h2++) {
+		uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
+						table->bits);
+		uint32_t offset = (size + bits - (h+1)) % size;
+		if (offset <= h2 - (h+1))
+			continue;
+		*entry = table->entries[h2 % size];
+		h = h2;
+		entry = &table->entries[h % size];
+	}
+
+	entry->hash = 0;
+	entry->data = NULL;
+	table->n--;
+}

Added: polly/trunk/lib/External/isl/isl_hide_deprecated.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hide_deprecated.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hide_deprecated.h (added)
+++ polly/trunk/lib/External/isl/isl_hide_deprecated.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,53 @@
+#define isl_aff_get_constant	isl_gmp_aff_get_constant
+#define isl_aff_get_coefficient	isl_gmp_aff_get_coefficient
+#define isl_aff_get_denominator	isl_gmp_aff_get_denominator
+#define isl_aff_set_constant	isl_gmp_aff_set_constant
+#define isl_aff_set_coefficient	isl_gmp_aff_set_coefficient
+#define isl_aff_set_denominator	isl_gmp_aff_set_denominator
+#define isl_aff_add_constant	isl_gmp_aff_add_constant
+#define isl_aff_add_constant_num	isl_gmp_aff_add_constant_num
+#define isl_aff_add_coefficient	isl_gmp_aff_add_coefficient
+#define isl_aff_mod	isl_gmp_aff_mod
+#define isl_aff_scale	isl_gmp_aff_scale
+#define isl_aff_scale_down	isl_gmp_aff_scale_down
+#define isl_pw_aff_mod	isl_gmp_pw_aff_mod
+#define isl_pw_aff_scale	isl_gmp_pw_aff_scale
+#define isl_pw_aff_scale_down	isl_gmp_pw_aff_scale_down
+#define isl_multi_aff_scale	isl_gmp_multi_aff_scale
+#define isl_ast_expr_get_int	isl_gmp_ast_expr_get_int
+#define isl_constraint_get_constant	isl_gmp_constraint_get_constant
+#define isl_constraint_get_coefficient	isl_gmp_constraint_get_coefficient
+#define isl_constraint_set_constant	isl_gmp_constraint_set_constant
+#define isl_constraint_set_coefficient	isl_gmp_constraint_set_coefficient
+#define isl_basic_set_max	isl_gmp_basic_set_max
+#define isl_set_min	isl_gmp_set_min
+#define isl_set_max	isl_gmp_set_max
+#define isl_gmp_hash	isl_gmp_gmp_hash
+#define isl_basic_map_plain_is_fixed	isl_gmp_basic_map_plain_is_fixed
+#define isl_map_fix	isl_gmp_map_fix
+#define isl_map_plain_is_fixed	isl_gmp_map_plain_is_fixed
+#define isl_map_fast_is_fixed	isl_gmp_map_fast_is_fixed
+#define isl_map_fixed_power	isl_gmp_map_fixed_power
+#define isl_mat_get_element	isl_gmp_mat_get_element
+#define isl_mat_set_element	isl_gmp_mat_set_element
+#define isl_point_get_coordinate	isl_gmp_point_get_coordinate
+#define isl_point_set_coordinate	isl_gmp_point_set_coordinate
+#define isl_qpolynomial_rat_cst_on_domain	isl_gmp_qpolynomial_rat_cst_on_domain
+#define isl_qpolynomial_is_cst	isl_gmp_qpolynomial_is_cst
+#define isl_qpolynomial_scale	isl_gmp_qpolynomial_scale
+#define isl_term_get_num	isl_gmp_term_get_num
+#define isl_term_get_den	isl_gmp_term_get_den
+#define isl_qpolynomial_fold_scale	isl_gmp_qpolynomial_fold_scale
+#define isl_pw_qpolynomial_fold_fix_dim	isl_gmp_pw_qpolynomial_fold_fix_dim
+#define isl_basic_set_fix	isl_gmp_basic_set_fix
+#define isl_set_lower_bound	isl_gmp_set_lower_bound
+#define isl_set_upper_bound	isl_gmp_set_upper_bound
+#define isl_set_fix	isl_gmp_set_fix
+#define isl_set_plain_is_fixed	isl_gmp_set_plain_is_fixed
+#define isl_union_map_fixed_power	isl_gmp_union_map_fixed_power
+#define isl_val_int_from_isl_int	isl_gmp_val_int_from_isl_int
+#define isl_val_get_num_isl_int	isl_gmp_val_get_num_isl_int
+#define isl_vec_get_element	isl_gmp_vec_get_element
+#define isl_vec_set_element	isl_gmp_vec_set_element
+#define isl_vec_set	isl_gmp_vec_set
+#define isl_vec_fdiv_r	isl_gmp_vec_fdiv_r

Added: polly/trunk/lib/External/isl/isl_hmap_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hmap_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hmap_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_hmap_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl/ctx.h>
+#include <isl/hash.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#define KEY CAT(isl_,KEY_BASE)
+#define VAL CAT(isl_,VAL_BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xHMAP(KEY,VAL_BASE) KEY ## _to_ ## VAL_BASE
+#define yHMAP(KEY,VAL_BASE) xHMAP(KEY,VAL_BASE)
+#define HMAP yHMAP(KEY,VAL_BASE)
+#define HMAP_BASE yHMAP(KEY_BASE,VAL_BASE)
+#define xS(TYPE1,TYPE2,NAME) struct isl_ ## TYPE1 ## _ ## TYPE2 ## _ ## NAME
+#define yS(TYPE1,TYPE2,NAME) xS(TYPE1,TYPE2,NAME)
+#define S(NAME) yS(KEY_BASE,VAL_BASE,NAME)
+
+struct HMAP {
+	int ref;
+	isl_ctx *ctx;
+	struct isl_hash_table table;
+};
+
+S(pair) {
+	KEY *key;
+	VAL *val;
+};
+
+__isl_give HMAP *FN(HMAP,alloc)(isl_ctx *ctx, int min_size)
+{
+	HMAP *hmap;
+
+	hmap = isl_calloc_type(ctx, HMAP);
+	if (!hmap)
+		return NULL;
+
+	hmap->ctx = ctx;
+	isl_ctx_ref(ctx);
+	hmap->ref = 1;
+
+	if (isl_hash_table_init(ctx, &hmap->table, min_size) < 0)
+		return FN(HMAP,free)(hmap);
+
+	return hmap;
+}
+
+static int free_pair(void **entry, void *user)
+{
+	S(pair) *pair = *entry;
+	FN(KEY,free)(pair->key);
+	FN(VAL,free)(pair->val);
+	free(pair);
+	*entry = NULL;
+	return 0;
+}
+
+__isl_null HMAP *FN(HMAP,free)(__isl_take HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+	if (--hmap->ref > 0)
+		return NULL;
+	isl_hash_table_foreach(hmap->ctx, &hmap->table, &free_pair, NULL);
+	isl_hash_table_clear(&hmap->table);
+	isl_ctx_deref(hmap->ctx);
+	free(hmap);
+	return NULL;
+}
+
+isl_ctx *FN(HMAP,get_ctx)(__isl_keep HMAP *hmap)
+{
+	return hmap ? hmap->ctx : NULL;
+}
+
+/* Add a mapping from "key" to "val" to the associative array
+ * pointed to by user.
+ */
+static int add_key_val(__isl_take KEY *key, __isl_take VAL *val, void *user)
+{
+	HMAP **hmap = (HMAP **) user;
+
+	*hmap = FN(HMAP,set)(*hmap, key, val);
+
+	if (!*hmap)
+		return -1;
+
+	return 0;
+}
+
+__isl_give HMAP *FN(HMAP,dup)(__isl_keep HMAP *hmap)
+{
+	HMAP *dup;
+
+	if (!hmap)
+		return NULL;
+
+	dup = FN(HMAP,alloc)(hmap->ctx, hmap->table.n);
+	if (FN(HMAP,foreach)(hmap, &add_key_val, &dup) < 0)
+		return FN(HMAP,free)(dup);
+
+	return dup;
+}
+
+__isl_give HMAP *FN(HMAP,cow)(__isl_take HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	if (hmap->ref == 1)
+		return hmap;
+	hmap->ref--;
+	return FN(HMAP,dup)(hmap);
+}
+
+__isl_give HMAP *FN(HMAP,copy)(__isl_keep HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	hmap->ref++;
+	return hmap;
+}
+
+static int has_key(const void *entry, const void *c_key)
+{
+	const S(pair) *pair = entry;
+	KEY *key = (KEY *) c_key;
+
+	return KEY_EQUAL(pair->key, key);
+}
+
+int FN(HMAP,has)(__isl_keep HMAP *hmap, __isl_keep KEY *key)
+{
+	uint32_t hash;
+
+	if (!hmap)
+		return -1;
+
+	hash = FN(KEY,get_hash)(key);
+	return !!isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+}
+
+__isl_give VAL *FN(HMAP,get)(__isl_keep HMAP *hmap, __isl_take KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = FN(KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	FN(KEY,free)(key);
+
+	if (!entry)
+		return NULL;
+
+	pair = entry->data;
+
+	return FN(VAL,copy)(pair->val);
+error:
+	FN(KEY,free)(key);
+	return NULL;
+}
+
+/* Remove the mapping between "key" and its associated value (if any)
+ * from "hmap".
+ *
+ * If "key" is not mapped to anything, then we leave "hmap" untouched"
+ */
+__isl_give HMAP *FN(HMAP,drop)(__isl_take HMAP *hmap, __isl_take KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = FN(KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	if (!entry) {
+		FN(KEY,free)(key);
+		return hmap;
+	}
+
+	hmap = FN(HMAP,cow)(hmap);
+	if (!hmap)
+		goto error;
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	FN(KEY,free)(key);
+
+	if (!entry)
+		isl_die(hmap->ctx, isl_error_internal,
+			"missing entry" , goto error);
+
+	pair = entry->data;
+	isl_hash_table_remove(hmap->ctx, &hmap->table, entry);
+	FN(KEY,free)(pair->key);
+	FN(VAL,free)(pair->val);
+	free(pair);
+
+	return hmap;
+error:
+	FN(KEY,free)(key);
+	FN(HMAP,free)(hmap);
+	return NULL;
+}
+
+/* Add a mapping from "key" to "val" to "hmap".
+ * If "key" was already mapped to something else, then that mapping
+ * is replaced.
+ * If key happened to be mapped to "val" already, then we leave
+ * "hmap" untouched.
+ */
+__isl_give HMAP *FN(HMAP,set)(__isl_take HMAP *hmap,
+	__isl_take KEY *key, __isl_take VAL *val)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key || !val)
+		goto error;
+
+	hash = FN(KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	if (entry) {
+		int equal;
+		pair = entry->data;
+		equal = VAL_EQUAL(pair->val, val);
+		if (equal < 0)
+			goto error;
+		if (equal) {
+			FN(KEY,free)(key);
+			FN(VAL,free)(val);
+			return hmap;
+		}
+	}
+
+	hmap = FN(HMAP,cow)(hmap);
+	if (!hmap)
+		goto error;
+
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 1);
+
+	if (!entry)
+		goto error;
+
+	if (entry->data) {
+		pair = entry->data;
+		FN(VAL,free)(pair->val);
+		pair->val = val;
+		FN(KEY,free)(key);
+		return hmap;
+	}
+
+	pair = isl_alloc_type(hmap->ctx, S(pair));
+	if (!pair)
+		goto error;
+
+	entry->data = pair;
+	pair->key = key;
+	pair->val = val;
+	return hmap;
+error:
+	FN(KEY,free)(key);
+	FN(VAL,free)(val);
+	return FN(HMAP,free)(hmap);
+}
+
+/* Internal data structure for isl_map_to_basic_set_foreach.
+ *
+ * fn is the function that should be called on each entry.
+ * user is the user-specified final argument to fn.
+ */
+S(foreach_data) {
+	int (*fn)(__isl_take KEY *key, __isl_take VAL *val, void *user);
+	void *user;
+};
+
+/* Call data->fn on a copy of the key and value in *entry.
+ */
+static int call_on_copy(void **entry, void *user)
+{
+	S(pair) *pair = *entry;
+	S(foreach_data) *data = (S(foreach_data) *) user;
+
+	return data->fn(FN(KEY,copy)(pair->key), FN(VAL,copy)(pair->val),
+			data->user);
+}
+
+/* Call "fn" on each pair of key and value in "hmap".
+ */
+int FN(HMAP,foreach)(__isl_keep HMAP *hmap,
+	int (*fn)(__isl_take KEY *key, __isl_take VAL *val, void *user),
+	void *user)
+{
+	S(foreach_data) data = { fn, user };
+
+	if (!hmap)
+		return -1;
+
+	return isl_hash_table_foreach(hmap->ctx, &hmap->table,
+				      &call_on_copy, &data);
+}
+
+/* Internal data structure for print_pair.
+ *
+ * p is the printer on which the associative array is being printed.
+ * first is set if the current key-value pair is the first to be printed.
+ */
+S(print_data) {
+	isl_printer *p;
+	int first;
+};
+
+/* Print the given key-value pair to data->p.
+ */
+static int print_pair(__isl_take KEY *key, __isl_take VAL *val, void *user)
+{
+	S(print_data) *data = user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, ", ");
+	data->p = FN(isl_printer_print,KEY_BASE)(data->p, key);
+	data->p = isl_printer_print_str(data->p, ": ");
+	data->p = FN(isl_printer_print,VAL_BASE)(data->p, val);
+	data->first = 0;
+
+	FN(KEY,free)(key);
+	FN(VAL,free)(val);
+	return 0;
+}
+
+/* Print the associative array to "p".
+ */
+__isl_give isl_printer *FN(isl_printer_print,HMAP_BASE)(
+	__isl_take isl_printer *p, __isl_keep HMAP *hmap)
+{
+	S(print_data) data;
+
+	if (!p || !hmap)
+		return isl_printer_free(p);
+
+	p = isl_printer_print_str(p, "{");
+	data.p = p;
+	data.first = 1;
+	if (FN(HMAP,foreach)(hmap, &print_pair, &data) < 0)
+		data.p = isl_printer_free(data.p);
+	p = data.p;
+	p = isl_printer_print_str(p, "}");
+
+	return p;
+}
+
+void FN(HMAP,dump)(__isl_keep HMAP *hmap)
+{
+	isl_printer *printer;
+
+	if (!hmap)
+		return;
+
+	printer = isl_printer_to_file(FN(HMAP,get_ctx)(hmap), stderr);
+	printer = FN(isl_printer_print,HMAP_BASE)(printer, hmap);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}

Added: polly/trunk/lib/External/isl/isl_id.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id.c (added)
+++ polly/trunk/lib/External/isl/isl_id.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_id_private.h>
+
+#undef BASE
+#define BASE id
+
+#include <isl_list_templ.c>
+
+/* A special, static isl_id to use as domains (and ranges)
+ * of sets and parameters domains.
+ * The user should never get a hold on this isl_id.
+ */
+isl_id isl_id_none = {
+	.ref = -1,
+	.ctx = NULL,
+	.name = "#none",
+	.user = NULL
+};
+
+isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id)
+{
+	return id ? id->ctx : NULL;
+}
+
+void *isl_id_get_user(__isl_keep isl_id *id)
+{
+	return id ? id->user : NULL;
+}
+
+const char *isl_id_get_name(__isl_keep isl_id *id)
+{
+	return id ? id->name : NULL;
+}
+
+static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+	const char *copy = name ? strdup(name) : NULL;
+	isl_id *id;
+
+	if (name && !copy)
+		return NULL;
+	id = isl_calloc_type(ctx, struct isl_id);
+	if (!id)
+		goto error;
+
+	id->ctx = ctx;
+	isl_ctx_ref(id->ctx);
+	id->ref = 1;
+	id->name = copy;
+	id->user = user;
+
+	id->hash = isl_hash_init();
+	if (name)
+		id->hash = isl_hash_string(id->hash, name);
+	else
+		id->hash = isl_hash_builtin(id->hash, user);
+
+	return id;
+error:
+	free((char *)copy);
+	return NULL;
+}
+
+uint32_t isl_id_get_hash(__isl_keep isl_id *id)
+{
+	return id ? id->hash : 0;
+}
+
+struct isl_name_and_user {
+	const char *name;
+	void *user;
+};
+
+static int isl_id_has_name_and_user(const void *entry, const void *val)
+{
+	isl_id *id = (isl_id *)entry;
+	struct isl_name_and_user *nu = (struct isl_name_and_user *) val;
+
+	if (id->user != nu->user)
+		return 0;
+	if (!id->name && !nu->name)
+		return 1;
+
+	return !strcmp(id->name, nu->name);
+}
+
+__isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t id_hash;
+	struct isl_name_and_user nu = { name, user };
+
+	if (!ctx)
+		return NULL;
+
+	id_hash = isl_hash_init();
+	if (name)
+		id_hash = isl_hash_string(id_hash, name);
+	else
+		id_hash = isl_hash_builtin(id_hash, user);
+	entry = isl_hash_table_find(ctx, &ctx->id_table, id_hash,
+					isl_id_has_name_and_user, &nu, 1);
+	if (!entry)
+		return NULL;
+	if (entry->data)
+		return isl_id_copy(entry->data);
+	entry->data = id_alloc(ctx, name, user);
+	if (!entry->data)
+		ctx->id_table.n--;
+	return entry->data;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * which should not be changed.
+ */
+__isl_give isl_id *isl_id_copy(isl_id *id)
+{
+	if (!id)
+		return NULL;
+
+	if (id->ref < 0)
+		return id;
+
+	id->ref++;
+	return id;
+}
+
+/* Compare two isl_ids.
+ *
+ * The order is fairly arbitrary.  We do keep the comparison of
+ * the user pointers as a last resort since these pointer values
+ * may not be stable across different systems or even different runs.
+ */
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2)
+{
+	if (id1 == id2)
+		return 0;
+	if (!id1)
+		return -1;
+	if (!id2)
+		return 1;
+	if (!id1->name != !id2->name)
+		return !id1->name - !id2->name;
+	if (id1->name) {
+		int cmp = strcmp(id1->name, id2->name);
+		if (cmp != 0)
+			return cmp;
+	}
+	if (id1->user < id2->user)
+		return -1;
+	else
+		return 1;
+}
+
+static int isl_id_eq(const void *entry, const void *name)
+{
+	return entry == name;
+}
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id)
+{
+	if (id)
+		isl_hash_hash(hash, id->hash);
+
+	return hash;
+}
+
+/* Replace the free_user callback by "free_user".
+ */
+__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id,
+	__isl_give void (*free_user)(void *user))
+{
+	if (!id)
+		return NULL;
+
+	id->free_user = free_user;
+
+	return id;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * and should not be freed.
+ */
+__isl_null isl_id *isl_id_free(__isl_take isl_id *id)
+{
+	struct isl_hash_table_entry *entry;
+
+	if (!id)
+		return NULL;
+
+	if (id->ref < 0)
+		return NULL;
+
+	if (--id->ref > 0)
+		return NULL;
+
+	entry = isl_hash_table_find(id->ctx, &id->ctx->id_table, id->hash,
+					isl_id_eq, id, 0);
+	if (!entry)
+		isl_die(id->ctx, isl_error_unknown,
+			"unable to find id", (void)0);
+	else
+		isl_hash_table_remove(id->ctx, &id->ctx->id_table, entry);
+
+	if (id->free_user)
+		id->free_user(id->user);
+
+	free((char *)id->name);
+	isl_ctx_deref(id->ctx);
+	free(id);
+
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p,
+	__isl_keep isl_id *id)
+{
+	if (!id)
+		goto error;
+
+	if (id->name)
+		p = isl_printer_print_str(p, id->name);
+	if (id->user) {
+		char buffer[50];
+		snprintf(buffer, sizeof(buffer), "@%p", id->user);
+		p = isl_printer_print_str(p, buffer);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_id_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_private.h (added)
+++ polly/trunk/lib/External/isl/isl_id_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_ID_PRIVATE_H
+#define ISL_ID_PRIVATE_H
+
+#include <isl/id.h>
+
+/* Represent a name and/or user pointer.
+ *
+ * If "free_user" is set, then it will be called on "user" when
+ * the last instance of the isl_id is freed.
+ */
+struct isl_id {
+	int ref;
+	isl_ctx *ctx;
+
+	const char *name;
+	void *user;
+	uint32_t hash;
+
+	__isl_give void (*free_user)(void *user);
+};
+
+#undef EL
+#define EL isl_id
+
+#include <isl_list_templ.h>
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id);
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2);
+
+extern isl_id isl_id_none;
+
+#endif

Added: polly/trunk/lib/External/isl/isl_id_to_ast_expr.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_to_ast_expr.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_to_ast_expr.c (added)
+++ polly/trunk/lib/External/isl/isl_id_to_ast_expr.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,11 @@
+#include <isl/id_to_ast_expr.h>
+#include <isl/ast.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define KEY_BASE	id
+#define KEY_EQUAL	isl_id_is_equal
+#define VAL_BASE	ast_expr
+#define VAL_EQUAL	isl_ast_expr_is_equal
+
+#include <isl_hmap_templ.c>

Added: polly/trunk/lib/External/isl/isl_id_to_pw_aff.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_to_pw_aff.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_to_pw_aff.c (added)
+++ polly/trunk/lib/External/isl/isl_id_to_pw_aff.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,11 @@
+#include <isl/id_to_pw_aff.h>
+#include <isl/aff.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define KEY_BASE	id
+#define KEY_EQUAL	isl_id_is_equal
+#define VAL_BASE	pw_aff
+#define VAL_EQUAL	isl_pw_aff_plain_is_equal
+
+#include <isl_hmap_templ.c>

Added: polly/trunk/lib/External/isl/isl_ilp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ilp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ilp.c (added)
+++ polly/trunk/lib/External/isl/isl_ilp.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/ilp.h>
+#include "isl_sample.h"
+#include <isl_seq.h>
+#include "isl_equalities.h"
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_lp_private.h>
+#include <isl_ilp_private.h>
+#include <isl/deprecated/ilp_int.h>
+
+/* Given a basic set "bset", construct a basic set U such that for
+ * each element x in U, the whole unit box positioned at x is inside
+ * the given basic set.
+ * Note that U may not contain all points that satisfy this property.
+ *
+ * We simply add the sum of all negative coefficients to the constant
+ * term.  This ensures that if x satisfies the resulting constraints,
+ * then x plus any sum of unit vectors satisfies the original constraints.
+ */
+static struct isl_basic_set *unit_box_base_points(struct isl_basic_set *bset)
+{
+	int i, j, k;
+	struct isl_basic_set *unit_box = NULL;
+	unsigned total;
+
+	if (!bset)
+		goto error;
+
+	if (bset->n_eq != 0) {
+		unit_box = isl_basic_set_empty_like(bset);
+		isl_basic_set_free(bset);
+		return unit_box;
+	}
+
+	total = isl_basic_set_total_dim(bset);
+	unit_box = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
+					0, 0, bset->n_ineq);
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(unit_box);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(unit_box->ineq[k], bset->ineq[i], 1 + total);
+		for (j = 0; j < total; ++j) {
+			if (isl_int_is_nonneg(unit_box->ineq[k][1 + j]))
+				continue;
+			isl_int_add(unit_box->ineq[k][0],
+				unit_box->ineq[k][0], unit_box->ineq[k][1 + j]);
+		}
+	}
+
+	isl_basic_set_free(bset);
+	return unit_box;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(unit_box);
+	return NULL;
+}
+
+/* Find an integer point in "bset", preferably one that is
+ * close to minimizing "f".
+ *
+ * We first check if we can easily put unit boxes inside bset.
+ * If so, we take the best base point of any of the unit boxes we can find
+ * and round it up to the nearest integer.
+ * If not, we simply pick any integer point in "bset".
+ */
+static struct isl_vec *initial_solution(struct isl_basic_set *bset, isl_int *f)
+{
+	enum isl_lp_result res;
+	struct isl_basic_set *unit_box;
+	struct isl_vec *sol;
+
+	unit_box = unit_box_base_points(isl_basic_set_copy(bset));
+
+	res = isl_basic_set_solve_lp(unit_box, 0, f, bset->ctx->one,
+					NULL, NULL, &sol);
+	if (res == isl_lp_ok) {
+		isl_basic_set_free(unit_box);
+		return isl_vec_ceil(sol);
+	}
+
+	isl_basic_set_free(unit_box);
+
+	return isl_basic_set_sample_vec(isl_basic_set_copy(bset));
+}
+
+/* Restrict "bset" to those points with values for f in the interval [l, u].
+ */
+static struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
+	isl_int *f, isl_int l, isl_int u)
+{
+	int k;
+	unsigned total;
+
+	total = isl_basic_set_total_dim(bset);
+	bset = isl_basic_set_extend_constraints(bset, 0, 2);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bset->ineq[k], f, 1 + total);
+	isl_int_sub(bset->ineq[k][0], bset->ineq[k][0], l);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_neg(bset->ineq[k], f, 1 + total);
+	isl_int_add(bset->ineq[k][0], bset->ineq[k][0], u);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Find an integer point in "bset" that minimizes f (in any) such that
+ * the value of f lies inside the interval [l, u].
+ * Return this integer point if it can be found.
+ * Otherwise, return sol.
+ *
+ * We perform a number of steps until l > u.
+ * In each step, we look for an integer point with value in either
+ * the whole interval [l, u] or half of the interval [l, l+floor(u-l-1/2)].
+ * The choice depends on whether we have found an integer point in the
+ * previous step.  If so, we look for the next point in half of the remaining
+ * interval.
+ * If we find a point, the current solution is updated and u is set
+ * to its value minus 1.
+ * If no point can be found, we update l to the upper bound of the interval
+ * we checked (u or l+floor(u-l-1/2)) plus 1.
+ */
+static struct isl_vec *solve_ilp_search(struct isl_basic_set *bset,
+	isl_int *f, isl_int *opt, struct isl_vec *sol, isl_int l, isl_int u)
+{
+	isl_int tmp;
+	int divide = 1;
+
+	isl_int_init(tmp);
+
+	while (isl_int_le(l, u)) {
+		struct isl_basic_set *slice;
+		struct isl_vec *sample;
+
+		if (!divide)
+			isl_int_set(tmp, u);
+		else {
+			isl_int_sub(tmp, u, l);
+			isl_int_fdiv_q_ui(tmp, tmp, 2);
+			isl_int_add(tmp, tmp, l);
+		}
+		slice = add_bounds(isl_basic_set_copy(bset), f, l, tmp);
+		sample = isl_basic_set_sample_vec(slice);
+		if (!sample) {
+			isl_vec_free(sol);
+			sol = NULL;
+			break;
+		}
+		if (sample->size > 0) {
+			isl_vec_free(sol);
+			sol = sample;
+			isl_seq_inner_product(f, sol->el, sol->size, opt);
+			isl_int_sub_ui(u, *opt, 1);
+			divide = 1;
+		} else {
+			isl_vec_free(sample);
+			if (!divide)
+				break;
+			isl_int_add_ui(l, tmp, 1);
+			divide = 0;
+		}
+	}
+
+	isl_int_clear(tmp);
+
+	return sol;
+}
+
+/* Find an integer point in "bset" that minimizes f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * The algorithm maintains a currently best solution and an interval [l, u]
+ * of values of f for which integer solutions could potentially still be found.
+ * The initial value of the best solution so far is any solution.
+ * The initial value of l is minimal value of f over the rationals
+ * (rounded up to the nearest integer).
+ * The initial value of u is the value of f at the initial solution minus 1.
+ *
+ * We then call solve_ilp_search to perform a binary search on the interval.
+ */
+static enum isl_lp_result solve_ilp(struct isl_basic_set *bset,
+				      isl_int *f, isl_int *opt,
+				      struct isl_vec **sol_p)
+{
+	enum isl_lp_result res;
+	isl_int l, u;
+	struct isl_vec *sol;
+
+	res = isl_basic_set_solve_lp(bset, 0, f, bset->ctx->one,
+					opt, NULL, &sol);
+	if (res == isl_lp_ok && isl_int_is_one(sol->el[0])) {
+		if (sol_p)
+			*sol_p = sol;
+		else
+			isl_vec_free(sol);
+		return isl_lp_ok;
+	}
+	isl_vec_free(sol);
+	if (res == isl_lp_error || res == isl_lp_empty)
+		return res;
+
+	sol = initial_solution(bset, f);
+	if (!sol)
+		return isl_lp_error;
+	if (sol->size == 0) {
+		isl_vec_free(sol);
+		return isl_lp_empty;
+	}
+	if (res == isl_lp_unbounded) {
+		isl_vec_free(sol);
+		return isl_lp_unbounded;
+	}
+
+	isl_int_init(l);
+	isl_int_init(u);
+
+	isl_int_set(l, *opt);
+
+	isl_seq_inner_product(f, sol->el, sol->size, opt);
+	isl_int_sub_ui(u, *opt, 1);
+
+	sol = solve_ilp_search(bset, f, opt, sol, l, u);
+	if (!sol)
+		res = isl_lp_error;
+
+	isl_int_clear(l);
+	isl_int_clear(u);
+
+	if (sol_p)
+		*sol_p = sol;
+	else
+		isl_vec_free(sol);
+
+	return res;
+}
+
+static enum isl_lp_result solve_ilp_with_eq(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int *opt,
+				      struct isl_vec **sol_p)
+{
+	unsigned dim;
+	enum isl_lp_result res;
+	struct isl_mat *T = NULL;
+	struct isl_vec *v;
+
+	bset = isl_basic_set_copy(bset);
+	dim = isl_basic_set_total_dim(bset);
+	v = isl_vec_alloc(bset->ctx, 1 + dim);
+	if (!v)
+		goto error;
+	isl_seq_cpy(v->el, f, 1 + dim);
+	bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+	v = isl_vec_mat_product(v, isl_mat_copy(T));
+	if (!v)
+		goto error;
+	res = isl_basic_set_solve_ilp(bset, max, v->el, opt, sol_p);
+	isl_vec_free(v);
+	if (res == isl_lp_ok && sol_p) {
+		*sol_p = isl_mat_vec_product(T, *sol_p);
+		if (!*sol_p)
+			res = isl_lp_error;
+	} else
+		isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return res;
+error:
+	isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return isl_lp_error;
+}
+
+/* Find an integer point in "bset" that minimizes (or maximizes if max is set)
+ * f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * If there is any equality among the points in "bset", then we first
+ * project it out.  Otherwise, we continue with solve_ilp above.
+ */
+enum isl_lp_result isl_basic_set_solve_ilp(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int *opt,
+				      struct isl_vec **sol_p)
+{
+	unsigned dim;
+	enum isl_lp_result res;
+
+	if (!bset)
+		return isl_lp_error;
+	if (sol_p)
+		*sol_p = NULL;
+
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_lp_empty;
+
+	if (bset->n_eq)
+		return solve_ilp_with_eq(bset, max, f, opt, sol_p);
+
+	dim = isl_basic_set_total_dim(bset);
+
+	if (max)
+		isl_seq_neg(f, f, 1 + dim);
+
+	res = solve_ilp(bset, f, opt, sol_p);
+
+	if (max) {
+		isl_seq_neg(f, f, 1 + dim);
+		isl_int_neg(*opt, *opt);
+	}
+
+	return res;
+error:
+	isl_basic_set_free(bset);
+	return isl_lp_error;
+}
+
+static enum isl_lp_result basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	enum isl_lp_result res;
+
+	if (!obj)
+		return isl_lp_error;
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_underlying_set(bset);
+	res = isl_basic_set_solve_ilp(bset, max, obj->v->el + 1, opt, NULL);
+	isl_basic_set_free(bset);
+	return res;
+}
+
+static __isl_give isl_mat *extract_divs(__isl_keep isl_basic_set *bset)
+{
+	int i;
+	isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+	isl_mat *div;
+
+	div = isl_mat_alloc(ctx, bset->n_div,
+			    1 + 1 + isl_basic_set_total_dim(bset));
+	if (!div)
+		return NULL;
+
+	for (i = 0; i < bset->n_div; ++i)
+		isl_seq_cpy(div->row[i], bset->div[i], div->n_col);
+
+	return div;
+}
+
+enum isl_lp_result isl_basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	isl_mat *bset_div = NULL;
+	isl_mat *div = NULL;
+	enum isl_lp_result res;
+	int bset_n_div, obj_n_div;
+
+	if (!bset || !obj)
+		return isl_lp_error;
+
+	ctx = isl_aff_get_ctx(obj);
+	if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", return isl_lp_error);
+	if (!isl_int_is_one(obj->v->el[0]))
+		isl_die(ctx, isl_error_unsupported,
+			"expecting integer affine expression",
+			return isl_lp_error);
+
+	bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+	obj_n_div = isl_aff_dim(obj, isl_dim_div);
+	if (bset_n_div == 0 && obj_n_div == 0)
+		return basic_set_opt(bset, max, obj, opt);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+
+	bset_div = extract_divs(bset);
+	exp1 = isl_alloc_array(ctx, int, bset_n_div);
+	exp2 = isl_alloc_array(ctx, int, obj_n_div);
+	if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+		goto error;
+
+	div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+	bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+	obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+	res = basic_set_opt(bset, max, obj, opt);
+
+	isl_mat_free(bset_div);
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+error:
+	isl_mat_free(div);
+	isl_mat_free(bset_div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+	return isl_lp_error;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static enum isl_lp_result isl_set_opt_aligned(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	int i;
+	enum isl_lp_result res;
+	int empty = 1;
+	isl_int opt_i;
+
+	if (!set || !obj)
+		return isl_lp_error;
+	if (set->n == 0)
+		return isl_lp_empty;
+
+	res = isl_basic_set_opt(set->p[0], max, obj, opt);
+	if (res == isl_lp_error || res == isl_lp_unbounded)
+		return res;
+	if (set->n == 1)
+		return res;
+	if (res == isl_lp_ok)
+		empty = 0;
+
+	isl_int_init(opt_i);
+	for (i = 1; i < set->n; ++i) {
+		res = isl_basic_set_opt(set->p[i], max, obj, &opt_i);
+		if (res == isl_lp_error || res == isl_lp_unbounded) {
+			isl_int_clear(opt_i);
+			return res;
+		}
+		if (res == isl_lp_ok)
+			empty = 0;
+		if (max ? isl_int_gt(opt_i, *opt) : isl_int_lt(opt_i, *opt))
+			isl_int_set(*opt, opt_i);
+	}
+	isl_int_clear(opt_i);
+
+	return empty ? isl_lp_empty : isl_lp_ok;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ */
+enum isl_lp_result isl_set_opt(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	enum isl_lp_result res;
+
+	if (!set || !obj)
+		return isl_lp_error;
+
+	if (isl_space_match(set->dim, isl_dim_param,
+			    obj->ls->dim, isl_dim_param))
+		return isl_set_opt_aligned(set, max, obj, opt);
+
+	set = isl_set_copy(set);
+	obj = isl_aff_copy(obj);
+	set = isl_set_align_params(set, isl_aff_get_domain_space(obj));
+	obj = isl_aff_align_params(obj, isl_set_get_space(set));
+
+	res = isl_set_opt_aligned(set, max, obj, opt);
+
+	isl_set_free(set);
+	isl_aff_free(obj);
+
+	return res;
+}
+
+enum isl_lp_result isl_basic_set_max(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_basic_set_opt(bset, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_set_opt(set, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_min(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_set_opt(set, 0, obj, opt);
+}
+
+/* Convert the result of a function that returns an isl_lp_result
+ * to an isl_val.  The numerator of "v" is set to the optimal value
+ * if lp_res is isl_lp_ok.  "max" is set if a maximum was computed.
+ *
+ * Return "v" with denominator set to 1 if lp_res is isl_lp_ok.
+ * Return NULL on error.
+ * Return a NaN if lp_res is isl_lp_empty.
+ * Return infinity or negative infinity if lp_res is isl_lp_unbounded,
+ * depending on "max".
+ */
+static __isl_give isl_val *convert_lp_result(enum isl_lp_result lp_res,
+	__isl_take isl_val *v, int max)
+{
+	isl_ctx *ctx;
+
+	if (lp_res == isl_lp_ok) {
+		isl_int_set_si(v->d, 1);
+		return isl_val_normalize(v);
+	}
+	ctx = isl_val_get_ctx(v);
+	isl_val_free(v);
+	if (lp_res == isl_lp_error)
+		return NULL;
+	if (lp_res == isl_lp_empty)
+		return isl_val_nan(ctx);
+	if (max)
+		return isl_val_infty(ctx);
+	else
+		return isl_val_neginfty(ctx);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_basic_set_opt_val(__isl_keep isl_basic_set *bset,
+	int max, __isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_basic_set_opt(bset, max, obj, &res->n);
+	return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_val(bset, 1, obj);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_set_opt_val(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!set || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_set_opt(set, max, obj, &res->n);
+	return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the minimum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj)
+{
+	return isl_set_opt_val(set, 0, obj);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj)
+{
+	return isl_set_opt_val(set, 1, obj);
+}

Added: polly/trunk/lib/External/isl/isl_ilp_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ilp_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ilp_private.h (added)
+++ polly/trunk/lib/External/isl/isl_ilp_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,11 @@
+#ifndef ISL_ILP_PRIVATE_H
+#define ISL_ILP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/set.h>
+
+enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_imath.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_imath.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_imath.c (added)
+++ polly/trunk/lib/External/isl/isl_imath.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,53 @@
+#include <isl_int.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash)
+{
+	unsigned const char *data = (unsigned char *)v->digits;
+	unsigned const char *end = data + v->used * sizeof(v->digits[0]);
+
+	if (v->sign == 1)
+		isl_hash_byte(hash, 0xFF);
+	for (; data < end; ++data)
+		isl_hash_byte(hash, *data);
+	return hash;
+}
+
+/* Try a standard conversion that fits into a long.
+ */
+int isl_imath_fits_slong_p(mp_int op)
+{
+	unsigned long out;
+	mp_result res = mp_int_to_int(op, &out);
+	return res == MP_OK;
+}
+
+/* Try a standard conversion that fits into an unsigned long.
+ */
+int isl_imath_fits_ulong_p(mp_int op)
+{
+	unsigned long out;
+	mp_result res = mp_int_to_uint(op, &out);
+	return res == MP_OK;
+}
+
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+	isl_int temp;
+	isl_int_init(temp);
+
+	isl_int_set_ui(temp, op2);
+	isl_int_addmul(rop, op1, temp);
+
+	isl_int_clear(temp);
+}
+
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+	isl_int temp;
+	isl_int_init(temp);
+
+	isl_int_set_ui(temp, op2);
+	isl_int_submul(rop, op1, temp);
+
+	isl_int_clear(temp);
+}

Added: polly/trunk/lib/External/isl/isl_imath.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_imath.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_imath.h (added)
+++ polly/trunk/lib/External/isl/isl_imath.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,8 @@
+#include <imath.h>
+#include <gmp_compat.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+int isl_imath_fits_ulong_p(mp_int op);
+int isl_imath_fits_slong_p(mp_int op);
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2);
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2);

Added: polly/trunk/lib/External/isl/isl_input.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_input.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_input.c (added)
+++ polly/trunk/lib/External/isl/isl_input.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,3370 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_stream_private.h>
+#include <isl/obj.h>
+#include "isl_polynomial_private.h"
+#include <isl/union_map.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl/list.h>
+#include <isl_val_private.h>
+
+struct variable {
+	char    	    	*name;
+	int	     		 pos;
+	struct variable		*next;
+};
+
+struct vars {
+	struct isl_ctx	*ctx;
+	int		 n;
+	struct variable	*v;
+};
+
+static struct vars *vars_new(struct isl_ctx *ctx)
+{
+	struct vars *v;
+	v = isl_alloc_type(ctx, struct vars);
+	if (!v)
+		return NULL;
+	v->ctx = ctx;
+	v->n = 0;
+	v->v = NULL;
+	return v;
+}
+
+static void variable_free(struct variable *var)
+{
+	while (var) {
+		struct variable *next = var->next;
+		free(var->name);
+		free(var);
+		var = next;
+	}
+}
+
+static void vars_free(struct vars *v)
+{
+	if (!v)
+		return;
+	variable_free(v->v);
+	free(v);
+}
+
+static void vars_drop(struct vars *v, int n)
+{
+	struct variable *var;
+
+	if (!v || !v->v)
+		return;
+
+	v->n -= n;
+
+	var = v->v;
+	while (--n >= 0) {
+		struct variable *next = var->next;
+		free(var->name);
+		free(var);
+		var = next;
+	}
+	v->v = var;
+}
+
+static struct variable *variable_new(struct vars *v, const char *name, int len,
+				int pos)
+{
+	struct variable *var;
+	var = isl_calloc_type(v->ctx, struct variable);
+	if (!var)
+		goto error;
+	var->name = strdup(name);
+	var->name[len] = '\0';
+	var->pos = pos;
+	var->next = v->v;
+	return var;
+error:
+	variable_free(v->v);
+	return NULL;
+}
+
+static int vars_pos(struct vars *v, const char *s, int len)
+{
+	int pos;
+	struct variable *q;
+
+	if (len == -1)
+		len = strlen(s);
+	for (q = v->v; q; q = q->next) {
+		if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0')
+			break;
+	}
+	if (q)
+		pos = q->pos;
+	else {
+		pos = v->n;
+		v->v = variable_new(v, s, len, v->n);
+		if (!v->v)
+			return -1;
+		v->n++;
+	}
+	return pos;
+}
+
+static int vars_add_anon(struct vars *v)
+{
+	v->v = variable_new(v, "", 0, v->n);
+
+	if (!v->v)
+		return -1;
+	v->n++;
+
+	return 0;
+}
+
+/* Obtain next token, with some preprocessing.
+ * In particular, evaluate expressions of the form x^y,
+ * with x and y values.
+ */
+static struct isl_token *next_token(struct isl_stream *s)
+{
+	struct isl_token *tok, *tok2;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE)
+		return tok;
+	if (!isl_stream_eat_if_available(s, '^'))
+		return tok;
+	tok2 = isl_stream_next_token(s);
+	if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok2, "expecting constant value");
+		goto error;
+	}
+
+	isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
+
+	isl_token_free(tok2);
+	return tok;
+error:
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return NULL;
+}
+
+/* Read an isl_val from "s".
+ *
+ * The following token sequences are recognized
+ *
+ *	"infty"		->	infty
+ *	"-" "infty"	->	-infty
+ *	"NaN"		->	NaN
+ *	n "/" d		->	n/d
+ *	v		->	v
+ *
+ * where n, d and v are integer constants.
+ */
+__isl_give isl_val *isl_stream_read_val(struct isl_stream *s)
+{
+	struct isl_token *tok = NULL;
+	struct isl_token *tok2 = NULL;
+	isl_val *val;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	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 (tok->type == ISL_TOKEN_NAN) {
+		isl_token_free(tok);
+		return isl_val_nan(s->ctx);
+	}
+	if (tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting value");
+		goto error;
+	}
+
+	if (isl_stream_eat_if_available(s, '/')) {
+		tok2 = next_token(s);
+		if (!tok2) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok2->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok2, "expecting value");
+			goto error;
+		}
+		val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v);
+		val = isl_val_normalize(val);
+	} else {
+		val = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+	}
+
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return val;
+error:
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return NULL;
+}
+
+/* Read an isl_val from "str".
+ */
+struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_val *val;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	val = isl_stream_read_val(s);
+	isl_stream_free(s);
+	return val;
+}
+
+static int accept_cst_factor(struct 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_mul(*f, *f, tok->u.v);
+
+	isl_token_free(tok);
+
+	if (isl_stream_eat_if_available(s, '*'))
+		return accept_cst_factor(s, f);
+
+	return 0;
+error:
+	isl_token_free(tok);
+	return -1;
+}
+
+/* Given an affine expression aff, return an affine expression
+ * for aff % d, with d the next token on the stream, which is
+ * assumed to be a constant.
+ *
+ * We introduce an integer division q = [aff/d] and the result
+ * is set to aff - d q.
+ */
+static __isl_give isl_pw_aff *affine_mod(struct isl_stream *s,
+	struct vars *v, __isl_take isl_pw_aff *aff)
+{
+	struct isl_token *tok;
+	isl_pw_aff *q;
+
+	tok = next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting constant value");
+		goto error;
+	}
+
+	q = isl_pw_aff_copy(aff);
+	q = isl_pw_aff_scale_down(q, tok->u.v);
+	q = isl_pw_aff_floor(q);
+	q = isl_pw_aff_scale(q, tok->u.v);
+
+	aff = isl_pw_aff_sub(aff, q);
+
+	isl_token_free(tok);
+	return aff;
+error:
+	isl_pw_aff_free(aff);
+	isl_token_free(tok);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s,
+	__isl_take isl_space *space, struct vars *v);
+static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v);
+
+static __isl_give isl_pw_aff *accept_minmax(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok;
+	isl_pw_aff_list *list = NULL;
+	int min;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	min = tok->type == ISL_TOKEN_MIN;
+	isl_token_free(tok);
+
+	if (isl_stream_eat(s, '('))
+		goto error;
+
+	list = accept_affine_list(s, isl_space_copy(dim), v);
+	if (!list)
+		goto error;
+
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	isl_space_free(dim);
+	return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list);
+error:
+	isl_space_free(dim);
+	isl_pw_aff_list_free(list);
+	return NULL;
+}
+
+/* Is "tok" the start of an integer division?
+ */
+static int is_start_of_div(struct isl_token *tok)
+{
+	if (!tok)
+		return 0;
+	if (tok->type == '[')
+		return 1;
+	if (tok->type == ISL_TOKEN_FLOOR)
+		return 1;
+	if (tok->type == ISL_TOKEN_CEIL)
+		return 1;
+	if (tok->type == ISL_TOKEN_FLOORD)
+		return 1;
+	if (tok->type == ISL_TOKEN_CEILD)
+		return 1;
+	return 0;
+}
+
+/* Read an integer division from "s" and return it as an isl_pw_aff.
+ *
+ * The integer division can be of the form
+ *
+ *	[<affine expression>]
+ *	floor(<affine expression>)
+ *	ceil(<affine expression>)
+ *	floord(<affine expression>,<denominator>)
+ *	ceild(<affine expression>,<denominator>)
+ */
+static __isl_give isl_pw_aff *accept_div(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok;
+	int f = 0;
+	int c = 0;
+	int extra = 0;
+	isl_pw_aff *pwaff = NULL;
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD))
+		extra = f = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD))
+		extra = c = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR))
+		f = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL))
+		c = 1;
+	if (f || c) {
+		if (isl_stream_eat(s, '('))
+			goto error;
+	} else {
+		if (isl_stream_eat(s, '['))
+			goto error;
+	}
+
+	pwaff = accept_affine(s, isl_space_copy(dim), v);
+
+	if (extra) {
+		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;
+		}
+		isl_pw_aff_scale_down(pwaff,  tok->u.v);
+		isl_token_free(tok);
+	}
+
+	if (c)
+		pwaff = isl_pw_aff_ceil(pwaff);
+	else
+		pwaff = isl_pw_aff_floor(pwaff);
+
+	if (f || c) {
+		if (isl_stream_eat(s, ')'))
+			goto error;
+	} else {
+		if (isl_stream_eat(s, ']'))
+			goto error;
+	}
+
+	isl_space_free(dim);
+	return pwaff;
+error:
+	isl_space_free(dim);
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine_factor(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok = NULL;
+	isl_pw_aff *res = NULL;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+
+	if (tok->type == ISL_TOKEN_AFF) {
+		res = isl_pw_aff_copy(tok->u.pwaff);
+		isl_token_free(tok);
+	} else if (tok->type == ISL_TOKEN_IDENT) {
+		int n = v->n;
+		int pos = vars_pos(v, tok->u.s, -1);
+		isl_aff *aff;
+
+		if (pos < 0)
+			goto error;
+		if (pos >= n) {
+			vars_drop(v, v->n - n);
+			isl_stream_error(s, tok, "unknown identifier");
+			goto error;
+		}
+
+		aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(dim)));
+		if (!aff)
+			goto error;
+		isl_int_set_si(aff->v->el[2 + pos], 1);
+		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, '*')) {
+			res = accept_affine_factor(s, isl_space_copy(dim), v);
+			res = isl_pw_aff_scale(res, tok->u.v);
+		} else {
+			isl_local_space *ls;
+			isl_aff *aff;
+			ls = isl_local_space_from_space(isl_space_copy(dim));
+			aff = isl_aff_zero_on_domain(ls);
+			aff = isl_aff_add_constant(aff, tok->u.v);
+			res = isl_pw_aff_from_aff(aff);
+		}
+		isl_token_free(tok);
+	} else if (tok->type == '(') {
+		isl_token_free(tok);
+		tok = NULL;
+		res = accept_affine(s, isl_space_copy(dim), v);
+		if (!res)
+			goto error;
+		if (isl_stream_eat(s, ')'))
+			goto error;
+	} else if (is_start_of_div(tok)) {
+		isl_stream_push_token(s, tok);
+		tok = NULL;
+		res = accept_div(s, isl_space_copy(dim), v);
+	} else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) {
+		isl_stream_push_token(s, tok);
+		tok = NULL;
+		res = accept_minmax(s, isl_space_copy(dim), v);
+	} else {
+		isl_stream_error(s, tok, "expecting factor");
+		goto error;
+	}
+	if (isl_stream_eat_if_available(s, '%') ||
+	    isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) {
+		isl_space_free(dim);
+		return affine_mod(s, v, res);
+	}
+	if (isl_stream_eat_if_available(s, '*')) {
+		isl_int f;
+		isl_int_init(f);
+		isl_int_set_si(f, 1);
+		if (accept_cst_factor(s, &f) < 0) {
+			isl_int_clear(f);
+			goto error2;
+		}
+		res = isl_pw_aff_scale(res, f);
+		isl_int_clear(f);
+	}
+	if (isl_stream_eat_if_available(s, '/')) {
+		isl_int f;
+		isl_int_init(f);
+		isl_int_set_si(f, 1);
+		if (accept_cst_factor(s, &f) < 0) {
+			isl_int_clear(f);
+			goto error2;
+		}
+		res = isl_pw_aff_scale_down(res, f);
+		isl_int_clear(f);
+	}
+
+	isl_space_free(dim);
+	return res;
+error:
+	isl_token_free(tok);
+error2:
+	isl_pw_aff_free(res);
+	isl_space_free(dim);
+	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.
+ */
+static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space)
+{
+	isl_local_space *ls;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	return isl_pw_aff_nan_on_domain(ls);
+}
+
+static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s,
+	__isl_take isl_space *space, struct vars *v)
+{
+	struct isl_token *tok = NULL;
+	isl_local_space *ls;
+	isl_pw_aff *res;
+	int sign = 1;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
+	if (!res)
+		goto error;
+
+	for (;;) {
+		tok = next_token(s);
+		if (!tok) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok->type == '-') {
+			sign = -sign;
+			isl_token_free(tok);
+			continue;
+		}
+		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_AFF) {
+			isl_pw_aff *term;
+			isl_stream_push_token(s, tok);
+			tok = NULL;
+			term = accept_affine_factor(s,
+						    isl_space_copy(space), v);
+			if (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 {
+				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 {
+			isl_stream_error(s, tok, "unexpected isl_token");
+			isl_stream_push_token(s, tok);
+			isl_pw_aff_free(res);
+			isl_space_free(space);
+			return NULL;
+		}
+		isl_token_free(tok);
+
+		tok = next_token(s);
+		if (tok && tok->type == '-') {
+			sign = -sign;
+			isl_token_free(tok);
+		} else if (tok && tok->type == '+') {
+			/* nothing */
+			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);
+			break;
+		}
+	}
+
+	isl_space_free(space);
+	return res;
+error:
+	isl_space_free(space);
+	isl_token_free(tok);
+	isl_pw_aff_free(res);
+	return NULL;
+}
+
+static int is_comparator(struct isl_token *tok)
+{
+	if (!tok)
+		return 0;
+
+	switch (tok->type) {
+	case ISL_TOKEN_LT:
+	case ISL_TOKEN_GT:
+	case ISL_TOKEN_LE:
+	case ISL_TOKEN_GE:
+	case ISL_TOKEN_NE:
+	case '=':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static __isl_give isl_map *read_formula(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational);
+static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v, int rational);
+
+/* Accept a ternary operator, given the first argument.
+ */
+static __isl_give isl_pw_aff *accept_ternary(struct isl_stream *s,
+	__isl_take isl_map *cond, struct vars *v, int rational)
+{
+	isl_space *dim;
+	isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond;
+
+	if (!cond)
+		return NULL;
+
+	if (isl_stream_eat(s, '?'))
+		goto error;
+
+	dim = isl_space_wrap(isl_map_get_space(cond));
+	pwaff1 = accept_extended_affine(s, dim, v, rational);
+	if (!pwaff1)
+		goto error;
+
+	if (isl_stream_eat(s, ':'))
+		goto error;
+
+	dim = isl_pw_aff_get_domain_space(pwaff1);
+	pwaff2 = accept_extended_affine(s, dim, v, rational);
+	if (!pwaff1)
+		goto error;
+
+	pa_cond = isl_set_indicator_function(isl_map_wrap(cond));
+	return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2);
+error:
+	isl_map_free(cond);
+	isl_pw_aff_free(pwaff1);
+	isl_pw_aff_free(pwaff2);
+	return NULL;
+}
+
+/* Set *line and *col to those of the next token, if any.
+ */
+static void set_current_line_col(struct isl_stream *s, int *line, int *col)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return;
+
+	*line = tok->line;
+	*col = tok->col;
+	isl_stream_push_token(s, tok);
+}
+
+/* Push a token encapsulating "pa" onto "s", with the given
+ * line and column.
+ */
+static int push_aff(struct isl_stream *s, int line, int col,
+	__isl_take isl_pw_aff *pa)
+{
+	struct isl_token *tok;
+
+	tok = isl_token_new(s->ctx, line, col, 0);
+	if (!tok)
+		goto error;
+	tok->type = ISL_TOKEN_AFF;
+	tok->u.pwaff = pa;
+	isl_stream_push_token(s, tok);
+
+	return 0;
+error:
+	isl_pw_aff_free(pa);
+	return -1;
+}
+
+/* Accept an affine expression that may involve ternary operators.
+ * We first read an affine expression.
+ * If it is not followed by a comparison operator, we simply return it.
+ * Otherwise, we assume the affine expression is part of the first
+ * argument of a ternary operator and try to parse that.
+ */
+static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v, int rational)
+{
+	isl_space *space;
+	isl_map *cond;
+	isl_pw_aff *pwaff;
+	struct isl_token *tok;
+	int line = -1, col = -1;
+	int is_comp;
+
+	set_current_line_col(s, &line, &col);
+
+	pwaff = accept_affine(s, dim, v);
+	if (rational)
+		pwaff = isl_pw_aff_set_rational(pwaff);
+	if (!pwaff)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return isl_pw_aff_free(pwaff);
+
+	is_comp = is_comparator(tok);
+	isl_stream_push_token(s, tok);
+	if (!is_comp)
+		return pwaff;
+
+	space = isl_pw_aff_get_domain_space(pwaff);
+	cond = isl_map_universe(isl_space_unwrap(space));
+
+	if (push_aff(s, line, col, pwaff) < 0)
+		cond = isl_map_free(cond);
+	if (!cond)
+		return NULL;
+
+	cond = read_formula(s, v, cond, rational);
+
+	return accept_ternary(s, cond, v, rational);
+}
+
+static __isl_give isl_map *read_var_def(struct isl_stream *s,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational)
+{
+	isl_pw_aff *def;
+	int pos;
+	isl_map *def_map;
+
+	if (type == isl_dim_param)
+		pos = isl_map_dim(map, isl_dim_param);
+	else {
+		pos = isl_map_dim(map, isl_dim_in);
+		if (type == isl_dim_out)
+			pos += isl_map_dim(map, isl_dim_out);
+		type = isl_dim_in;
+	}
+	--pos;
+
+	def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)),
+					v, rational);
+	def_map = isl_map_from_pw_aff(def);
+	def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0);
+	def_map = isl_set_unwrap(isl_map_domain(def_map));
+
+	map = isl_map_intersect(map, def_map);
+
+	return map;
+}
+
+static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	isl_pw_aff *pwaff;
+	isl_pw_aff_list *list;
+	struct isl_token *tok = NULL;
+
+	pwaff = accept_affine(s, isl_space_copy(dim), v);
+	list = isl_pw_aff_list_from_pw_aff(pwaff);
+	if (!list)
+		goto error;
+
+	for (;;) {
+		tok = isl_stream_next_token(s);
+		if (!tok) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok->type != ',') {
+			isl_stream_push_token(s, tok);
+			break;
+		}
+		isl_token_free(tok);
+
+		pwaff = accept_affine(s, isl_space_copy(dim), v);
+		list = isl_pw_aff_list_concat(list,
+				isl_pw_aff_list_from_pw_aff(pwaff));
+		if (!list)
+			goto error;
+	}
+
+	isl_space_free(dim);
+	return list;
+error:
+	isl_space_free(dim);
+	isl_pw_aff_list_free(list);
+	return NULL;
+}
+
+static __isl_give isl_map *read_defined_var_list(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok;
+
+	while ((tok = isl_stream_next_token(s)) != NULL) {
+		int p;
+		int n = v->n;
+
+		if (tok->type != ISL_TOKEN_IDENT)
+			break;
+
+		p = vars_pos(v, tok->u.s, -1);
+		if (p < 0)
+			goto error;
+		if (p < n) {
+			isl_stream_error(s, tok, "expecting unique identifier");
+			goto error;
+		}
+
+		map = isl_map_add_dims(map, isl_dim_out, 1);
+
+		isl_token_free(tok);
+		tok = isl_stream_next_token(s);
+		if (tok && tok->type == '=') {
+			isl_token_free(tok);
+			map = read_var_def(s, map, isl_dim_out, v, rational);
+			tok = isl_stream_next_token(s);
+		}
+
+		if (!tok || tok->type != ',')
+			break;
+
+		isl_token_free(tok);
+	}
+	if (tok)
+		isl_stream_push_token(s, tok);
+
+	return map;
+error:
+	isl_token_free(tok);
+	isl_map_free(map);
+	return NULL;
+}
+
+static int next_is_tuple(struct isl_stream *s)
+{
+	struct isl_token *tok;
+	int is_tuple;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == '[') {
+		isl_stream_push_token(s, tok);
+		return 1;
+	}
+	if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) {
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	is_tuple = isl_stream_next_token_is(s, '[');
+
+	isl_stream_push_token(s, tok);
+
+	return is_tuple;
+}
+
+/* Allocate an initial tuple with zero dimensions and an anonymous,
+ * unstructured space.
+ * A tuple is represented as an isl_multi_pw_aff.
+ * The range space is the space of the tuple.
+ * The domain space is an anonymous space
+ * with a dimension for each variable in the set of variables in "v".
+ * If a given dimension is not defined in terms of earlier dimensions in
+ * the input, then the corresponding isl_pw_aff is set equal to one time
+ * the variable corresponding to the dimension being defined.
+ */
+static __isl_give isl_multi_pw_aff *tuple_alloc(struct vars *v)
+{
+	return isl_multi_pw_aff_alloc(isl_space_alloc(v->ctx, 0, v->n, 0));
+}
+
+/* Is "pa" an expression in term of earlier dimensions?
+ * The alternative is that the dimension is defined to be equal to itself,
+ * meaning that it has a universe domain and an expression that depends
+ * on itself.  "i" is the position of the expression in a sequence
+ * of "n" expressions.  The final dimensions of "pa" correspond to
+ * these "n" expressions.
+ */
+static int pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n)
+{
+	isl_aff *aff;
+
+	if (!pa)
+		return -1;
+	if (pa->n != 1)
+		return 1;
+	if (!isl_set_plain_is_universe(pa->p[0].set))
+		return 1;
+
+	aff = pa->p[0].aff;
+	if (isl_int_is_zero(aff->v->el[aff->v->size - n + i]))
+		return 1;
+	return 0;
+}
+
+/* Does the tuple contain any dimensions that are defined
+ * in terms of earlier dimensions?
+ */
+static int tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple)
+{
+	int i, n;
+	int has_expr = 0;
+	isl_pw_aff *pa;
+
+	if (!tuple)
+		return -1;
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		has_expr = pw_aff_is_expr(pa, i, n);
+		isl_pw_aff_free(pa);
+		if (has_expr < 0 || has_expr)
+			break;
+	}
+
+	return has_expr;
+}
+
+/* Add a dimension to the given tuple.
+ * The dimension is initially undefined, so it is encoded
+ * as one times itself.
+ */
+static __isl_give isl_multi_pw_aff *tuple_add_dim(
+	__isl_take isl_multi_pw_aff *tuple, struct vars *v)
+{
+	isl_space *space;
+	isl_aff *aff;
+	isl_pw_aff *pa;
+
+	tuple = isl_multi_pw_aff_add_dims(tuple, isl_dim_in, 1);
+	space = isl_multi_pw_aff_get_domain_space(tuple);
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n, 1);
+	pa = isl_pw_aff_from_aff(aff);
+	tuple = isl_multi_pw_aff_flat_range_product(tuple,
+					    isl_multi_pw_aff_from_pw_aff(pa));
+
+	return tuple;
+}
+
+/* Set the name of dimension "pos" in "tuple" to "name".
+ * During printing, we add primes if the same name appears more than once
+ * to distinguish the occurrences.  Here, we remove those primes from "name"
+ * before setting the name of the dimension.
+ */
+static __isl_give isl_multi_pw_aff *tuple_set_dim_name(
+	__isl_take isl_multi_pw_aff *tuple, int pos, char *name)
+{
+	char *prime;
+
+	if (!name)
+		return tuple;
+
+	prime = strchr(name, '\'');
+	if (prime)
+		*prime = '\0';
+	tuple = isl_multi_pw_aff_set_dim_name(tuple, isl_dim_set, pos, name);
+	if (prime)
+		*prime = '\'';
+
+	return tuple;
+}
+
+/* Accept a piecewise affine expression.
+ *
+ * At the outer level, the piecewise affine expression may be of the form
+ *
+ *	aff1 : condition1; aff2 : conditions2; ...
+ *
+ * or simply
+ *
+ *	aff
+ *
+ * each of the affine expressions may in turn include ternary operators.
+ *
+ * There may be parentheses around some subexpression of "aff1"
+ * around "aff1" itself, around "aff1 : condition1" and/or
+ * around the entire piecewise affine expression.
+ * We therefore remove the opening parenthesis (if any) from the stream
+ * in case the closing parenthesis follows the colon, but if the closing
+ * parenthesis is the first thing in the stream after the parsed affine
+ * expression, we push the parsed expression onto the stream and parse
+ * again in case the parentheses enclose some subexpression of "aff1".
+ */
+static __isl_give isl_pw_aff *accept_piecewise_affine(struct isl_stream *s,
+	__isl_take isl_space *space, struct vars *v, int rational)
+{
+	isl_pw_aff *res;
+	isl_space *res_space;
+
+	res_space = isl_space_from_domain(isl_space_copy(space));
+	res_space = isl_space_add_dims(res_space, isl_dim_out, 1);
+	res = isl_pw_aff_empty(res_space);
+	do {
+		isl_pw_aff *pa;
+		int seen_paren;
+		int line = -1, col = -1;
+
+		set_current_line_col(s, &line, &col);
+		seen_paren = isl_stream_eat_if_available(s, '(');
+		if (seen_paren)
+			pa = accept_piecewise_affine(s, isl_space_copy(space),
+							v, rational);
+		else
+			pa = accept_extended_affine(s, isl_space_copy(space),
+							v, rational);
+		if (seen_paren && isl_stream_eat_if_available(s, ')')) {
+			seen_paren = 0;
+			if (push_aff(s, line, col, pa) < 0)
+				goto error;
+			pa = accept_extended_affine(s, isl_space_copy(space),
+							v, rational);
+		}
+		if (isl_stream_eat_if_available(s, ':')) {
+			isl_space *dom_space;
+			isl_set *dom;
+
+			dom_space = isl_pw_aff_get_domain_space(pa);
+			dom = isl_set_universe(dom_space);
+			dom = read_formula(s, v, dom, rational);
+			pa = isl_pw_aff_intersect_domain(pa, dom);
+		}
+
+		res = isl_pw_aff_union_add(res, pa);
+
+		if (seen_paren && isl_stream_eat(s, ')'))
+			goto error;
+	} while (isl_stream_eat_if_available(s, ';'));
+
+	isl_space_free(space);
+
+	return res;
+error:
+	isl_space_free(space);
+	return isl_pw_aff_free(res);
+}
+
+/* Read an affine expression from "s" and replace the definition
+ * of dimension "pos" in "tuple" by this expression.
+ *
+ * accept_extended_affine requires a wrapped space as input.
+ * The domain space of "tuple", on the other hand is an anonymous space,
+ * so we have to adjust the space of the isl_pw_aff before adding it
+ * to "tuple".
+ */
+static __isl_give isl_multi_pw_aff *read_tuple_var_def(struct isl_stream *s,
+	__isl_take isl_multi_pw_aff *tuple, int pos, struct vars *v,
+	int rational)
+{
+	isl_space *space;
+	isl_pw_aff *def;
+
+	space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0));
+
+	def = accept_piecewise_affine(s, space, v, rational);
+
+	space = isl_space_set_alloc(s->ctx, 0, v->n);
+	def = isl_pw_aff_reset_domain_space(def, space);
+	tuple = isl_multi_pw_aff_set_pw_aff(tuple, pos, def);
+
+	return tuple;
+}
+
+/* Read a list of variables and/or affine expressions and return the list
+ * as an isl_multi_pw_aff.
+ * The elements in the list are separated by either "," or "][".
+ * If "comma" is set then only "," is allowed.
+ */
+static __isl_give isl_multi_pw_aff *read_tuple_var_list(struct isl_stream *s,
+	struct vars *v, int rational, int comma)
+{
+	int i = 0;
+	struct isl_token *tok;
+	isl_multi_pw_aff *res;
+
+	res = tuple_alloc(v);
+
+	if (isl_stream_next_token_is(s, ']'))
+		return res;
+
+	while ((tok = next_token(s)) != NULL) {
+		int new_name = 0;
+
+		res = tuple_add_dim(res, v);
+
+		if (tok->type == ISL_TOKEN_IDENT) {
+			int n = v->n;
+			int p = vars_pos(v, tok->u.s, -1);
+			if (p < 0)
+				goto error;
+			new_name = p >= n;
+		}
+
+		if (tok->type == '*') {
+			if (vars_add_anon(v) < 0)
+				goto error;
+			isl_token_free(tok);
+		} else if (new_name) {
+			res = tuple_set_dim_name(res, i, v->v->name);
+			isl_token_free(tok);
+			if (isl_stream_eat_if_available(s, '='))
+				res = read_tuple_var_def(s, res, i, v,
+							rational);
+		} else {
+			isl_stream_push_token(s, tok);
+			tok = NULL;
+			if (vars_add_anon(v) < 0)
+				goto error;
+			res = read_tuple_var_def(s, res, i, v, rational);
+		}
+
+		tok = isl_stream_next_token(s);
+		if (!comma && tok && tok->type == ']' &&
+		    isl_stream_next_token_is(s, '[')) {
+			isl_token_free(tok);
+			tok = isl_stream_next_token(s);
+		} else if (!tok || tok->type != ',')
+			break;
+
+		isl_token_free(tok);
+		i++;
+	}
+	if (tok)
+		isl_stream_push_token(s, tok);
+
+	return res;
+error:
+	isl_token_free(tok);
+	return isl_multi_pw_aff_free(res);
+}
+
+/* Read a tuple and represent it as an isl_multi_pw_aff.  See tuple_alloc.
+ */
+static __isl_give isl_multi_pw_aff *read_tuple(struct isl_stream *s,
+	struct vars *v, int rational, int comma)
+{
+	struct isl_token *tok;
+	char *name = NULL;
+	isl_multi_pw_aff *res = NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) {
+		name = strdup(tok->u.s);
+		isl_token_free(tok);
+		if (!name)
+			goto error;
+	} else
+		isl_stream_push_token(s, tok);
+	if (isl_stream_eat(s, '['))
+		goto error;
+	if (next_is_tuple(s)) {
+		isl_multi_pw_aff *out;
+		int n;
+		res = read_tuple(s, v, rational, comma);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+		out = read_tuple(s, v, rational, comma);
+		n = isl_multi_pw_aff_dim(out, isl_dim_out);
+		res = isl_multi_pw_aff_add_dims(res, isl_dim_in, n);
+		res = isl_multi_pw_aff_range_product(res, out);
+	} else
+		res = read_tuple_var_list(s, v, rational, comma);
+	if (isl_stream_eat(s, ']'))
+		goto error;
+
+	if (name) {
+		res = isl_multi_pw_aff_set_tuple_name(res, isl_dim_out, name);
+		free(name);
+	}
+
+	return res;
+error:
+	free(name);
+	return isl_multi_pw_aff_free(res);
+}
+
+/* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map".
+ * We first create the appropriate space in "map" based on the range
+ * space of this isl_multi_pw_aff.  Then, we add equalities based
+ * on the affine expressions.  These live in an anonymous space,
+ * however, so we first need to reset the space to that of "map".
+ */
+static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_space *space = NULL;
+
+	if (!map || !tuple)
+		goto error;
+	ctx = isl_multi_pw_aff_get_ctx(tuple);
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+	if (!space)
+		goto error;
+
+	if (type == isl_dim_param) {
+		if (isl_space_has_tuple_name(space, isl_dim_set) ||
+		    isl_space_is_wrapping(space)) {
+			isl_die(ctx, isl_error_invalid,
+				"parameter tuples cannot be named or nested",
+				goto error);
+		}
+		map = isl_map_add_dims(map, type, n);
+		for (i = 0; i < n; ++i) {
+			isl_id *id;
+			if (!isl_space_has_dim_name(space, isl_dim_set, i))
+				isl_die(ctx, isl_error_invalid,
+					"parameters must be named",
+					goto error);
+			id = isl_space_get_dim_id(space, isl_dim_set, i);
+			map = isl_map_set_dim_id(map, isl_dim_param, i, id);
+		}
+	} else if (type == isl_dim_in) {
+		isl_set *set;
+
+		set = isl_set_universe(isl_space_copy(space));
+		if (rational)
+			set = isl_set_set_rational(set);
+		set = isl_set_intersect_params(set, isl_map_params(map));
+		map = isl_map_from_domain(set);
+	} else {
+		isl_set *set;
+
+		set = isl_set_universe(isl_space_copy(space));
+		if (rational)
+			set = isl_set_set_rational(set);
+		map = isl_map_from_domain_and_range(isl_map_domain(map), set);
+	}
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_space *space;
+		isl_aff *aff;
+		isl_set *set;
+		isl_map *map_i;
+
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		space = isl_pw_aff_get_domain_space(pa);
+		aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+		aff = isl_aff_add_coefficient_si(aff,
+						isl_dim_in, v->n - n + i, -1);
+		pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff));
+		if (rational)
+			pa = isl_pw_aff_set_rational(pa);
+		set = isl_pw_aff_zero_set(pa);
+		map_i = isl_map_from_range(set);
+		map_i = isl_map_reset_space(map_i, isl_map_get_space(map));
+		map = isl_map_intersect(map, map_i);
+	}
+
+	isl_space_free(space);
+	isl_multi_pw_aff_free(tuple);
+	return map;
+error:
+	isl_space_free(space);
+	isl_multi_pw_aff_free(tuple);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Read a tuple from "s" and add it to "map".
+ * The tuple is initially represented as an isl_multi_pw_aff and
+ * then added to "map".
+ */
+static __isl_give isl_map *read_map_tuple(struct isl_stream *s,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational, int comma)
+{
+	isl_multi_pw_aff *tuple;
+
+	tuple = read_tuple(s, v, rational, comma);
+	if (!tuple)
+		return isl_map_free(map);
+
+	return map_from_tuple(tuple, map, type, v, rational);
+}
+
+static __isl_give isl_set *construct_constraints(
+	__isl_take isl_set *set, int type,
+	__isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right,
+	int rational)
+{
+	isl_set *cond;
+
+	left = isl_pw_aff_list_copy(left);
+	right = isl_pw_aff_list_copy(right);
+	if (rational) {
+		left = isl_pw_aff_list_set_rational(left);
+		right = isl_pw_aff_list_set_rational(right);
+	}
+	if (type == ISL_TOKEN_LE)
+		cond = isl_pw_aff_list_le_set(left, right);
+	else if (type == ISL_TOKEN_GE)
+		cond = isl_pw_aff_list_ge_set(left, right);
+	else if (type == ISL_TOKEN_LT)
+		cond = isl_pw_aff_list_lt_set(left, right);
+	else if (type == ISL_TOKEN_GT)
+		cond = isl_pw_aff_list_gt_set(left, right);
+	else if (type == ISL_TOKEN_NE)
+		cond = isl_pw_aff_list_ne_set(left, right);
+	else
+		cond = isl_pw_aff_list_eq_set(left, right);
+
+	return isl_set_intersect(set, cond);
+}
+
+static __isl_give isl_map *add_constraint(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok = NULL;
+	isl_pw_aff_list *list1 = NULL, *list2 = NULL;
+	isl_set *set;
+
+	set = isl_map_wrap(map);
+	list1 = accept_affine_list(s, isl_set_get_space(set), v);
+	if (!list1)
+		goto error;
+	tok = isl_stream_next_token(s);
+	if (!is_comparator(tok)) {
+		isl_stream_error(s, tok, "missing operator");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		tok = NULL;
+		goto error;
+	}
+	for (;;) {
+		list2 = accept_affine_list(s, isl_set_get_space(set), v);
+		if (!list2)
+			goto error;
+
+		set = construct_constraints(set, tok->type, list1, list2,
+						rational);
+		isl_token_free(tok);
+		isl_pw_aff_list_free(list1);
+		list1 = list2;
+
+		tok = isl_stream_next_token(s);
+		if (!is_comparator(tok)) {
+			if (tok)
+				isl_stream_push_token(s, tok);
+			break;
+		}
+	}
+	isl_pw_aff_list_free(list1);
+
+	return isl_set_unwrap(set);
+error:
+	if (tok)
+		isl_token_free(tok);
+	isl_pw_aff_list_free(list1);
+	isl_pw_aff_list_free(list2);
+	isl_set_free(set);
+	return NULL;
+}
+
+static __isl_give isl_map *read_exists(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	int n = v->n;
+	int seen_paren = isl_stream_eat_if_available(s, '(');
+
+	map = isl_map_from_domain(isl_map_wrap(map));
+	map = read_defined_var_list(s, v, map, rational);
+
+	if (isl_stream_eat(s, ':'))
+		goto error;
+
+	map = read_formula(s, v, map, rational);
+	map = isl_set_unwrap(isl_map_domain(map));
+
+	vars_drop(v, v->n - n);
+	if (seen_paren && isl_stream_eat(s, ')'))
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Parse an expression between parentheses and push the result
+ * back on the stream.
+ *
+ * The parsed expression may be either an affine expression
+ * or a condition.  The first type is pushed onto the stream
+ * as an isl_pw_aff, while the second is pushed as an isl_map.
+ *
+ * If the initial token indicates the start of a condition,
+ * we parse it as such.
+ * Otherwise, we first parse an affine expression and push
+ * that onto the stream.  If the affine expression covers the
+ * entire expression between parentheses, we return.
+ * Otherwise, we assume that the affine expression is the
+ * start of a condition and continue parsing.
+ */
+static int resolve_paren_expr(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok, *tok2;
+	int line, col;
+	isl_pw_aff *pwaff;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != '(')
+		goto error;
+
+	if (isl_stream_next_token_is(s, '('))
+		if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+			goto error;
+
+	if (isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_NOT) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_TRUE) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_FALSE) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+		map = read_formula(s, v, map, rational);
+		if (isl_stream_eat(s, ')'))
+			goto error;
+		tok->type = ISL_TOKEN_MAP;
+		tok->u.map = map;
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	tok2 = isl_stream_next_token(s);
+	if (!tok2)
+		goto error;
+	line = tok2->line;
+	col = tok2->col;
+	isl_stream_push_token(s, tok2);
+
+	pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v);
+	if (!pwaff)
+		goto error;
+
+	tok2 = isl_token_new(s->ctx, line, col, 0);
+	if (!tok2)
+		goto error2;
+	tok2->type = ISL_TOKEN_AFF;
+	tok2->u.pwaff = pwaff;
+
+	if (isl_stream_eat_if_available(s, ')')) {
+		isl_stream_push_token(s, tok2);
+		isl_token_free(tok);
+		isl_map_free(map);
+		return 0;
+	}
+
+	isl_stream_push_token(s, tok2);
+
+	map = read_formula(s, v, map, rational);
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	tok->type = ISL_TOKEN_MAP;
+	tok->u.map = map;
+	isl_stream_push_token(s, tok);
+
+	return 0;
+error2:
+	isl_pw_aff_free(pwaff);
+error:
+	isl_token_free(tok);
+	isl_map_free(map);
+	return -1;
+}
+
+static __isl_give isl_map *read_conjunct(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	if (isl_stream_next_token_is(s, '('))
+		if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+			goto error;
+
+	if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+		struct isl_token *tok;
+		tok = isl_stream_next_token(s);
+		if (!tok)
+			goto error;
+		isl_map_free(map);
+		map = isl_map_copy(tok->u.map);
+		isl_token_free(tok);
+		return map;
+	}
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
+		return read_exists(s, v, map, rational);
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
+		return map;
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_map_empty(dim);
+	}
+		
+	return add_constraint(s, v, map, rational);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static __isl_give isl_map *read_conjuncts(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+	int negate;
+
+	negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+	res = read_conjunct(s, v, isl_map_copy(map), rational);
+	if (negate)
+		res = isl_map_subtract(isl_map_copy(map), res);
+
+	while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
+		isl_map *res_i;
+
+		negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+		res_i = read_conjunct(s, v, isl_map_copy(map), rational);
+		if (negate)
+			res = isl_map_subtract(res, res_i);
+		else
+			res = isl_map_intersect(res, res_i);
+	}
+
+	isl_map_free(map);
+	return res;
+}
+
+static struct isl_map *read_disjuncts(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+
+	if (isl_stream_next_token_is(s, '}')) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_map_universe(dim);
+	}
+
+	res = read_conjuncts(s, v, isl_map_copy(map), rational);
+	while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
+		isl_map *res_i;
+
+		res_i = read_conjuncts(s, v, isl_map_copy(map), rational);
+		res = isl_map_union(res, res_i);
+	}
+
+	isl_map_free(map);
+	return res;
+}
+
+/* Read a first order formula from "s", add the corresponding
+ * constraints to "map" and return the result.
+ *
+ * In particular, read a formula of the form
+ *
+ *	a
+ *
+ * or
+ *
+ *	a implies b
+ *
+ * where a and b are disjunctions.
+ *
+ * In the first case, map is replaced by
+ *
+ *	map \cap { [..] : a }
+ *
+ * In the second case, it is replaced by
+ *
+ *	(map \setminus { [..] : a}) \cup (map \cap { [..] : b })
+ */
+static __isl_give isl_map *read_formula(struct isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+
+	res = read_disjuncts(s, v, isl_map_copy(map), rational);
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) {
+		isl_map *res2;
+
+		res = isl_map_subtract(isl_map_copy(map), res);
+		res2 = read_disjuncts(s, v, map, rational);
+		res = isl_map_union(res, res2);
+	} else
+		isl_map_free(map);
+
+	return res;
+}
+
+static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
+{
+	if (pos < isl_basic_map_dim(bmap, isl_dim_out))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+			   isl_basic_map_dim(bmap, isl_dim_in) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_out);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_in))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_in);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_div))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+			   isl_basic_map_dim(bmap, isl_dim_in) +
+			   isl_basic_map_dim(bmap, isl_dim_out) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_div);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_param))
+		return 1 + pos;
+
+	return 0;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib_constraint(
+	struct isl_stream *s, __isl_take isl_basic_map *bmap)
+{
+	int j;
+	struct isl_token *tok;
+	int type;
+	int k;
+	isl_int *c;
+	unsigned nparam;
+	unsigned dim;
+
+	if (!bmap)
+		return NULL;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	dim = isl_basic_map_dim(bmap, isl_dim_out);
+
+	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 appear on new line");
+		isl_stream_push_token(s, tok);
+		goto error;
+	}
+
+	type = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	isl_assert(s->ctx, type == 0 || type == 1, goto error);
+	if (type == 0) {
+		k = isl_basic_map_alloc_equality(bmap);
+		c = bmap->eq[k];
+	} else {
+		k = isl_basic_map_alloc_inequality(bmap);
+		c = bmap->ineq[k];
+	}
+	if (k < 0)
+		goto error;
+
+	for (j = 0; j < 1 + isl_basic_map_total_dim(bmap); ++j) {
+		int 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);
+			goto error;
+		}
+		pos = polylib_pos_to_isl_pos(bmap, j);
+		isl_int_set(c[pos], tok->u.v);
+		isl_token_free(tok);
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib(struct isl_stream *s)
+{
+	int i;
+	struct isl_token *tok;
+	struct isl_token *tok2;
+	int n_row, n_col;
+	int on_new_line;
+	unsigned in = 0, out, local = 0;
+	struct isl_basic_map *bmap = NULL;
+	int nparam = 0;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	tok2 = isl_stream_next_token(s);
+	if (!tok2) {
+		isl_token_free(tok);
+		isl_stream_error(s, NULL, "unexpected EOF");
+		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_stream_error(s, NULL,
+				 "expecting constraint matrix dimensions");
+		return NULL;
+	}
+	n_row = isl_int_get_si(tok->u.v);
+	n_col = isl_int_get_si(tok2->u.v);
+	on_new_line = tok2->on_new_line;
+	isl_token_free(tok2);
+	isl_token_free(tok);
+	isl_assert(s->ctx, !on_new_line, return NULL);
+	isl_assert(s->ctx, n_row >= 0, return NULL);
+	isl_assert(s->ctx, n_col >= 2 + nparam, return NULL);
+	tok = isl_stream_next_token_on_same_line(s);
+	if (tok) {
+		if (tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of output dimensions");
+			isl_stream_push_token(s, tok);
+			goto error;
+		}
+		out = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		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);
+			goto error;
+		}
+		in = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of existentials");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		local = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of parameters");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		nparam = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+		if (n_col != 1 + out + in + local + nparam + 1) {
+			isl_stream_error(s, NULL,
+				    "dimensions don't match");
+			goto error;
+		}
+	} else
+		out = n_col - 2 - nparam;
+	bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row);
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < local; ++i) {
+		int k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local);
+	}
+
+	for (i = 0; i < n_row; ++i)
+		bmap = basic_map_read_polylib_constraint(s, bmap);
+
+	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);
+		goto error;
+	}
+
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static struct isl_map *map_read_polylib(struct isl_stream *s)
+{
+	struct isl_token *tok;
+	struct isl_token *tok2;
+	int i, n;
+	struct isl_map *map;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	tok2 = isl_stream_next_token_on_same_line(s);
+	if (tok2 && tok2->type == ISL_TOKEN_VALUE) {
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		return isl_map_from_basic_map(basic_map_read_polylib(s));
+	}
+	if (tok2) {
+		isl_stream_error(s, tok2, "unexpected token");
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		return NULL;
+	}
+	n = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	isl_assert(s->ctx, n >= 1, return NULL);
+
+	map = isl_map_from_basic_map(basic_map_read_polylib(s));
+
+	for (i = 1; map && i < n; ++i)
+		map = isl_map_union(map,
+			isl_map_from_basic_map(basic_map_read_polylib(s)));
+
+	return map;
+}
+
+static int optional_power(struct isl_stream *s)
+{
+	int pow;
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 1;
+	if (tok->type != '^') {
+		isl_stream_push_token(s, tok);
+		return 1;
+	}
+	isl_token_free(tok);
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting exponent");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		return 1;
+	}
+	pow = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+	return pow;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v);
+
+static __isl_give isl_pw_qpolynomial *read_factor(struct isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v)
+{
+	isl_pw_qpolynomial *pwqp;
+	struct isl_token *tok;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	if (tok->type == '(') {
+		int pow;
+
+		isl_token_free(tok);
+		pwqp = read_term(s, map, v);
+		if (!pwqp)
+			return NULL;
+		if (isl_stream_eat(s, ')'))
+			goto error;
+		pow = optional_power(s);
+		pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+	} else if (tok->type == ISL_TOKEN_VALUE) {
+		struct isl_token *tok2;
+		isl_qpolynomial *qp;
+
+		tok2 = isl_stream_next_token(s);
+		if (tok2 && tok2->type == '/') {
+			isl_token_free(tok2);
+			tok2 = next_token(s);
+			if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+				isl_stream_error(s, tok2, "expected denominator");
+				isl_token_free(tok);
+				isl_token_free(tok2);
+				return NULL;
+			}
+			qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map),
+						    tok->u.v, tok2->u.v);
+			isl_token_free(tok2);
+		} else {
+			isl_stream_push_token(s, tok2);
+			qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map),
+						tok->u.v);
+		}
+		isl_token_free(tok);
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_INFTY) {
+		isl_qpolynomial *qp;
+		isl_token_free(tok);
+		qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map));
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_NAN) {
+		isl_qpolynomial *qp;
+		isl_token_free(tok);
+		qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map));
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_IDENT) {
+		int n = v->n;
+		int pos = vars_pos(v, tok->u.s, -1);
+		int pow;
+		isl_qpolynomial *qp;
+		if (pos < 0) {
+			isl_token_free(tok);
+			return NULL;
+		}
+		if (pos >= n) {
+			vars_drop(v, v->n - n);
+			isl_stream_error(s, tok, "unknown identifier");
+			isl_token_free(tok);
+			return NULL;
+		}
+		isl_token_free(tok);
+		pow = optional_power(s);
+		qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow);
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (is_start_of_div(tok)) {
+		isl_pw_aff *pwaff;
+		int pow;
+
+		isl_stream_push_token(s, tok);
+		pwaff = accept_div(s, isl_map_get_space(map), v);
+		pow = optional_power(s);
+		pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff);
+		pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+	} else if (tok->type == '-') {
+		isl_token_free(tok);
+		pwqp = read_factor(s, map, v);
+		pwqp = isl_pw_qpolynomial_neg(pwqp);
+	} else {
+		isl_stream_error(s, tok, "unexpected isl_token");
+		isl_stream_push_token(s, tok);
+		return NULL;
+	}
+
+	if (isl_stream_eat_if_available(s, '*') ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
+		isl_pw_qpolynomial *pwqp2;
+
+		pwqp2 = read_factor(s, map, v);
+		pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2);
+	}
+
+	return pwqp;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v)
+{
+	struct isl_token *tok;
+	isl_pw_qpolynomial *pwqp;
+
+	pwqp = read_factor(s, map, v);
+
+	for (;;) {
+		tok = next_token(s);
+		if (!tok)
+			return pwqp;
+
+		if (tok->type == '+') {
+			isl_pw_qpolynomial *pwqp2;
+
+			isl_token_free(tok);
+			pwqp2 = read_factor(s, map, v);
+			pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
+		} else if (tok->type == '-') {
+			isl_pw_qpolynomial *pwqp2;
+
+			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;
+		}
+	}
+
+	return pwqp;
+}
+
+static __isl_give isl_map *read_optional_formula(struct isl_stream *s,
+	__isl_take isl_map *map, struct vars *v, int rational)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	if (tok->type == ':' ||
+	    (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
+		isl_token_free(tok);
+		map = read_formula(s, v, map, rational);
+	} else
+		isl_stream_push_token(s, tok);
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static struct isl_obj obj_read_poly(struct isl_stream *s,
+	__isl_take isl_map *map, struct vars *v, int n)
+{
+	struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL };
+	isl_pw_qpolynomial *pwqp;
+	struct isl_set *set;
+
+	pwqp = read_term(s, map, v);
+	map = read_optional_formula(s, map, v, 0);
+	set = isl_map_range(map);
+
+	pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = pwqp;
+	return obj;
+}
+
+static struct isl_obj obj_read_poly_or_fold(struct isl_stream *s,
+	__isl_take isl_set *set, struct vars *v, int n)
+{
+	struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL };
+	isl_pw_qpolynomial *pwqp;
+	isl_pw_qpolynomial_fold *pwf = NULL;
+
+	if (!isl_stream_eat_if_available(s, ISL_TOKEN_MAX))
+		return obj_read_poly(s, set, v, n);
+
+	if (isl_stream_eat(s, '('))
+		goto error;
+
+	pwqp = read_term(s, set, v);
+	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, pwqp);
+
+	while (isl_stream_eat_if_available(s, ',')) {
+		isl_pw_qpolynomial_fold *pwf_i;
+		pwqp = read_term(s, set, v);
+		pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max,
+									pwqp);
+		pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i);
+	}
+
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	set = read_optional_formula(s, set, v, 0);
+	pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = pwf;
+	return obj;
+error:
+	isl_set_free(set);
+	isl_pw_qpolynomial_fold_free(pwf);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static int is_rational(struct isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
+		isl_token_free(tok);
+		isl_stream_eat(s, ':');
+		return 1;
+	}
+
+	isl_stream_push_token(s, tok);
+
+	return 0;
+}
+
+static struct isl_obj obj_read_body(struct isl_stream *s,
+	__isl_take isl_map *map, struct vars *v)
+{
+	struct isl_token *tok;
+	struct isl_obj obj = { isl_obj_set, NULL };
+	int n = v->n;
+	int rational;
+
+	rational = is_rational(s);
+	if (rational)
+		map = isl_map_set_rational(map);
+
+	if (isl_stream_next_token_is(s, ':')) {
+		obj.type = isl_obj_set;
+		obj.v = read_optional_formula(s, map, v, rational);
+		return obj;
+	}
+
+	if (!next_is_tuple(s))
+		return obj_read_poly_or_fold(s, map, v, n);
+
+	map = read_map_tuple(s, map, isl_dim_in, v, rational, 0);
+	if (!map)
+		goto error;
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	if (tok->type == ISL_TOKEN_TO) {
+		obj.type = isl_obj_map;
+		isl_token_free(tok);
+		if (!next_is_tuple(s)) {
+			isl_set *set = isl_map_domain(map);
+			return obj_read_poly_or_fold(s, set, v, n);
+		}
+		map = read_map_tuple(s, map, isl_dim_out, v, rational, 0);
+		if (!map)
+			goto error;
+	} else {
+		map = isl_map_domain(map);
+		isl_stream_push_token(s, tok);
+	}
+
+	map = read_optional_formula(s, map, v, rational);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = map;
+	return obj;
+error:
+	isl_map_free(map);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj)
+{
+	if (obj.type == isl_obj_map) {
+		obj.v = isl_union_map_from_map(obj.v);
+		obj.type = isl_obj_union_map;
+	} else if (obj.type == isl_obj_set) {
+		obj.v = isl_union_set_from_set(obj.v);
+		obj.type = isl_obj_union_set;
+	} else if (obj.type == isl_obj_pw_qpolynomial) {
+		obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+		obj.type = isl_obj_union_pw_qpolynomial;
+	} else if (obj.type == isl_obj_pw_qpolynomial_fold) {
+		obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
+		obj.type = isl_obj_union_pw_qpolynomial_fold;
+	} else
+		isl_assert(ctx, 0, goto error);
+	return obj;
+error:
+	obj.type->free(obj.v);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static struct isl_obj obj_add(struct isl_ctx *ctx,
+	struct isl_obj obj1, struct isl_obj obj2)
+{
+	if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set)
+		obj1 = to_union(ctx, obj1);
+	if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set)
+		obj2 = to_union(ctx, obj2);
+	if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map)
+		obj1 = to_union(ctx, obj1);
+	if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map)
+		obj2 = to_union(ctx, obj2);
+	if (obj1.type == isl_obj_pw_qpolynomial &&
+	    obj2.type == isl_obj_union_pw_qpolynomial)
+		obj1 = to_union(ctx, obj1);
+	if (obj1.type == isl_obj_union_pw_qpolynomial &&
+	    obj2.type == isl_obj_pw_qpolynomial)
+		obj2 = to_union(ctx, obj2);
+	if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+	    obj2.type == isl_obj_union_pw_qpolynomial_fold)
+		obj1 = to_union(ctx, obj1);
+	if (obj1.type == isl_obj_union_pw_qpolynomial_fold &&
+	    obj2.type == isl_obj_pw_qpolynomial_fold)
+		obj2 = to_union(ctx, obj2);
+	isl_assert(ctx, obj1.type == obj2.type, goto error);
+	if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(ctx, obj1);
+		obj2 = to_union(ctx, obj2);
+	}
+	if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(ctx, obj1);
+		obj2 = to_union(ctx, obj2);
+	}
+	if (obj1.type == isl_obj_pw_qpolynomial &&
+	    !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(ctx, obj1);
+		obj2 = to_union(ctx, obj2);
+	}
+	if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+	    !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(ctx, obj1);
+		obj2 = to_union(ctx, obj2);
+	}
+	obj1.v = obj1.type->add(obj1.v, obj2.v);
+	return obj1;
+error:
+	obj1.type->free(obj1.v);
+	obj2.type->free(obj2.v);
+	obj1.type = isl_obj_none;
+	obj1.v = NULL;
+	return obj1;
+}
+
+static struct isl_obj obj_read(struct isl_stream *s)
+{
+	isl_map *map = NULL;
+	struct isl_token *tok;
+	struct vars *v = NULL;
+	struct isl_obj obj = { isl_obj_set, NULL };
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	if (tok->type == ISL_TOKEN_VALUE) {
+		struct isl_token *tok2;
+		struct isl_map *map;
+
+		tok2 = isl_stream_next_token(s);
+		if (!tok2 || tok2->type != ISL_TOKEN_VALUE ||
+		    isl_int_is_neg(tok2->u.v)) {
+			if (tok2)
+				isl_stream_push_token(s, tok2);
+			obj.type = isl_obj_val;
+			obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+			isl_token_free(tok);
+			return obj;
+		}
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		map = map_read_polylib(s);
+		if (!map)
+			goto error;
+		if (isl_map_may_be_set(map))
+			obj.v = isl_map_range(map);
+		else {
+			obj.type = isl_obj_map;
+			obj.v = map;
+		}
+		return obj;
+	}
+	v = vars_new(s->ctx);
+	if (!v) {
+		isl_stream_push_token(s, tok);
+		goto error;
+	}
+	map = isl_map_universe(isl_space_params_alloc(s->ctx, 0));
+	if (tok->type == '[') {
+		isl_stream_push_token(s, tok);
+		map = read_map_tuple(s, map, isl_dim_param, v, 0, 0);
+		if (!map)
+			goto error;
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ISL_TOKEN_TO) {
+			isl_stream_error(s, tok, "expecting '->'");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		isl_token_free(tok);
+		tok = isl_stream_next_token(s);
+	}
+	if (!tok || tok->type != '{') {
+		isl_stream_error(s, tok, "expecting '{'");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		goto error;
+	}
+	isl_token_free(tok);
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		;
+	else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) {
+		isl_token_free(tok);
+		if (isl_stream_eat(s, '='))
+			goto error;
+		map = read_map_tuple(s, map, isl_dim_param, v, 0, 1);
+		if (!map)
+			goto error;
+	} else if (tok->type == '}') {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_empty(isl_map_get_space(map));
+		isl_token_free(tok);
+		goto done;
+	} else
+		isl_stream_push_token(s, tok);
+
+	for (;;) {
+		struct isl_obj o;
+		tok = NULL;
+		o = obj_read_body(s, isl_map_copy(map), v);
+		if (o.type == isl_obj_none || !o.v)
+			goto error;
+		if (!obj.v)
+			obj = o;
+		else {
+			obj = obj_add(s->ctx, obj, o);
+			if (obj.type == isl_obj_none || !obj.v)
+				goto error;
+		}
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ';')
+			break;
+		isl_token_free(tok);
+		if (isl_stream_next_token_is(s, '}')) {
+			tok = isl_stream_next_token(s);
+			break;
+		}
+	}
+
+	if (tok && tok->type == '}') {
+		isl_token_free(tok);
+	} else {
+		isl_stream_error(s, tok, "unexpected isl_token");
+		if (tok)
+			isl_token_free(tok);
+		goto error;
+	}
+done:
+	vars_free(v);
+	isl_map_free(map);
+
+	return obj;
+error:
+	isl_map_free(map);
+	obj.type->free(obj.v);
+	if (v)
+		vars_free(v);
+	obj.v = NULL;
+	return obj;
+}
+
+struct isl_obj isl_stream_read_obj(struct isl_stream *s)
+{
+	return obj_read(s);
+}
+
+__isl_give isl_map *isl_stream_read_map(struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_map ||
+				   obj.type == isl_obj_set, goto error);
+	
+	if (obj.type == isl_obj_set)
+		obj.v = isl_map_from_range(obj.v);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_set *isl_stream_read_set(struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v) {
+		if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) {
+			obj.v = isl_map_range(obj.v);
+			obj.type = isl_obj_set;
+		}
+		isl_assert(s->ctx, obj.type == isl_obj_set, goto error);
+	}
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_stream_read_union_map(struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_map) {
+		obj.type = isl_obj_union_map;
+		obj.v = isl_union_map_from_map(obj.v);
+	}
+	if (obj.type == isl_obj_set) {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_from_set(obj.v);
+	}
+	if (obj.v && obj.type == isl_obj_union_set &&
+	    isl_union_set_is_empty(obj.v))
+		obj.type = isl_obj_union_map;
+	if (obj.v && obj.type != isl_obj_union_map)
+		isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_stream_read_union_set(struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_set) {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_from_set(obj.v);
+	}
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_union_set, goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read(struct isl_stream *s)
+{
+	struct isl_obj obj;
+	struct isl_map *map;
+	struct isl_basic_map *bmap;
+
+	obj = obj_read(s);
+	if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set))
+		isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map",
+			goto error);
+	map = obj.v;
+	if (!map)
+		return NULL;
+
+	if (map->n > 1)
+		isl_die(s->ctx, isl_error_invalid,
+			"set or map description involves "
+			"more than one disjunct", goto error);
+
+	if (map->n == 0)
+		bmap = isl_basic_map_empty_like_map(map);
+	else
+		bmap = isl_basic_map_copy(map->p[0]);
+
+	isl_map_free(map);
+
+	return bmap;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *basic_set_read(struct isl_stream *s)
+{
+	isl_basic_map *bmap;
+	bmap = basic_map_read(s);
+	if (!bmap)
+		return NULL;
+	if (!isl_basic_map_may_be_set(bmap))
+		isl_die(s->ctx, isl_error_invalid,
+			"input is not a set", goto error);
+	return isl_basic_map_range(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	struct isl_basic_map *bmap;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	bmap = basic_map_read(s);
+	isl_stream_free(s);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_basic_set *bset;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	bset = basic_set_read(s);
+	isl_stream_free(s);
+	return bset;
+}
+
+struct isl_basic_map *isl_basic_map_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	struct isl_basic_map *bmap;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	bmap = basic_map_read(s);
+	isl_stream_free(s);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_basic_set *bset;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	bset = basic_set_read(s);
+	isl_stream_free(s);
+	return bset;
+}
+
+__isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx,
+	FILE *input)
+{
+	struct isl_map *map;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	map = isl_stream_read_map(s);
+	isl_stream_free(s);
+	return map;
+}
+
+__isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	struct isl_map *map;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	map = isl_stream_read_map(s);
+	isl_stream_free(s);
+	return map;
+}
+
+__isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx,
+	FILE *input)
+{
+	isl_set *set;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	set = isl_stream_read_set(s);
+	isl_stream_free(s);
+	return set;
+}
+
+struct isl_set *isl_set_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_set *set;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	set = isl_stream_read_set(s);
+	isl_stream_free(s);
+	return set;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_union_map *umap;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	umap = isl_stream_read_union_map(s);
+	isl_stream_free(s);
+	return umap;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
+		const char *str)
+{
+	isl_union_map *umap;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	umap = isl_stream_read_union_map(s);
+	isl_stream_free(s);
+	return umap;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_union_set *uset;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	uset = isl_stream_read_union_set(s);
+	isl_stream_free(s);
+	return uset;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
+		const char *str)
+{
+	isl_union_set *uset;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	uset = isl_stream_read_union_set(s);
+	isl_stream_free(s);
+	return uset;
+}
+
+static __isl_give isl_vec *isl_vec_read_polylib(struct isl_stream *s)
+{
+	struct isl_vec *vec = NULL;
+	struct isl_token *tok;
+	unsigned size;
+	int j;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting vector length");
+		goto error;
+	}
+
+	size = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	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");
+			goto error;
+		}
+		isl_int_set(vec->el[j], tok->u.v);
+		isl_token_free(tok);
+	}
+
+	return vec;
+error:
+	isl_token_free(tok);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+static __isl_give isl_vec *vec_read(struct isl_stream *s)
+{
+	return isl_vec_read_polylib(s);
+}
+
+__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
+{
+	isl_vec *v;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	v = vec_read(s);
+	isl_stream_free(s);
+	return v;
+}
+
+__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
+	struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial,
+			   goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
+		const char *str)
+{
+	isl_pw_qpolynomial *pwqp;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pwqp = isl_stream_read_pw_qpolynomial(s);
+	isl_stream_free(s);
+	return pwqp;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
+		FILE *input)
+{
+	isl_pw_qpolynomial *pwqp;
+	struct isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	pwqp = isl_stream_read_pw_qpolynomial(s);
+	isl_stream_free(s);
+	return pwqp;
+}
+
+/* Is the next token an identifer not in "v"?
+ */
+static int next_is_fresh_ident(struct isl_stream *s, struct vars *v)
+{
+	int n = v->n;
+	int fresh;
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
+	isl_stream_push_token(s, tok);
+
+	vars_drop(v, v->n - n);
+
+	return fresh;
+}
+
+/* First read the domain of the affine expression, which may be
+ * a parameter space or a set.
+ * The tricky part is that we don't know if the domain is a set or not,
+ * so when we are trying to read the domain, we may actually be reading
+ * the affine expression itself (defined on a parameter domains)
+ * If the tuple we are reading is named, we assume it's the domain.
+ * Also, if inside the tuple, the first thing we find is a nested tuple
+ * or a new identifier, we again assume it's the domain.
+ * Otherwise, we assume we are reading an affine expression.
+ */
+static __isl_give isl_set *read_aff_domain(struct isl_stream *s,
+	__isl_take isl_set *dom, struct vars *v)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
+		isl_stream_push_token(s, tok);
+		return read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+	}
+	if (!tok || tok->type != '[') {
+		isl_stream_error(s, tok, "expecting '['");
+		goto error;
+	}
+	if (next_is_tuple(s) || next_is_fresh_ident(s, v)) {
+		isl_stream_push_token(s, tok);
+		dom = read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+	} else
+		isl_stream_push_token(s, tok);
+
+	return dom;
+error:
+	if (tok)
+		isl_stream_push_token(s, tok);
+	isl_set_free(dom);
+	return NULL;
+}
+
+/* Read an affine expression from "s".
+ */
+__isl_give isl_aff *isl_stream_read_aff(struct isl_stream *s)
+{
+	isl_aff *aff;
+	isl_multi_aff *ma;
+
+	ma = isl_stream_read_multi_aff(s);
+	if (!ma)
+		return NULL;
+	if (isl_multi_aff_dim(ma, isl_dim_out) != 1)
+		isl_die(s->ctx, isl_error_invalid,
+			"expecting single affine expression",
+			goto error);
+
+	aff = isl_multi_aff_get_aff(ma, 0);
+	isl_multi_aff_free(ma);
+	return aff;
+error:
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Read a piecewise affine expression from "s" with domain (space) "dom".
+ */
+static __isl_give isl_pw_aff *read_pw_aff_with_dom(struct isl_stream *s,
+	__isl_take isl_set *dom, struct vars *v)
+{
+	isl_pw_aff *pwaff = NULL;
+
+	if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
+		goto error;
+
+	if (isl_stream_eat(s, '['))
+		goto error;
+
+	pwaff = accept_affine(s, isl_set_get_space(dom), v);
+
+	if (isl_stream_eat(s, ']'))
+		goto error;
+
+	dom = read_optional_formula(s, dom, v, 0);
+	pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
+
+	return pwaff;
+error:
+	isl_set_free(dom);
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+__isl_give isl_pw_aff *isl_stream_read_pw_aff(struct isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_set *aff_dom;
+	isl_pw_aff *pa = NULL;
+	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);
+	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)
+{
+	isl_aff *aff;
+	struct 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_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+	isl_pw_aff *pa;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pa = isl_stream_read_pw_aff(s);
+	isl_stream_free(s);
+	return pa;
+}
+
+/* Read an isl_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_pw_multi_aff.
+ * It would be more efficient if we were to construct the isl_pw_multi_aff
+ * directly.
+ */
+__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (!obj.v)
+		return NULL;
+
+	if (obj.type == isl_obj_map)
+		return isl_pw_multi_aff_from_map(obj.v);
+	if (obj.type == isl_obj_set)
+		return isl_pw_multi_aff_from_set(obj.v);
+
+	obj.type->free(obj.v);
+	isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+		return NULL);
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_pw_multi_aff *pma;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pma = isl_stream_read_pw_multi_aff(s);
+	isl_stream_free(s);
+	return pma;
+}
+
+/* Read an isl_union_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_union_pw_multi_aff.
+ * It would be more efficient if we were to construct
+ * the isl_union_pw_multi_aff directly.
+ */
+__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
+	struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (!obj.v)
+		return NULL;
+
+	if (obj.type == isl_obj_map || obj.type == isl_obj_set)
+		obj = to_union(s->ctx, obj);
+	if (obj.type == isl_obj_union_map)
+		return isl_union_pw_multi_aff_from_union_map(obj.v);
+	if (obj.type == isl_obj_union_set)
+		return isl_union_pw_multi_aff_from_union_set(obj.v);
+
+	obj.type->free(obj.v);
+	isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+		return NULL);
+}
+
+/* Read an isl_union_pw_multi_aff from "str".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+	isl_ctx *ctx, const char *str)
+{
+	isl_union_pw_multi_aff *upma;
+	struct isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	upma = isl_stream_read_union_pw_multi_aff(s);
+	isl_stream_free(s);
+	return upma;
+}
+
+/* Assuming "pa" represents a single affine expression defined on a universe
+ * domain, extract this affine expression.
+ */
+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;
+}
+
+/* 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.
+ */
+__isl_give isl_multi_aff *isl_stream_read_multi_aff(struct isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_multi_pw_aff *tuple = NULL;
+	int dim, i, n;
+	isl_space *space, *dom_space;
+	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);
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	tuple = read_tuple(s, v, 0, 0);
+	if (!tuple)
+		goto error;
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+		isl_set *set;
+		isl_space *space;
+		int has_expr;
+
+		has_expr = tuple_has_expr(tuple);
+		if (has_expr < 0)
+			goto error;
+		if (has_expr)
+			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);
+		isl_multi_pw_aff_free(tuple);
+		tuple = read_tuple(s, v, 0, 0);
+		if (!tuple)
+			goto error;
+	}
+
+	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);
+	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);
+	}
+
+	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_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;
+	struct 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;
+}
+
+/* Read an isl_multi_pw_aff from "s".
+ *
+ * The input format is similar to that of map, except that any conditions
+ * on the domains should be specified inside the tuple since each
+ * piecewise affine expression may have a different domain.
+ *
+ * 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.
+ *
+ * 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 reading am isl_multi_pw_aff so we check
+ * that the definition of the output/set dimensions does not involve any
+ * output/set dimensions.
+ * We then 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.
+ */
+__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(struct isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_multi_pw_aff *tuple = NULL;
+	int dim, i, n;
+	isl_space *space, *dom_space;
+	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;
+
+	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);
+		tuple = read_tuple(s, v, 0, 0);
+		if (!tuple)
+			goto error;
+	}
+
+	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);
+	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);
+	mpa = isl_multi_pw_aff_alloc(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		if (!pa)
+			goto error;
+		if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
+			isl_pw_aff_free(pa);
+			isl_die(s->ctx, isl_error_invalid,
+				"not an affine expression", goto error);
+		}
+		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);
+	}
+
+	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;
+}
+
+/* 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;
+	struct 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;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
+	struct isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_pw_qpolynomial) {
+		obj.type = isl_obj_union_pw_qpolynomial;
+		obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+	}
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
+			   goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	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;
+	struct 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;
+}

Added: polly/trunk/lib/External/isl/isl_int.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int.h (added)
+++ polly/trunk/lib/External/isl/isl_int.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_INT_H
+#define ISL_INT_H
+#define ISL_DEPRECATED_INT_H
+
+#include <isl/hash.h>
+#include <isl/printer.h>
+#include <string.h>
+#include <isl_config.h>
+
+#ifdef USE_GMP_FOR_MP
+#include <isl_int_gmp.h>
+#endif
+
+#ifdef USE_IMATH_FOR_MP
+#include <isl_int_imath.h>
+#endif
+
+#define isl_int_is_zero(i)	(isl_int_sgn(i) == 0)
+#define isl_int_is_one(i)	(isl_int_cmp_si(i,1) == 0)
+#define isl_int_is_negone(i)	(isl_int_cmp_si(i,-1) == 0)
+#define isl_int_is_pos(i)	(isl_int_sgn(i) > 0)
+#define isl_int_is_neg(i)	(isl_int_sgn(i) < 0)
+#define isl_int_is_nonpos(i)	(isl_int_sgn(i) <= 0)
+#define isl_int_is_nonneg(i)	(isl_int_sgn(i) >= 0)
+
+#define isl_int_print(out,i,width)					\
+	do {								\
+		char *s;						\
+		s = isl_int_get_str(i);					\
+		fprintf(out, "%*s", width, s);				\
+		isl_int_free_str(s);                                        \
+	} while (0)
+
+__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
+	isl_int i);
+
+#endif /* ISL_INT_H */

Added: polly/trunk/lib/External/isl/isl_int_gmp.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int_gmp.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int_gmp.h (added)
+++ polly/trunk/lib/External/isl/isl_int_gmp.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,88 @@
+#ifndef ISL_INT_GMP_H
+#define ISL_INT_GMP_H
+
+#include <gmp.h>
+
+/* isl_int is the basic integer type, implemented with GMP's mpz_t.  In the
+ * future, different types such as long long or cln::cl_I will be supported.
+ */
+typedef mpz_t	isl_int;
+
+#define isl_int_init(i)		mpz_init(i)
+#define isl_int_clear(i)	mpz_clear(i)
+
+#define isl_int_set(r,i)	mpz_set(r,i)
+#define isl_int_set_si(r,i)	mpz_set_si(r,i)
+#define isl_int_set_ui(r,i)	mpz_set_ui(r,i)
+#define isl_int_fits_slong(r)	mpz_fits_slong_p(r)
+#define isl_int_get_si(r)	mpz_get_si(r)
+#define isl_int_fits_ulong(r)	mpz_fits_ulong_p(r)
+#define isl_int_get_ui(r)	mpz_get_ui(r)
+#define isl_int_get_d(r)	mpz_get_d(r)
+#define isl_int_get_str(r)	mpz_get_str(0, 10, r)
+#define isl_int_abs(r,i)	mpz_abs(r,i)
+#define isl_int_neg(r,i)	mpz_neg(r,i)
+#define isl_int_swap(i,j)	mpz_swap(i,j)
+#define isl_int_swap_or_set(i,j)	mpz_swap(i,j)
+#define isl_int_add_ui(r,i,j)	mpz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j)	mpz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j)	mpz_add(r,i,j)
+#define isl_int_sub(r,i,j)	mpz_sub(r,i,j)
+#define isl_int_mul(r,i,j)	mpz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j)	mpz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j)	mpz_mul_si(r,i,j)
+#define isl_int_mul_ui(r,i,j)	mpz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j)	mpz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j)	mpz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j)	mpz_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j)	mpz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j)	mpz_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j)	mpz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j)	mpz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j)	mpz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j)	mpz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j)	mpz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j)	mpz_cdiv_q(r,i,j)
+#define isl_int_fdiv_q(r,i,j)	mpz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j)	mpz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j)	mpz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s)	mpz_set_str(r,s,10)
+#define isl_int_sgn(i)		mpz_sgn(i)
+#define isl_int_cmp(i,j)	mpz_cmp(i,j)
+#define isl_int_cmp_si(i,si)	mpz_cmp_si(i,si)
+#define isl_int_eq(i,j)		(mpz_cmp(i,j) == 0)
+#define isl_int_ne(i,j)		(mpz_cmp(i,j) != 0)
+#define isl_int_lt(i,j)		(mpz_cmp(i,j) < 0)
+#define isl_int_le(i,j)		(mpz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j)		(mpz_cmp(i,j) > 0)
+#define isl_int_ge(i,j)		(mpz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j)	mpz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j)	(mpz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j)	(mpz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j)	(mpz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j)	(mpz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j)	(mpz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j)	mpz_divisible_p(i,j)
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash);
+#define isl_int_hash(v,h)	isl_gmp_hash(v,h)
+
+#ifndef mp_get_memory_functions
+void mp_get_memory_functions(
+		void *(**alloc_func_ptr) (size_t),
+		void *(**realloc_func_ptr) (void *, size_t, size_t),
+		void (**free_func_ptr) (void *, size_t));
+#endif
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s)					\
+	do {								\
+		isl_int_print_mp_free_t mp_free;			\
+		mp_get_memory_functions(NULL, NULL, &mp_free);		\
+		(*mp_free)(s, strlen(s) + 1);				\
+	} while (0)
+
+#endif /* ISL_INT_GMP_H */

Added: polly/trunk/lib/External/isl/isl_int_imath.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int_imath.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int_imath.h (added)
+++ polly/trunk/lib/External/isl/isl_int_imath.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,76 @@
+#ifndef ISL_INT_IMATH_H
+#define ISL_INT_IMATH_H
+
+#include "isl_hide_deprecated.h"
+
+#include <isl_imath.h>
+
+/* isl_int is the basic integer type, implemented with imath's mp_int. */
+typedef mp_int isl_int;
+
+#define isl_int_init(i)		i = mp_int_alloc()
+#define isl_int_clear(i)	mp_int_free(i)
+
+#define isl_int_set(r,i)	impz_set(r,i)
+#define isl_int_set_si(r,i)	impz_set_si(r,i)
+#define isl_int_set_ui(r,i)	impz_set_ui(r,i)
+#define isl_int_fits_slong(r)	isl_imath_fits_slong_p(r)
+#define isl_int_get_si(r)	impz_get_si(r)
+#define isl_int_fits_ulong(r)	isl_imath_fits_ulong_p(r)
+#define isl_int_get_ui(r)	impz_get_ui(r)
+#define isl_int_get_d(r)	impz_get_si(r)
+#define isl_int_get_str(r)	impz_get_str(0, 10, r)
+#define isl_int_abs(r,i)	impz_abs(r,i)
+#define isl_int_neg(r,i)	impz_neg(r,i)
+#define isl_int_swap(i,j)	impz_swap(i,j)
+#define isl_int_swap_or_set(i,j)	impz_swap(i,j)
+#define isl_int_add_ui(r,i,j)	impz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j)	impz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j)	impz_add(r,i,j)
+#define isl_int_sub(r,i,j)	impz_sub(r,i,j)
+#define isl_int_mul(r,i,j)	impz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j)	impz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j)	mp_int_mul_value(i,j,r)
+#define isl_int_mul_ui(r,i,j)	impz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j)	impz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j)	impz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j)	isl_imath_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j)	impz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j)	isl_imath_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j)	impz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j)	impz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j)	impz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j)	impz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j)	impz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j)	impz_cdiv_q(r,i,j)
+#define isl_int_fdiv_q(r,i,j)	impz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j)	impz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j)	impz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s)	impz_set_str(r,s,10)
+#define isl_int_sgn(i)		impz_sgn(i)
+#define isl_int_cmp(i,j)	impz_cmp(i,j)
+#define isl_int_cmp_si(i,si)	impz_cmp_si(i,si)
+#define isl_int_eq(i,j)		(impz_cmp(i,j) == 0)
+#define isl_int_ne(i,j)		(impz_cmp(i,j) != 0)
+#define isl_int_lt(i,j)		(impz_cmp(i,j) < 0)
+#define isl_int_le(i,j)		(impz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j)		(impz_cmp(i,j) > 0)
+#define isl_int_ge(i,j)		(impz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j)	impz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j)	(impz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j)	(impz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j)	(impz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j)	(impz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j)	(impz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j)	impz_divisible_p(i,j)
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+#define isl_int_hash(v,h)	isl_imath_hash(v,h)
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s)	free(s)
+
+#endif /* ISL_INT_IMATH_H */

Added: polly/trunk/lib/External/isl/isl_list_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_list_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_list_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_list_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_sort.h>
+#include <isl_tarjan.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
+
+isl_ctx *FN(LIST(EL),get_ctx)(__isl_keep LIST(EL) *list)
+{
+	return list ? list->ctx : NULL;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),alloc)(isl_ctx *ctx, int n)
+{
+	LIST(EL) *list;
+
+	if (n < 0)
+		isl_die(ctx, isl_error_invalid,
+			"cannot create list of negative length",
+			return NULL);
+	list = isl_alloc(ctx, LIST(EL),
+			 sizeof(LIST(EL)) + (n - 1) * sizeof(struct EL *));
+	if (!list)
+		return NULL;
+
+	list->ctx = ctx;
+	isl_ctx_ref(ctx);
+	list->ref = 1;
+	list->size = n;
+	list->n = 0;
+	return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),copy)(__isl_keep LIST(EL) *list)
+{
+	if (!list)
+		return NULL;
+
+	list->ref++;
+	return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list)
+{
+	int i;
+	LIST(EL) *dup;
+
+	if (!list)
+		return NULL;
+
+	dup = FN(LIST(EL),alloc)(FN(LIST(EL),get_ctx)(list), list->n);
+	if (!dup)
+		return NULL;
+	for (i = 0; i < list->n; ++i)
+		dup = FN(LIST(EL),add)(dup, FN(EL,copy)(list->p[i]));
+	return dup;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),cow)(__isl_take LIST(EL) *list)
+{
+	if (!list)
+		return NULL;
+
+	if (list->ref == 1)
+		return list;
+	list->ref--;
+	return FN(LIST(EL),dup)(list);
+}
+
+/* Make sure "list" has room for at least "n" more pieces.
+ * Always return a list with a single reference.
+ *
+ * If there is only one reference to list, we extend it in place.
+ * Otherwise, we create a new LIST(EL) and copy the elements.
+ */
+static __isl_give LIST(EL) *FN(LIST(EL),grow)(__isl_take LIST(EL) *list, int n)
+{
+	isl_ctx *ctx;
+	int i, new_size;
+	LIST(EL) *res;
+
+	if (!list)
+		return NULL;
+	if (list->ref == 1 && list->n + n <= list->size)
+		return list;
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	new_size = ((list->n + n + 1) * 3) / 2;
+	if (list->ref == 1) {
+		res = isl_realloc(ctx, list, LIST(EL),
+			    sizeof(LIST(EL)) + (new_size - 1) * sizeof(EL *));
+		if (!res)
+			return FN(LIST(EL),free)(list);
+		res->size = new_size;
+		return res;
+	}
+
+	if (list->n + n <= list->size && list->size < new_size)
+		new_size = list->size;
+
+	res = FN(LIST(EL),alloc)(ctx, new_size);
+	if (!res)
+		return FN(LIST(EL),free)(list);
+
+	for (i = 0; i < list->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+
+	FN(LIST(EL),free)(list);
+	return res;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),add)(__isl_take LIST(EL) *list,
+	__isl_take struct EL *el)
+{
+	list = FN(LIST(EL),grow)(list, 1);
+	if (!list || !el)
+		goto error;
+	list->p[list->n] = el;
+	list->n++;
+	return list;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+/* Remove the "n" elements starting at "first" from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),drop)(__isl_take LIST(EL) *list,
+	unsigned first, unsigned n)
+{
+	int i;
+
+	if (!list)
+		return NULL;
+	if (first + n > list->n || first + n < first)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", return FN(LIST(EL),free)(list));
+	if (n == 0)
+		return list;
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		return NULL;
+	for (i = 0; i < n; ++i)
+		FN(EL,free)(list->p[first + i]);
+	for (i = first; i + n < list->n; ++i)
+		list->p[i] = list->p[i + n];
+	list->n -= n;
+	return list;
+}
+
+/* Insert "el" at position "pos" in "list".
+ *
+ * If there is only one reference to "list" and if it already has space
+ * for one extra element, we insert it directly into "list".
+ * Otherwise, we create a new list consisting of "el" and copied
+ * elements from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),insert)(__isl_take LIST(EL) *list,
+	unsigned pos, __isl_take struct EL *el)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *res;
+
+	if (!list || !el)
+		goto error;
+	ctx = FN(LIST(EL),get_ctx)(list);
+	if (pos > list->n)
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (list->ref == 1 && list->size > list->n) {
+		for (i = list->n - 1; i >= pos; --i)
+			list->p[i + 1] = list->p[i];
+		list->n++;
+		list->p[pos] = el;
+		return list;
+	}
+
+	res = FN(LIST(EL),alloc)(ctx, list->n + 1);
+	for (i = 0; i < pos; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+	res = FN(LIST(EL),add)(res, el);
+	for (i = pos; i < list->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+	FN(LIST(EL),free)(list);
+
+	return res;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+__isl_null LIST(EL) *FN(LIST(EL),free)(__isl_take LIST(EL) *list)
+{
+	int i;
+
+	if (!list)
+		return NULL;
+
+	if (--list->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(list->ctx);
+	for (i = 0; i < list->n; ++i)
+		FN(EL,free)(list->p[i]);
+	free(list);
+
+	return NULL;
+}
+
+int FN(FN(LIST(EL),n),BASE)(__isl_keep LIST(EL) *list)
+{
+	return list ? list->n : 0;
+}
+
+__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index)
+{
+	if (!list)
+		return NULL;
+	if (index < 0 || index >= list->n)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", return NULL);
+	return FN(EL,copy)(list->p[index]);
+}
+
+/* Replace the element at position "index" in "list" by "el".
+ */
+__isl_give LIST(EL) *FN(FN(LIST(EL),set),BASE)(__isl_take LIST(EL) *list,
+	int index, __isl_take EL *el)
+{
+	if (!list || !el)
+		goto error;
+	if (index < 0 || index >= list->n)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	if (list->p[index] == el) {
+		FN(EL,free)(el);
+		return list;
+	}
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		goto error;
+	FN(EL,free)(list->p[index]);
+	list->p[index] = el;
+	return list;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+int FN(LIST(EL),foreach)(__isl_keep LIST(EL) *list,
+	int (*fn)(__isl_take EL *el, void *user), void *user)
+{
+	int i;
+
+	if (!list)
+		return -1;
+
+	for (i = 0; i < list->n; ++i) {
+		EL *el = FN(EL,copy(list->p[i]));
+		if (!el)
+			return -1;
+		if (fn(el, user) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Internal data structure for isl_*_list_sort.
+ *
+ * "cmp" is the original comparison function.
+ * "user" is a user provided pointer that should be passed to "cmp".
+ */
+S(LIST(EL),sort_data) {
+	int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+	void *user;
+};
+
+/* Compare two entries of an isl_*_list based on the user provided
+ * comparison function on pairs of isl_* objects.
+ */
+static int FN(LIST(EL),cmp)(const void *a, const void *b, void *user)
+{
+	S(LIST(EL),sort_data) *data = user;
+	EL * const *el1 = a;
+	EL * const *el2 = b;
+
+	return data->cmp(*el1, *el2, data->user);
+}
+
+/* Sort the elements of "list" in ascending order according to
+ * comparison function "cmp".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),sort)(__isl_take LIST(EL) *list,
+	int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user), void *user)
+{
+	S(LIST(EL),sort_data) data = { cmp, user };
+
+	if (!list)
+		return NULL;
+	if (list->n <= 1)
+		return list;
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		return NULL;
+
+	if (isl_sort(list->p, list->n, sizeof(list->p[0]),
+			&FN(LIST(EL),cmp), &data) < 0)
+		return FN(LIST(EL),free)(list);
+
+	return list;
+}
+
+/* Internal data structure for isl_*_list_foreach_scc.
+ *
+ * "list" is the original list.
+ * "follows" is the user provided callback that defines the edges of the graph.
+ */
+S(LIST(EL),foreach_scc_data) {
+	LIST(EL) *list;
+	int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+	void *follows_user;
+};
+
+/* Does element i of data->list follow element j?
+ *
+ * Use the user provided callback to find out.
+ */
+static int FN(LIST(EL),follows)(int i, int j, void *user)
+{
+	S(LIST(EL),foreach_scc_data) *data = user;
+
+	return data->follows(data->list->p[i], data->list->p[j],
+				data->follows_user);
+}
+
+/* Call "fn" on the sublist of "list" that consists of the elements
+ * with indices specified by the "n" elements of "pos".
+ */
+static int FN(LIST(EL),call_on_scc)(__isl_keep LIST(EL) *list, int *pos, int n,
+	int (*fn)(__isl_take LIST(EL) *scc, void *user), void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *slice;
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	slice = FN(LIST(EL),alloc)(ctx, n);
+	for (i = 0; i < n; ++i) {
+		EL *el;
+
+		el = FN(EL,copy)(list->p[pos[i]]);
+		slice = FN(LIST(EL),add)(slice, el);
+	}
+
+	return fn(slice, user);
+}
+
+/* Call "fn" on each of the strongly connected components (SCCs) of
+ * the graph with as vertices the elements of "list" and
+ * a directed edge from node b to node a iff follows(a, b)
+ * returns 1.  follows should return -1 on error.
+ *
+ * If SCC a contains a node i that follows a node j in another SCC b
+ * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a
+ * after being called on SCC b.
+ *
+ * We simply call isl_tarjan_graph_init, extract the SCCs from the result and
+ * call fn on each of them.
+ */
+int FN(LIST(EL),foreach_scc)(__isl_keep LIST(EL) *list,
+	int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user),
+	void *follows_user,
+	int (*fn)(__isl_take LIST(EL) *scc, void *user), void *fn_user)
+{
+	S(LIST(EL),foreach_scc_data) data = { list, follows, follows_user };
+	int i, n;
+	isl_ctx *ctx;
+	struct isl_tarjan_graph *g;
+
+	if (!list)
+		return -1;
+	if (list->n == 0)
+		return 0;
+	if (list->n == 1)
+		return fn(FN(LIST(EL),copy)(list), fn_user);
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	n = list->n;
+	g = isl_tarjan_graph_init(ctx, n, &FN(LIST(EL),follows), &data);
+	if (!g)
+		return -1;
+
+	i = 0;
+	do {
+		int first;
+
+		if (g->order[i] == -1)
+			isl_die(ctx, isl_error_internal, "cannot happen",
+				break);
+		first = i;
+		while (g->order[i] != -1) {
+			++i; --n;
+		}
+		if (first == 0 && n == 0) {
+			isl_tarjan_graph_free(g);
+			return fn(FN(LIST(EL),copy)(list), fn_user);
+		}
+		if (FN(LIST(EL),call_on_scc)(list, g->order + first, i - first,
+					    fn, fn_user) < 0)
+			break;
+		++i;
+	} while (n);
+
+	isl_tarjan_graph_free(g);
+
+	return n > 0 ? -1 : 0;
+}
+
+__isl_give LIST(EL) *FN(FN(LIST(EL),from),BASE)(__isl_take EL *el)
+{
+	isl_ctx *ctx;
+	LIST(EL) *list;
+
+	if (!el)
+		return NULL;
+	ctx = FN(EL,get_ctx)(el);
+	list = FN(LIST(EL),alloc)(ctx, 1);
+	if (!list)
+		goto error;
+	list = FN(LIST(EL),add)(list, el);
+	return list;
+error:
+	FN(EL,free)(el);
+	return NULL;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),concat)(__isl_take LIST(EL) *list1,
+	__isl_take LIST(EL) *list2)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *res;
+
+	if (!list1 || !list2)
+		goto error;
+
+	ctx = FN(LIST(EL),get_ctx)(list1);
+	res = FN(LIST(EL),alloc)(ctx, list1->n + list2->n);
+	for (i = 0; i < list1->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list1->p[i]));
+	for (i = 0; i < list2->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list2->p[i]));
+
+	FN(LIST(EL),free)(list1);
+	FN(LIST(EL),free)(list2);
+	return res;
+error:
+	FN(LIST(EL),free)(list1);
+	FN(LIST(EL),free)(list2);
+	return NULL;
+}
+
+__isl_give isl_printer *CAT(isl_printer_print_,LIST(BASE))(
+	__isl_take isl_printer *p, __isl_keep LIST(EL) *list)
+{
+	int i;
+
+	if (!p || !list)
+		goto error;
+	p = isl_printer_print_str(p, "(");
+	for (i = 0; i < list->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ",");
+		p = CAT(isl_printer_print_,BASE)(p, list->p[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void FN(LIST(EL),dump)(__isl_keep LIST(EL) *list)
+{
+	isl_printer *printer;
+
+	if (!list)
+		return;
+
+	printer = isl_printer_to_file(FN(LIST(EL),get_ctx)(list), stderr);
+	printer = CAT(isl_printer_print_,LIST(BASE))(printer, list);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}

Added: polly/trunk/lib/External/isl/isl_list_templ.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_list_templ.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_list_templ.h (added)
+++ polly/trunk/lib/External/isl/isl_list_templ.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,16 @@
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+
+struct LIST(EL) {
+	int ref;
+	isl_ctx *ctx;
+
+	int n;
+
+	size_t size;
+	struct EL *p[1];
+};
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list);

Added: polly/trunk/lib/External/isl/isl_local_space.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_local_space.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_local_space.c (added)
+++ polly/trunk/lib/External/isl/isl_local_space.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1363 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_local_space_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
+{
+	return ls ? ls->dim->ctx : NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+	__isl_take isl_mat *div)
+{
+	isl_ctx *ctx;
+	isl_local_space *ls = NULL;
+
+	if (!dim || !div)
+		goto error;
+
+	ctx = isl_space_get_ctx(dim);
+	ls = isl_calloc_type(ctx, struct isl_local_space);
+	if (!ls)
+		goto error;
+
+	ls->ref = 1;
+	ls->dim = dim;
+	ls->div = div;
+
+	return ls;
+error:
+	isl_mat_free(div);
+	isl_space_free(dim);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+	unsigned n_div)
+{
+	isl_ctx *ctx;
+	isl_mat *div;
+	unsigned total;
+
+	if (!dim)
+		return NULL;
+
+	total = isl_space_dim(dim, isl_dim_all);
+
+	ctx = isl_space_get_ctx(dim);
+	div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
+	return isl_local_space_alloc_div(dim, div);
+}
+
+__isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
+{
+	return isl_local_space_alloc(dim, 0);
+}
+
+__isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	ls->ref++;
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	return isl_local_space_alloc_div(isl_space_copy(ls->dim),
+					 isl_mat_copy(ls->div));
+
+}
+
+__isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (ls->ref == 1)
+		return ls;
+	ls->ref--;
+	return isl_local_space_dup(ls);
+}
+
+__isl_null isl_local_space *isl_local_space_free(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (--ls->ref > 0)
+		return NULL;
+
+	isl_space_free(ls->dim);
+	isl_mat_free(ls->div);
+
+	free(ls);
+
+	return NULL;
+}
+
+/* Is the local space that of a parameter domain?
+ */
+int isl_local_space_is_params(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return -1;
+	return isl_space_is_params(ls->dim);
+}
+
+/* Is the local space that of a set?
+ */
+int isl_local_space_is_set(__isl_keep isl_local_space *ls)
+{
+	return ls ? isl_space_is_set(ls->dim) : -1;
+}
+
+/* Return true if the two local spaces are identical, with identical
+ * expressions for the integer divisions.
+ */
+int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	int equal;
+
+	if (!ls1 || !ls2)
+		return -1;
+
+	equal = isl_space_is_equal(ls1->dim, ls2->dim);
+	if (equal < 0 || !equal)
+		return equal;
+
+	if (!isl_local_space_divs_known(ls1))
+		return 0;
+	if (!isl_local_space_divs_known(ls2))
+		return 0;
+
+	return isl_mat_is_equal(ls1->div, ls2->div);
+}
+
+/* Compare two isl_local_spaces.
+ *
+ * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
+ * than "ls2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do "prefer" divs that only involve
+ * earlier dimensions in the sense that we consider local spaces where
+ * the first differing div involves earlier dimensions to be smaller.
+ */
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	int i;
+	int cmp;
+	int known1, known2;
+	int last1, last2;
+	int n_col;
+
+	if (ls1 == ls2)
+		return 0;
+	if (!ls1)
+		return -1;
+	if (!ls2)
+		return 1;
+
+	cmp = isl_space_cmp(ls1->dim, ls2->dim);
+	if (cmp != 0)
+		return cmp;
+
+	if (ls1->div->n_row != ls2->div->n_row)
+		return ls1->div->n_row - ls2->div->n_row;
+
+	n_col = isl_mat_cols(ls1->div);
+	for (i = 0; i < ls1->div->n_row; ++i) {
+		known1 = isl_local_space_div_is_known(ls1, i);
+		known2 = isl_local_space_div_is_known(ls2, i);
+		if (!known1 && !known2)
+			continue;
+		if (!known1)
+			return 1;
+		if (!known2)
+			return -1;
+		last1 = isl_seq_last_non_zero(ls1->div->row[i] + 1, n_col - 1);
+		last2 = isl_seq_last_non_zero(ls2->div->row[i] + 1, n_col - 1);
+		if (last1 != last2)
+			return last1 - last2;
+		cmp = isl_seq_cmp(ls1->div->row[i], ls2->div->row[i], n_col);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	if (!ls)
+		return 0;
+	if (type == isl_dim_div)
+		return ls->div->n_row;
+	if (type == isl_dim_all)
+		return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
+	return isl_space_dim(ls->dim, type);
+}
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	isl_space *dim;
+
+	if (!ls)
+		return 0;
+
+	dim = ls->dim;
+	switch (type) {
+	case isl_dim_cst:	return 0;
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	case isl_dim_div:	return 1 + dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "ls".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, const char *name)
+{
+	if (!ls)
+		return -1;
+	if (type == isl_dim_div)
+		return -1;
+	return isl_space_find_dim_by_name(ls->dim, type, name);
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_has_dim_name(ls->dim, type, pos) : -1;
+}
+
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
+}
+
+int isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_has_dim_id(ls->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
+}
+
+__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+	int pos)
+{
+	isl_aff *aff;
+
+	if (!ls)
+		return NULL;
+
+	if (pos < 0 || pos >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return NULL);
+
+	if (isl_int_is_zero(ls->div->row[pos][0]))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"expression of div unknown", return NULL);
+	if (!isl_local_space_is_set(ls))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot represent divs of map spaces", return NULL);
+
+	aff = isl_aff_alloc(isl_local_space_copy(ls));
+	if (!aff)
+		return NULL;
+	isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
+	return aff;
+}
+
+__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	return isl_space_copy(ls->dim);
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_local_space *isl_local_space_set_tuple_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		goto error;
+	ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_name(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		goto error;
+	ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+	__isl_take isl_local_space *ls, __isl_take isl_space *dim)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !dim)
+		goto error;
+
+	isl_space_free(ls->dim);
+	ls->dim = dim;
+
+	return ls;
+error:
+	isl_local_space_free(ls);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reorder the columns of the given div definitions according to the
+ * given reordering.
+ * The order of the divs themselves is assumed not to change.
+ */
+static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
+	__isl_take isl_reordering *r)
+{
+	int i, j;
+	isl_mat *mat;
+	int extra;
+
+	if (!div || !r)
+		goto error;
+
+	extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
+	mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
+	if (!mat)
+		goto error;
+
+	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)
+			isl_int_set(mat->row[i][2 + r->pos[j]],
+				    div->row[i][2 + j]);
+	}
+
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return mat;
+error:
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Reorder the dimensions of "ls" according to the given reordering.
+ * The reordering r is assumed to have been extended with the local
+ * variables, leaving them in the same order.
+ */
+__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;
+
+	ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
+	if (!ls->div)
+		goto error;
+
+	ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
+
+	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(
+	__isl_take isl_local_space *ls, __isl_take isl_vec *div)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !div)
+		goto error;
+
+	if (ls->div->n_col != div->size)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"incompatible dimensions", goto error);
+
+	ls->div = isl_mat_add_zero_cols(ls->div, 1);
+	ls->div = isl_mat_add_rows(ls->div, 1);
+	if (!ls->div)
+		goto error;
+
+	isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
+	isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
+
+	isl_vec_free(div);
+	return ls;
+error:
+	isl_local_space_free(ls);
+	isl_vec_free(div);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+	__isl_take isl_local_space *ls, __isl_take isl_mat *div)
+{
+	ls = isl_local_space_cow(ls);
+
+	if (!ls || !div)
+		goto error;
+
+	isl_mat_free(ls->div);
+	ls->div = div;
+	return ls;
+error:
+	isl_mat_free(div);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Copy row "s" of "src" to row "d" of "dst", applying the expansion
+ * defined by "exp".
+ */
+static void expand_row(__isl_keep isl_mat *dst, int d,
+	__isl_keep isl_mat *src, int s, int *exp)
+{
+	int i;
+	unsigned c = src->n_col - src->n_row;
+
+	isl_seq_cpy(dst->row[d], src->row[s], c);
+	isl_seq_clr(dst->row[d] + c, dst->n_col - c);
+
+	for (i = 0; i < s; ++i)
+		isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
+}
+
+/* Compare (known) divs.
+ * Return non-zero if at least one of the two divs is unknown.
+ * In particular, if both divs are unknown, we respect their
+ * current order.  Otherwise, we sort the known div after the unknown
+ * div only if the known div depends on the unknown div.
+ */
+static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
+	unsigned n_row, unsigned n_col)
+{
+	int li, lj;
+	int unknown_i, unknown_j;
+
+	unknown_i = isl_int_is_zero(row_i[0]);
+	unknown_j = isl_int_is_zero(row_j[0]);
+
+	if (unknown_i && unknown_j)
+		return i - j;
+
+	if (unknown_i)
+		li = n_col - n_row + i;
+	else
+		li = isl_seq_last_non_zero(row_i, n_col);
+	if (unknown_j)
+		lj = n_col - n_row + j;
+	else
+		lj = isl_seq_last_non_zero(row_j, n_col);
+
+	if (li != lj)
+		return li - lj;
+
+	return isl_seq_cmp(row_i, row_j, n_col);
+}
+
+/* Call cmp_row for divs in a matrix.
+ */
+int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
+{
+	return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
+}
+
+/* Call cmp_row for divs in a basic map.
+ */
+static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
+	unsigned total)
+{
+	return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
+}
+
+/* Sort the divs in "bmap".
+ *
+ * We first make sure divs are placed after divs on which they depend.
+ * Then we perform a simple insertion sort based on the same ordering
+ * that is used in isl_merge_divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned total;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	if (!bmap)
+		return NULL;
+	if (bmap->n_div <= 1)
+		return bmap;
+
+	total = 2 + isl_basic_map_total_dim(bmap);
+	for (i = 1; i < bmap->n_div; ++i) {
+		for (j = i - 1; j >= 0; --j) {
+			if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
+				break;
+			isl_basic_map_swap_div(bmap, j, j + 1);
+		}
+	}
+
+	return bmap;
+}
+
+/* Sort the divs in the basic maps of "map".
+ */
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
+{
+	return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
+}
+
+/* Combine the two lists of divs into a single list.
+ * For each row i in div1, exp1[i] is set to the position of the corresponding
+ * row in the result.  Similarly for div2 and exp2.
+ * This function guarantees
+ *	exp1[i] >= i
+ *	exp1[i+1] > exp1[i]
+ * For optimal merging, the two input list should have been sorted.
+ */
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+	__isl_keep isl_mat *div2, int *exp1, int *exp2)
+{
+	int i, j, k;
+	isl_mat *div = NULL;
+	unsigned d;
+
+	if (!div1 || !div2)
+		return NULL;
+
+	d = div1->n_col - div1->n_row;
+	div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
+				d + div1->n_row + div2->n_row);
+	if (!div)
+		return NULL;
+
+	for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
+		int cmp;
+
+		expand_row(div, k, div1, i, exp1);
+		expand_row(div, k + 1, div2, j, exp2);
+
+		cmp = isl_mat_cmp_div(div, k, k + 1);
+		if (cmp == 0) {
+			exp1[i++] = k;
+			exp2[j++] = k;
+		} else if (cmp < 0) {
+			exp1[i++] = k;
+		} else {
+			exp2[j++] = k;
+			isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
+		}
+	}
+	for (; i < div1->n_row; ++i, ++k) {
+		expand_row(div, k, div1, i, exp1);
+		exp1[i] = k;
+	}
+	for (; j < div2->n_row; ++j, ++k) {
+		expand_row(div, k, div2, j, exp2);
+		exp2[j] = k;
+	}
+
+	div->n_row = k;
+	div->n_col = d + k;
+
+	return div;
+}
+
+/* Swap divs "a" and "b" in "ls".
+ */
+__isl_give isl_local_space *isl_local_space_swap_div(
+	__isl_take isl_local_space *ls, int a, int b)
+{
+	int offset;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return isl_local_space_free(ls));
+	offset = ls->div->n_col - ls->div->n_row;
+	ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
+	ls->div = isl_mat_swap_rows(ls->div, a, b);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+/* Construct a local space that contains all the divs in either
+ * "ls1" or "ls2".
+ */
+__isl_give isl_local_space *isl_local_space_intersect(
+	__isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
+{
+	isl_ctx *ctx;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div;
+	int equal;
+
+	if (!ls1 || !ls2)
+		goto error;
+
+	ctx = isl_local_space_get_ctx(ls1);
+	if (!isl_space_is_equal(ls1->dim, ls2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces should be identical", goto error);
+
+	if (ls2->div->n_row == 0) {
+		isl_local_space_free(ls2);
+		return ls1;
+	}
+
+	if (ls1->div->n_row == 0) {
+		isl_local_space_free(ls1);
+		return ls2;
+	}
+
+	exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
+	exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
+	if (!exp1 || !exp2)
+		goto error;
+
+	div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
+	if (!div)
+		goto error;
+
+	equal = isl_mat_is_equal(ls1->div, div);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		ls1 = isl_local_space_cow(ls1);
+	if (!ls1)
+		goto error;
+
+	free(exp1);
+	free(exp2);
+	isl_local_space_free(ls2);
+	isl_mat_free(ls1->div);
+	ls1->div = div;
+
+	return ls1;
+error:
+	free(exp1);
+	free(exp2);
+	isl_local_space_free(ls1);
+	isl_local_space_free(ls2);
+	return NULL;
+}
+
+/* Does "ls" have an explicit representation for div "div"?
+ */
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
+{
+	if (!ls)
+		return -1;
+	if (div < 0 || div >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"position out of bounds", return -1);
+	return !isl_int_is_zero(ls->div->row[div][0]);
+}
+
+int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
+{
+	int i;
+
+	if (!ls)
+		return -1;
+
+	for (i = 0; i < ls->div->n_row; ++i)
+		if (isl_int_is_zero(ls->div->row[i][0]))
+			return 0;
+
+	return 1;
+}
+
+__isl_give isl_local_space *isl_local_space_domain(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_drop_dims(ls, isl_dim_out,
+					0, isl_local_space_dim(ls, isl_dim_out));
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_range(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_drop_dims(ls, isl_dim_in,
+					0, isl_local_space_dim(ls, isl_dim_in));
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_range(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+/* Construct a local space for a map that has the given local
+ * space as domain and that has a zero-dimensional range.
+ */
+__isl_give isl_local_space *isl_local_space_from_domain(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_from_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_add_dims(
+	__isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
+{
+	int pos;
+
+	if (!ls)
+		return NULL;
+	pos = isl_local_space_dim(ls, type);
+	return isl_local_space_insert_dims(ls, type, pos, n);
+}
+
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_local_space *ls, int div)
+{
+	isl_ctx *ctx = ls->div->ctx;
+	unsigned total = ls->div->n_col - 2;
+
+	isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd,
+		    ctx->normalize_gcd, ls->div->row[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+
+	isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
+			    ctx->normalize_gcd, total);
+	isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
+			    ctx->normalize_gcd);
+	isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
+			    ctx->normalize_gcd);
+}
+
+/* Exploit the equalities in "eq" to simplify the expressions of
+ * the integer divisions in "ls".
+ * The integer divisions in "ls" are assumed to appear as regular
+ * dimensions in "eq".
+ */
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+	__isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
+{
+	int i, j, k;
+	unsigned total;
+	unsigned n_div;
+
+	if (!ls || !eq)
+		goto error;
+
+	total = isl_space_dim(eq->dim, isl_dim_all);
+	if (isl_local_space_dim(ls, isl_dim_all) != total)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", goto error);
+	total++;
+	n_div = eq->n_div;
+	for (i = 0; i < eq->n_eq; ++i) {
+		j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+		if (j < 0 || j == 0 || j >= total)
+			continue;
+
+		for (k = 0; k < ls->div->n_row; ++k) {
+			if (isl_int_is_zero(ls->div->row[k][1 + j]))
+				continue;
+			ls = isl_local_space_cow(ls);
+			if (!ls)
+				goto error;
+			ls->div = isl_mat_cow(ls->div);
+			if (!ls->div)
+				goto error;
+			isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
+					&ls->div->row[k][0]);
+			normalize_div(ls, k);
+		}
+	}
+
+	isl_basic_set_free(eq);
+	return ls;
+error:
+	isl_basic_set_free(eq);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Plug in the affine expressions "subs" of length "subs_len" (including
+ * the denominator and the constant term) into the variable at position "pos"
+ * of the "n" div expressions starting at "first".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division starting at "first" with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+	int first, int n)
+{
+	int i;
+	isl_int v;
+
+	if (n == 0)
+		return ls;
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->div = isl_mat_cow(ls->div);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	if (first + n > ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return isl_local_space_free(ls));
+
+	pos += isl_local_space_offset(ls, type);
+
+	isl_int_init(v);
+	for (i = first; i < ls->div->n_row; ++i) {
+		if (isl_int_is_zero(ls->div->row[i][1 + pos]))
+			continue;
+		isl_seq_substitute(ls->div->row[i], pos, subs,
+			ls->div->n_col, subs_len, v);
+		normalize_div(ls, i);
+	}
+	isl_int_clear(v);
+
+	return ls;
+}
+
+/* Plug in "subs" for dimension "type", "pos" in the integer divisions
+ * of "ls".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !subs)
+		return isl_local_space_free(ls);
+
+	if (!isl_space_is_equal(ls->dim, subs->ls->dim))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", return isl_local_space_free(ls));
+	if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+			"cannot handle divs yet",
+			return isl_local_space_free(ls));
+
+	return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
+					    subs->v->size, 0, ls->div->n_row);
+}
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	if (!ls)
+		return -1;
+	return isl_space_is_named_or_nested(ls->dim, type);
+}
+
+__isl_give isl_local_space *isl_local_space_drop_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+		return ls;
+
+	ctx = isl_local_space_get_ctx(ls);
+	if (first + n > isl_local_space_dim(ls, type))
+		isl_die(ctx, isl_error_invalid, "range out of bounds",
+			return isl_local_space_free(ls));
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	if (type == isl_dim_div) {
+		ls->div = isl_mat_drop_rows(ls->div, first, n);
+	} else {
+		ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
+		if (!ls->dim)
+			return isl_local_space_free(ls);
+	}
+
+	first += 1 + isl_local_space_offset(ls, type);
+	ls->div = isl_mat_drop_cols(ls->div, first, n);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_insert_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+		return ls;
+
+	ctx = isl_local_space_get_ctx(ls);
+	if (first > isl_local_space_dim(ls, type))
+		isl_die(ctx, isl_error_invalid, "position out of bounds",
+			return isl_local_space_free(ls));
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	if (type == isl_dim_div) {
+		ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
+	} else {
+		ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
+		if (!ls->dim)
+			return isl_local_space_free(ls);
+	}
+
+	first += 1 + isl_local_space_offset(ls, type);
+	ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Check if the constraints pointed to by "constraint" is a div
+ * constraint corresponding to div "div" in "ls".
+ *
+ * That is, if div = floor(f/m), then check if the constraint is
+ *
+ *		f - m d >= 0
+ * or
+ *		-(f-(m-1)) + m d >= 0
+ */
+int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!ls)
+		return -1;
+
+	if (isl_int_is_zero(ls->div->row[div][0]))
+		return 0;
+
+	pos = isl_local_space_offset(ls, isl_dim_div) + div;
+
+	if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
+		int neg;
+		isl_int_sub(ls->div->row[div][1],
+				ls->div->row[div][1], ls->div->row[div][0]);
+		isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+		neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
+		isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+		isl_int_add(ls->div->row[div][1],
+				ls->div->row[div][1], ls->div->row[div][0]);
+		if (!neg)
+			return 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return 0;
+	} else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
+		if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
+			return 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return 0;
+	} else
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Set active[i] to 1 if the dimension at position i is involved
+ * in the linear expression l.
+ */
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
+{
+	int i, j;
+	isl_ctx *ctx;
+	int *active = NULL;
+	unsigned total;
+	unsigned offset;
+
+	ctx = isl_local_space_get_ctx(ls);
+	total = isl_local_space_dim(ls, isl_dim_all);
+	active = isl_calloc_array(ctx, int, total);
+	if (total && !active)
+		return NULL;
+
+	for (i = 0; i < total; ++i)
+		active[i] = !isl_int_is_zero(l[i]);
+
+	offset = isl_local_space_offset(ls, isl_dim_div) - 1;
+	for (i = ls->div->n_row - 1; i >= 0; --i) {
+		if (!active[offset + i])
+			continue;
+		for (j = 0; j < total; ++j)
+			active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
+	}
+
+	return active;
+}
+
+/* Given a local space "ls" of a set, create a local space
+ * for the lift of the set.  In particular, the result
+ * is of the form [dim -> local[..]], with ls->div->n_row variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_local_space *isl_local_space_lift(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
+	ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
+	if (!ls->dim || !ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Construct a basic map that maps a set living in local space "ls"
+ * to the corresponding lifted local space.
+ */
+__isl_give isl_basic_map *isl_local_space_lifting(
+	__isl_take isl_local_space *ls)
+{
+	isl_basic_map *lifting;
+	isl_basic_set *bset;
+
+	if (!ls)
+		return NULL;
+	if (!isl_local_space_is_set(ls))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"lifting only defined on set spaces", goto error);
+
+	bset = isl_basic_set_from_local_space(ls);
+	lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
+	lifting = isl_basic_map_domain_map(lifting);
+	lifting = isl_basic_map_reverse(lifting);
+
+	return lifting;
+error:
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Compute the preimage of "ls" under the function represented by "ma".
+ * In other words, plug in "ma" in "ls".  The result is a local space
+ * that is part of the domain space of "ma".
+ *
+ * If the divs in "ls" are represented as
+ *
+ *	floor((a_i(p) + b_i x + c_i(divs))/n_i)
+ *
+ * and ma is represented by
+ *
+ *	x = D(p) + F(y) + G(divs')
+ *
+ * then the resulting divs are
+ *
+ *	floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
+ *
+ * We first copy over the divs from "ma" and then
+ * we add the modified divs from "ls".
+ */
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+	__isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space;
+	isl_local_space *res = NULL;
+	int n_div_ls, n_div_ma;
+	isl_int f, c1, c2, g;
+
+	ma = isl_multi_aff_align_divs(ma);
+	if (!ls || !ma)
+		goto error;
+	if (!isl_space_is_range_internal(ls->dim, ma->space))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	n_div_ls = isl_local_space_dim(ls, isl_dim_div);
+	n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+	space = isl_space_domain(isl_multi_aff_get_space(ma));
+	res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
+	if (!res)
+		goto error;
+
+	if (n_div_ma) {
+		isl_mat_free(res->div);
+		res->div = isl_mat_copy(ma->p[0]->ls->div);
+		res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
+		res->div = isl_mat_add_rows(res->div, n_div_ls);
+		if (!res->div)
+			goto error;
+	}
+
+	isl_int_init(f);
+	isl_int_init(c1);
+	isl_int_init(c2);
+	isl_int_init(g);
+
+	for (i = 0; i < ls->div->n_row; ++i) {
+		if (isl_int_is_zero(ls->div->row[i][0])) {
+			isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
+			continue;
+		}
+		isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
+				ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
+		normalize_div(res, n_div_ma + i);
+	}
+
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+
+	isl_local_space_free(ls);
+	isl_multi_aff_free(ma);
+	return res;
+error:
+	isl_local_space_free(ls);
+	isl_multi_aff_free(ma);
+	isl_local_space_free(res);
+	return NULL;
+}
+
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * Moving to/from local dimensions is not allowed.
+ * We currently assume that the dimension type changes.
+ */
+__isl_give isl_local_space *isl_local_space_move_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	unsigned g_dst_pos;
+	unsigned g_src_pos;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 &&
+	    !isl_local_space_is_named_or_nested(ls, src_type) &&
+	    !isl_local_space_is_named_or_nested(ls, dst_type))
+		return ls;
+
+	if (src_pos + n > isl_local_space_dim(ls, src_type))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"range out of bounds", return isl_local_space_free(ls));
+	if (dst_pos > isl_local_space_dim(ls, dst_type))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"position out of bounds",
+			return isl_local_space_free(ls));
+	if (src_type == isl_dim_div)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot move divs", return isl_local_space_free(ls));
+	if (dst_type == isl_dim_div)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot move to divs", return isl_local_space_free(ls));
+	if (dst_type == src_type && dst_pos == src_pos)
+		return ls;
+	if (dst_type == src_type)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+			"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;
+	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,
+					src_type, src_pos, n);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Remove any internal structure of the domain of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_domain(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (!ls->dim->nested[0])
+		return ls;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_flatten_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Remove any internal structure of the range of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_range(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (!ls->dim->nested[1])
+		return ls;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_flatten_range(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}

Added: polly/trunk/lib/External/isl/isl_local_space_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_local_space_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_local_space_private.h (added)
+++ polly/trunk/lib/External/isl/isl_local_space_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,75 @@
+#ifndef ISL_LOCAL_SPACE_PRIVATE_H
+#define ISL_LOCAL_SPACE_PRIVATE_H
+
+#include <isl/mat.h>
+#include <isl/set.h>
+#include <isl/local_space.h>
+
+struct isl_local_space {
+	int ref;
+
+	isl_space *dim;
+	isl_mat *div;
+};
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+	unsigned n_div);
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+	__isl_take isl_mat *div);
+
+__isl_give isl_local_space *isl_local_space_swap_div(
+	__isl_take isl_local_space *ls, int a, int b);
+__isl_give isl_local_space *isl_local_space_add_div(
+	__isl_take isl_local_space *ls, __isl_take isl_vec *div);
+
+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);
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+	__isl_take isl_local_space *ls, __isl_take isl_mat *div);
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div);
+int isl_local_space_divs_known(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+	__isl_take isl_local_space *ls, __isl_take isl_basic_set *eq);
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+	__isl_take isl_local_space *ls, __isl_take isl_space *dim);
+__isl_give isl_local_space *isl_local_space_realign(
+	__isl_take isl_local_space *ls, __isl_take isl_reordering *r);
+
+int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+	isl_int *constraint, unsigned div);
+
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l);
+
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+	int first, int n);
+__isl_give isl_local_space *isl_local_space_substitute(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_local_space *isl_local_space_lift(
+	__isl_take isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+	__isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma);
+
+__isl_give isl_local_space *isl_local_space_move_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_lp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_lp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_lp.c (added)
+++ polly/trunk/lib/External/isl/isl_lp.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/lp.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_options_private.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+
+enum isl_lp_result isl_tab_solve_lp(struct isl_basic_map *bmap, int maximize,
+				      isl_int *f, isl_int denom, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	struct isl_tab *tab;
+	enum isl_lp_result res;
+	unsigned dim = isl_basic_map_total_dim(bmap);
+
+	if (maximize)
+		isl_seq_neg(f, f, 1 + dim);
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	tab = isl_tab_from_basic_map(bmap, 0);
+	res = isl_tab_min(tab, f, denom, opt, opt_denom, 0);
+	if (res == isl_lp_ok && sol) {
+		*sol = isl_tab_get_sample_value(tab);
+		if (!*sol)
+			res = isl_lp_error;
+	}
+	isl_tab_free(tab);
+
+	if (maximize)
+		isl_seq_neg(f, f, 1 + dim);
+	if (maximize && opt)
+		isl_int_neg(*opt, *opt);
+
+	return res;
+}
+
+/* Given a basic map "bmap" and an affine combination of the variables "f"
+ * with denominator "denom", set *opt / *opt_denom to the minimal
+ * (or maximal if "maximize" is true) value attained by f/d over "bmap",
+ * assuming the basic map is not empty and the expression cannot attain
+ * arbitrarily small (or large) values.
+ * If opt_denom is NULL, then *opt is rounded up (or down)
+ * to the nearest integer.
+ * The return value reflects the nature of the result (empty, unbounded,
+ * minmimal or maximal value returned in *opt).
+ */
+enum isl_lp_result isl_basic_map_solve_lp(struct isl_basic_map *bmap, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	if (sol)
+		*sol = NULL;
+
+	if (!bmap)
+		return isl_lp_error;
+
+	return isl_tab_solve_lp(bmap, max, f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_basic_set_solve_lp(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	return isl_basic_map_solve_lp((struct isl_basic_map *)bset, max,
+					f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	int i;
+	isl_int o;
+	isl_int t;
+	isl_int opt_i;
+	isl_int opt_denom_i;
+	enum isl_lp_result res;
+	int max_div;
+	isl_vec *v = NULL;
+
+	if (!map)
+		return isl_lp_error;
+	if (map->n == 0)
+		return isl_lp_empty;
+
+	max_div = 0;
+	for (i = 0; i < map->n; ++i)
+		if (map->p[i]->n_div > max_div)
+			max_div = map->p[i]->n_div;
+	if (max_div > 0) {
+		unsigned total = isl_space_dim(map->dim, isl_dim_all);
+		v = isl_vec_alloc(map->ctx, 1 + total + max_div);
+		if (!v)
+			return isl_lp_error;
+		isl_seq_cpy(v->el, f, 1 + total);
+		isl_seq_clr(v->el + 1 + total, max_div);
+		f = v->el;
+	}
+
+	if (!opt && map->n > 1 && sol) {
+		isl_int_init(o);
+		opt = &o;
+	}
+	if (map->n > 0)
+		isl_int_init(opt_i);
+	if (map->n > 0 && opt_denom) {
+		isl_int_init(opt_denom_i);
+		isl_int_init(t);
+	}
+
+	res = isl_basic_map_solve_lp(map->p[0], max, f, d,
+					opt, opt_denom, sol);
+	if (res == isl_lp_error || res == isl_lp_unbounded)
+		goto done;
+
+	if (sol)
+		*sol = NULL;
+
+	for (i = 1; i < map->n; ++i) {
+		isl_vec *sol_i = NULL;
+		enum isl_lp_result res_i;
+		int better;
+
+		res_i = isl_basic_map_solve_lp(map->p[i], max, f, d,
+					    &opt_i,
+					    opt_denom ? &opt_denom_i : NULL,
+					    sol ? &sol_i : NULL);
+		if (res_i == isl_lp_error || res_i == isl_lp_unbounded) {
+			res = res_i;
+			goto done;
+		}
+		if (res_i == isl_lp_empty)
+			continue;
+		if (res == isl_lp_empty) {
+			better = 1;
+		} else if (!opt_denom) {
+			if (max)
+				better = isl_int_gt(opt_i, *opt);
+			else
+				better = isl_int_lt(opt_i, *opt);
+		} else {
+			isl_int_mul(t, opt_i, *opt_denom);
+			isl_int_submul(t, *opt, opt_denom_i);
+			if (max)
+				better = isl_int_is_pos(t);
+			else
+				better = isl_int_is_neg(t);
+		}
+		if (better) {
+			res = res_i;
+			if (opt)
+				isl_int_set(*opt, opt_i);
+			if (opt_denom)
+				isl_int_set(*opt_denom, opt_denom_i);
+			if (sol) {
+				isl_vec_free(*sol);
+				*sol = sol_i;
+			}
+		} else
+			isl_vec_free(sol_i);
+	}
+
+done:
+	isl_vec_free(v);
+	if (map->n > 0 && opt_denom) {
+		isl_int_clear(opt_denom_i);
+		isl_int_clear(t);
+	}
+	if (map->n > 0)
+		isl_int_clear(opt_i);
+	if (opt == &o)
+		isl_int_clear(o);
+	return res;
+}
+
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	return isl_map_solve_lp((struct isl_map *)set, max,
+					f, d, opt, opt_denom, sol);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters and divs.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_solve_lp and translate the results.
+ */
+static __isl_give isl_val *basic_set_opt_lp(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_basic_set_solve_lp(bset, max, obj->v->el + 1,
+					obj->v->el[0], &res->n, &res->d, NULL);
+	if (lp_res == isl_lp_ok)
+		return isl_val_normalize(res);
+	isl_val_free(res);
+	if (lp_res == isl_lp_error)
+		return NULL;
+	if (lp_res == isl_lp_empty)
+		return isl_val_nan(ctx);
+	if (max)
+		return isl_val_infty(ctx);
+	else
+		return isl_val_neginfty(ctx);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Align the divs of "bset" and "obj" and call basic_set_opt_lp.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val_aligned(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	isl_mat *bset_div = NULL;
+	isl_mat *div = NULL;
+	isl_val *res;
+	int bset_n_div, obj_n_div;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", return NULL);
+
+	bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+	obj_n_div = isl_aff_dim(obj, isl_dim_div);
+	if (bset_n_div == 0 && obj_n_div == 0)
+		return basic_set_opt_lp(bset, max, obj);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+
+	bset_div = isl_basic_set_get_divs(bset);
+	exp1 = isl_alloc_array(ctx, int, bset_n_div);
+	exp2 = isl_alloc_array(ctx, int, obj_n_div);
+	if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+		goto error;
+
+	div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+	bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+	obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+	res = basic_set_opt_lp(bset, max, obj);
+
+	isl_mat_free(bset_div);
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+error:
+	isl_mat_free(div);
+	isl_mat_free(bset_div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+	return NULL;
+}
+
+/* Return the optimal (rational) value of "obj" over "bset".
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	isl_val *res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	if (isl_space_match(bset->dim, isl_dim_param,
+			    obj->ls->dim, isl_dim_param))
+		return isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+	bset = isl_basic_set_align_params(bset, isl_aff_get_domain_space(obj));
+	obj = isl_aff_align_params(obj, isl_basic_set_get_space(bset));
+
+	res = isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+}
+
+/* Return the minimal (rational) value of "obj" over "bset".
+ *
+ * Return negative infinity if the minimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_lp_val(bset, 0, obj);
+}
+
+/* Return the maximal (rational) value of "obj" over "bset".
+ *
+ * Return infinity if the maximal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_lp_val(bset, 1, obj);
+}

Added: polly/trunk/lib/External/isl/isl_lp_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_lp_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_lp_private.h (added)
+++ polly/trunk/lib/External/isl/isl_lp_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,21 @@
+#ifndef ISL_LP_PRIVATE_H
+#define ISL_LP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/vec.h>
+
+enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap,
+	int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_basic_set_solve_lp(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_map.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map.c (added)
+++ polly/trunk/lib/External/isl/isl_map.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,12888 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_blk.h>
+#include "isl_space_private.h"
+#include "isl_equalities.h"
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include "isl_sample.h"
+#include <isl_sort.h>
+#include "isl_tab.h"
+#include <isl/vec.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_dim_map.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_options_private.h>
+#include <isl_morph.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/map_int.h>
+#include <isl/deprecated/set_int.h>
+
+static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return dim->nparam;
+	case isl_dim_in:	return dim->n_in;
+	case isl_dim_out:	return dim->n_out;
+	case isl_dim_all:	return dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+				enum isl_dim_type type)
+{
+	if (!bmap)
+		return 0;
+	switch (type) {
+	case isl_dim_cst:	return 1;
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:	return isl_space_dim(bmap->dim, type);
+	case isl_dim_div:	return bmap->n_div;
+	case isl_dim_all:	return isl_basic_map_total_dim(bmap);
+	default:		return 0;
+	}
+}
+
+unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? n(map->dim, type) : 0;
+}
+
+unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type)
+{
+	return set ? n(set->dim, type) : 0;
+}
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+					enum isl_dim_type type)
+{
+	isl_space *dim = bmap->dim;
+	switch (type) {
+	case isl_dim_cst:	return 0;
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	case isl_dim_div:	return 1 + dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+					enum isl_dim_type type)
+{
+	return isl_basic_map_offset(bset, type);
+}
+
+static unsigned map_offset(struct isl_map *map, enum isl_dim_type type)
+{
+	return pos(map->dim, type);
+}
+
+unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset,
+				enum isl_dim_type type)
+{
+	return isl_basic_map_dim(bset, type);
+}
+
+unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_dim(bset, isl_dim_set);
+}
+
+unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_dim(bset, isl_dim_param);
+}
+
+unsigned isl_basic_set_total_dim(const struct isl_basic_set *bset)
+{
+	if (!bset)
+		return 0;
+	return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div;
+}
+
+unsigned isl_set_n_dim(__isl_keep isl_set *set)
+{
+	return isl_set_dim(set, isl_dim_set);
+}
+
+unsigned isl_set_n_param(__isl_keep isl_set *set)
+{
+	return isl_set_dim(set, isl_dim_param);
+}
+
+unsigned isl_basic_map_n_in(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_in : 0;
+}
+
+unsigned isl_basic_map_n_out(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_out : 0;
+}
+
+unsigned isl_basic_map_n_param(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->nparam : 0;
+}
+
+unsigned isl_basic_map_n_div(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->n_div : 0;
+}
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap)
+{
+	return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0;
+}
+
+unsigned isl_map_n_in(const struct isl_map *map)
+{
+	return map ? map->dim->n_in : 0;
+}
+
+unsigned isl_map_n_out(const struct isl_map *map)
+{
+	return map ? map->dim->n_out : 0;
+}
+
+unsigned isl_map_n_param(const struct isl_map *map)
+{
+	return map ? map->dim->nparam : 0;
+}
+
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set)
+{
+	int m;
+	if (!map || !set)
+		return -1;
+	m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset)
+{
+	int m;
+	if (!bmap || !bset)
+		return -1;
+	m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+					bset->dim, isl_dim_set);
+}
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
+{
+	int m;
+	if (!map || !set)
+		return -1;
+	m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_out,
+					set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset)
+{
+	int m;
+	if (!bmap || !bset)
+		return -1;
+	m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(bmap->dim, isl_dim_out,
+					bset->dim, isl_dim_set);
+}
+
+isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap)
+{
+	return bmap ? bmap->ctx : NULL;
+}
+
+isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset)
+{
+	return bset ? bset->ctx : NULL;
+}
+
+isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map)
+{
+	return map ? map->ctx : NULL;
+}
+
+isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set)
+{
+	return set ? set->ctx : NULL;
+}
+
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	return isl_space_copy(bmap->dim);
+}
+
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return NULL;
+	return isl_space_copy(bset->dim);
+}
+
+/* Extract the divs in "bmap" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_mat *div;
+	unsigned total;
+	unsigned cols;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	cols = 1 + 1 + total + bmap->n_div;
+	div = isl_mat_alloc(ctx, bmap->n_div, cols);
+	if (!div)
+		return NULL;
+
+	for (i = 0; i < bmap->n_div; ++i)
+		isl_seq_cpy(div->row[i], bmap->div[i], cols);
+
+	return div;
+}
+
+/* Extract the divs in "bset" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_divs(bset);
+}
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+	__isl_keep isl_basic_map *bmap)
+{
+	isl_mat *div;
+
+	if (!bmap)
+		return NULL;
+
+	div = isl_basic_map_get_divs(bmap);
+	return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div);
+}
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+	__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_local_space(bset);
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+	__isl_take isl_local_space *ls)
+{
+	int i;
+	int n_div;
+	isl_basic_map *bmap;
+
+	if (!ls)
+		return NULL;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	bmap = isl_basic_map_alloc_space(isl_local_space_get_space(ls),
+					n_div, 0, 2 * n_div);
+
+	for (i = 0; i < n_div; ++i)
+		if (isl_basic_map_alloc_div(bmap) < 0)
+			goto error;
+
+	for (i = 0; i < n_div; ++i) {
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+		if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+			goto error;
+	}
+					
+	isl_local_space_free(ls);
+	return bmap;
+error:
+	isl_local_space_free(ls);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+	__isl_take isl_local_space *ls)
+{
+	return isl_basic_map_from_local_space(ls);
+}
+
+__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map)
+{
+	if (!map)
+		return NULL;
+	return isl_space_copy(map->dim);
+}
+
+__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set)
+{
+	if (!set)
+		return NULL;
+	return isl_space_copy(set->dim);
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_tuple_name(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_set_tuple_name(bmap->dim, type, s);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_tuple_name(
+	__isl_take isl_basic_set *bset, const char *s)
+{
+	return isl_basic_map_set_tuple_name(bset, isl_dim_set, s);
+}
+
+const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type)
+{
+	return bmap ? isl_space_get_tuple_name(bmap->dim, type) : NULL;
+}
+
+__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
+	enum isl_dim_type type, const char *s)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_set_tuple_name(map->dim, type, s);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_tuple_name(map->p[i], type, s);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_basic_map *isl_basic_map_set_tuple_id(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap->dim = isl_space_set_tuple_id(bmap->dim, type, id);
+	if (!bmap->dim)
+		return isl_basic_map_free(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Replace the identifier of the tuple by "id".
+ */
+__isl_give isl_basic_set *isl_basic_set_set_tuple_id(
+	__isl_take isl_basic_set *bset, __isl_take isl_id *id)
+{
+	return isl_basic_map_set_tuple_id(bset, isl_dim_set, id);
+}
+
+/* Does the input or output tuple have a name?
+ */
+int isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? isl_space_has_tuple_name(map->dim, type) : -1;
+}
+
+const char *isl_map_get_tuple_name(__isl_keep isl_map *map,
+	enum isl_dim_type type)
+{
+	return map ? isl_space_get_tuple_name(map->dim, type) : NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
+	const char *s)
+{
+	return (isl_set *)isl_map_set_tuple_name((isl_map *)set, isl_dim_set, s);
+}
+
+__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	map->dim = isl_space_set_tuple_id(map->dim, type, id);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
+	__isl_take isl_id *id)
+{
+	return isl_map_set_tuple_id(set, isl_dim_set, id);
+}
+
+__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_reset_tuple_id(map->dim, type);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+}
+
+__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set)
+{
+	return isl_map_reset_tuple_id(set, isl_dim_set);
+}
+
+int isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? isl_space_has_tuple_id(map->dim, type) : -1;
+}
+
+__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map,
+	enum isl_dim_type type)
+{
+	return map ? isl_space_get_tuple_id(map->dim, type) : NULL;
+}
+
+int isl_set_has_tuple_id(__isl_keep isl_set *set)
+{
+	return isl_map_has_tuple_id(set, isl_dim_set);
+}
+
+__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set)
+{
+	return isl_map_get_tuple_id(set, isl_dim_set);
+}
+
+/* Does the set tuple have a name?
+ */
+int isl_set_has_tuple_name(__isl_keep isl_set *set)
+{
+	return set ? isl_space_has_tuple_name(set->dim, isl_dim_set) : -1;
+}
+
+
+const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset)
+{
+	return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_set_get_tuple_name(__isl_keep isl_set *set)
+{
+	return set ? isl_space_get_tuple_name(set->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bmap ? isl_space_get_dim_name(bmap->dim, type, pos) : NULL;
+}
+
+const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_map_has_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_has_dim_name(map->dim, type, pos) : -1;
+}
+
+const char *isl_map_get_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_get_dim_name(map->dim, type, pos) : NULL;
+}
+
+const char *isl_set_get_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_set_has_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return set ? isl_space_has_dim_name(set->dim, type, pos) : -1;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_dim_name(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s);
+	if (!bmap->dim)
+		goto error;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_set_dim_name(map->dim, type, pos, s);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_dim_name(map->p[i], type, pos, s);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_dim_name(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	return (isl_basic_set *)isl_basic_map_set_dim_name(
+		(isl_basic_map *)bset, type, pos, s);
+}
+
+__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	return (isl_set *)isl_map_set_dim_name((isl_map *)set, type, pos, s);
+}
+
+int isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bmap ? isl_space_has_dim_id(bmap->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL;
+}
+
+int isl_map_has_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_has_dim_id(map->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_get_dim_id(map->dim, type, pos) : NULL;
+}
+
+int isl_set_has_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_has_dim_id(set, type, pos);
+}
+
+__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_get_dim_id(set, type, pos);
+}
+
+__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	map->dim = isl_space_set_dim_id(map->dim, type, pos, id);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	return isl_map_set_dim_id(set, type, pos, id);
+}
+
+int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	if (!map)
+		return -1;
+	return isl_space_find_dim_by_id(map->dim, type, id);
+}
+
+int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	return isl_map_find_dim_by_id(set, type, id);
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "bmap".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, const char *name)
+{
+	if (!bmap)
+		return -1;
+	return isl_space_find_dim_by_name(bmap->dim, type, name);
+}
+
+int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type,
+	const char *name)
+{
+	if (!map)
+		return -1;
+	return isl_space_find_dim_by_name(map->dim, type, name);
+}
+
+int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type,
+	const char *name)
+{
+	return isl_map_find_dim_by_name(set, type, name);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "map".
+ */
+__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	space = isl_space_reset_user(space);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "set".
+ */
+__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set)
+{
+	return isl_map_reset_user(set);
+}
+
+int isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+}
+
+int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_is_rational(bset);
+}
+
+/* Does "bmap" contain any rational points?
+ *
+ * If "bmap" has an equality for each dimension, equating the dimension
+ * to an integer constant, then it has no rational points, even if it
+ * is marked as rational.
+ */
+int isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap)
+{
+	int has_rational = 1;
+	unsigned total;
+
+	if (!bmap)
+		return -1;
+	if (isl_basic_map_plain_is_empty(bmap))
+		return 0;
+	if (!isl_basic_map_is_rational(bmap))
+		return 0;
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_implicit_equalities(bmap);
+	if (!bmap)
+		return -1;
+	total = isl_basic_map_total_dim(bmap);
+	if (bmap->n_eq == total) {
+		int i, j;
+		for (i = 0; i < bmap->n_eq; ++i) {
+			j = isl_seq_first_non_zero(bmap->eq[i] + 1, total);
+			if (j < 0)
+				break;
+			if (!isl_int_is_one(bmap->eq[i][1 + j]) &&
+			    !isl_int_is_negone(bmap->eq[i][1 + j]))
+				break;
+			j = isl_seq_first_non_zero(bmap->eq[i] + 1 + j + 1,
+						    total - j - 1);
+			if (j >= 0)
+				break;
+		}
+		if (i == bmap->n_eq)
+			has_rational = 0;
+	}
+	isl_basic_map_free(bmap);
+
+	return has_rational;
+}
+
+/* Does "map" contain any rational points?
+ */
+int isl_map_has_rational(__isl_keep isl_map *map)
+{
+	int i;
+	int has_rational;
+
+	if (!map)
+		return -1;
+	for (i = 0; i < map->n; ++i) {
+		has_rational = isl_basic_map_has_rational(map->p[i]);
+		if (has_rational < 0)
+			return -1;
+		if (has_rational)
+			return 1;
+	}
+	return 0;
+}
+
+/* Does "set" contain any rational points?
+ */
+int isl_set_has_rational(__isl_keep isl_set *set)
+{
+	return isl_map_has_rational(set);
+}
+
+/* Is this basic set a parameter domain?
+ */
+int isl_basic_set_is_params(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return -1;
+	return isl_space_is_params(bset->dim);
+}
+
+/* Is this set a parameter domain?
+ */
+int isl_set_is_params(__isl_keep isl_set *set)
+{
+	if (!set)
+		return -1;
+	return isl_space_is_params(set->dim);
+}
+
+/* Is this map actually a parameter domain?
+ * Users should never call this function.  Outside of isl,
+ * a map can never be a parameter domain.
+ */
+int isl_map_is_params(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	return isl_space_is_params(map->dim);
+}
+
+static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx,
+		struct isl_basic_map *bmap, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	int i;
+	size_t row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + extra;
+
+	bmap->ctx = ctx;
+	isl_ctx_ref(ctx);
+
+	bmap->block = isl_blk_alloc(ctx, (n_ineq + n_eq) * row_size);
+	if (isl_blk_is_error(bmap->block))
+		goto error;
+
+	bmap->ineq = isl_alloc_array(ctx, isl_int *, n_ineq + n_eq);
+	if ((n_ineq + n_eq) && !bmap->ineq)
+		goto error;
+
+	if (extra == 0) {
+		bmap->block2 = isl_blk_empty();
+		bmap->div = NULL;
+	} else {
+		bmap->block2 = isl_blk_alloc(ctx, extra * (1 + row_size));
+		if (isl_blk_is_error(bmap->block2))
+			goto error;
+
+		bmap->div = isl_alloc_array(ctx, isl_int *, extra);
+		if (!bmap->div)
+			goto error;
+	}
+
+	for (i = 0; i < n_ineq + n_eq; ++i)
+		bmap->ineq[i] = bmap->block.data + i * row_size;
+
+	for (i = 0; i < extra; ++i)
+		bmap->div[i] = bmap->block2.data + i * (1 + row_size);
+
+	bmap->ref = 1;
+	bmap->flags = 0;
+	bmap->c_size = n_eq + n_ineq;
+	bmap->eq = bmap->ineq + n_ineq;
+	bmap->extra = extra;
+	bmap->n_eq = 0;
+	bmap->n_ineq = 0;
+	bmap->n_div = 0;
+	bmap->sample = NULL;
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *space;
+
+	space = isl_space_set_alloc(ctx, nparam, dim);
+	if (!space)
+		return NULL;
+
+	bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq);
+	return (struct isl_basic_set *)bmap;
+}
+
+struct isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	if (!dim)
+		return NULL;
+	isl_assert(dim->ctx, dim->n_in == 0, goto error);
+	bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	return (struct isl_basic_set *)bmap;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+
+	if (!dim)
+		return NULL;
+	bmap = isl_calloc_type(dim->ctx, struct isl_basic_map);
+	if (!bmap)
+		goto error;
+	bmap->dim = dim;
+
+	return basic_map_init(dim->ctx, bmap, extra, n_eq, n_ineq);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned in, unsigned out, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *dim;
+
+	dim = isl_space_alloc(ctx, nparam, in, out);
+	if (!dim)
+		return NULL;
+
+	bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	return bmap;
+}
+
+static void dup_constraints(
+		struct isl_basic_map *dst, struct isl_basic_map *src)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(src);
+
+	for (i = 0; i < src->n_eq; ++i) {
+		int j = isl_basic_map_alloc_equality(dst);
+		isl_seq_cpy(dst->eq[j], src->eq[i], 1+total);
+	}
+
+	for (i = 0; i < src->n_ineq; ++i) {
+		int j = isl_basic_map_alloc_inequality(dst);
+		isl_seq_cpy(dst->ineq[j], src->ineq[i], 1+total);
+	}
+
+	for (i = 0; i < src->n_div; ++i) {
+		int j = isl_basic_map_alloc_div(dst);
+		isl_seq_cpy(dst->div[j], src->div[i], 1+1+total);
+	}
+	ISL_F_SET(dst, ISL_BASIC_SET_FINAL);
+}
+
+struct isl_basic_map *isl_basic_map_dup(struct isl_basic_map *bmap)
+{
+	struct isl_basic_map *dup;
+
+	if (!bmap)
+		return NULL;
+	dup = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	if (!dup)
+		return NULL;
+	dup_constraints(dup, bmap);
+	dup->flags = bmap->flags;
+	dup->sample = isl_vec_copy(bmap->sample);
+	return dup;
+}
+
+struct isl_basic_set *isl_basic_set_dup(struct isl_basic_set *bset)
+{
+	struct isl_basic_map *dup;
+
+	dup = isl_basic_map_dup((struct isl_basic_map *)bset);
+	return (struct isl_basic_set *)dup;
+}
+
+struct isl_basic_set *isl_basic_set_copy(struct 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);
+}
+
+struct isl_set *isl_set_copy(struct isl_set *set)
+{
+	if (!set)
+		return NULL;
+
+	set->ref++;
+	return set;
+}
+
+struct isl_basic_map *isl_basic_map_copy(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL)) {
+		bmap->ref++;
+		return bmap;
+	}
+	bmap = isl_basic_map_dup(bmap);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+struct isl_map *isl_map_copy(struct isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	map->ref++;
+	return map;
+}
+
+__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (--bmap->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(bmap->ctx);
+	free(bmap->div);
+	isl_blk_free(bmap->ctx, bmap->block2);
+	free(bmap->ineq);
+	isl_blk_free(bmap->ctx, bmap->block);
+	isl_vec_free(bmap->sample);
+	isl_space_free(bmap->dim);
+	free(bmap);
+
+	return NULL;
+}
+
+__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_free((struct isl_basic_map *)bset);
+}
+
+static int room_for_con(struct isl_basic_map *bmap, unsigned n)
+{
+	return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size;
+}
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+	__isl_take isl_map *map1, __isl_take isl_map *map2,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+				    __isl_take isl_map *map2))
+{
+	if (!map1 || !map2)
+		goto error;
+	if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+		return fn(map1, map2);
+	if (!isl_space_has_named_params(map1->dim) ||
+	    !isl_space_has_named_params(map2->dim))
+		isl_die(map1->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+	map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+	return fn(map1, map2);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2,
+	int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2))
+{
+	int r;
+
+	if (!map1 || !map2)
+		return -1;
+	if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+		return fn(map1, map2);
+	if (!isl_space_has_named_params(map1->dim) ||
+	    !isl_space_has_named_params(map2->dim))
+		isl_die(map1->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", return -1);
+	map1 = isl_map_copy(map1);
+	map2 = isl_map_copy(map2);
+	map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+	map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+	r = fn(map1, map2);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return r;
+}
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap)
+{
+	struct isl_ctx *ctx;
+	if (!bmap)
+		return -1;
+	ctx = bmap->ctx;
+	isl_assert(ctx, room_for_con(bmap, 1), return -1);
+	isl_assert(ctx, (bmap->eq - bmap->ineq) + bmap->n_eq <= bmap->c_size,
+			return -1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	if ((bmap->eq - bmap->ineq) + bmap->n_eq == bmap->c_size) {
+		isl_int *t;
+		int j = isl_basic_map_alloc_inequality(bmap);
+		if (j < 0)
+			return -1;
+		t = bmap->ineq[j];
+		bmap->ineq[j] = bmap->ineq[bmap->n_ineq - 1];
+		bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+		bmap->eq[-1] = t;
+		bmap->n_eq++;
+		bmap->n_ineq--;
+		bmap->eq--;
+		return 0;
+	}
+	isl_seq_clr(bmap->eq[bmap->n_eq] + 1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	return bmap->n_eq++;
+}
+
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_equality((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_eq, return -1);
+	bmap->n_eq -= n;
+	return 0;
+}
+
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_equality((struct isl_basic_map *)bset, n);
+}
+
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, pos < bmap->n_eq, return -1);
+
+	if (pos != bmap->n_eq - 1) {
+		t = bmap->eq[pos];
+		bmap->eq[pos] = bmap->eq[bmap->n_eq - 1];
+		bmap->eq[bmap->n_eq - 1] = t;
+	}
+	bmap->n_eq--;
+	return 0;
+}
+
+int isl_basic_set_drop_equality(struct isl_basic_set *bset, unsigned pos)
+{
+	return isl_basic_map_drop_equality((struct isl_basic_map *)bset, pos);
+}
+
+/* Turn inequality "pos" of "bmap" into an equality.
+ *
+ * In particular, we move the inequality in front of the equalities
+ * and move the last inequality in the position of the moved inequality.
+ * Note that isl_tab_make_equalities_explicit depends on this particular
+ * change in the ordering of the constraints.
+ */
+void isl_basic_map_inequality_to_equality(
+		struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+
+	t = bmap->ineq[pos];
+	bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+	bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+	bmap->eq[-1] = t;
+	bmap->n_eq++;
+	bmap->n_ineq--;
+	bmap->eq--;
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+}
+
+static int room_for_ineq(struct isl_basic_map *bmap, unsigned n)
+{
+	return bmap->n_ineq + n <= bmap->eq - bmap->ineq;
+}
+
+int isl_basic_map_alloc_inequality(struct isl_basic_map *bmap)
+{
+	struct isl_ctx *ctx;
+	if (!bmap)
+		return -1;
+	ctx = bmap->ctx;
+	isl_assert(ctx, room_for_ineq(bmap, 1), return -1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+	isl_seq_clr(bmap->ineq[bmap->n_ineq] +
+		      1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	return bmap->n_ineq++;
+}
+
+int isl_basic_set_alloc_inequality(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_inequality((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_ineq, return -1);
+	bmap->n_ineq -= n;
+	return 0;
+}
+
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_inequality((struct isl_basic_map *)bset, n);
+}
+
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+
+	if (pos != bmap->n_ineq - 1) {
+		t = bmap->ineq[pos];
+		bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+		bmap->ineq[bmap->n_ineq - 1] = t;
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+	bmap->n_ineq--;
+	return 0;
+}
+
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos)
+{
+	return isl_basic_map_drop_inequality((struct isl_basic_map *)bset, pos);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+	isl_int *eq)
+{
+	int k;
+
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	if (!bmap)
+		return NULL;
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bmap->eq[k], eq, 1 + isl_basic_map_total_dim(bmap));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+	isl_int *eq)
+{
+	return (isl_basic_set *)
+		isl_basic_map_add_eq((isl_basic_map *)bset, eq);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+	isl_int *ineq)
+{
+	int k;
+
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	if (!bmap)
+		return NULL;
+	k = isl_basic_map_alloc_inequality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bmap->ineq[k], ineq, 1 + isl_basic_map_total_dim(bmap));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+	isl_int *ineq)
+{
+	return (isl_basic_set *)
+		isl_basic_map_add_ineq((isl_basic_map *)bset, ineq);
+}
+
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, bmap->n_div < bmap->extra, return -1);
+	isl_seq_clr(bmap->div[bmap->n_div] +
+		      1 + 1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	return bmap->n_div++;
+}
+
+int isl_basic_set_alloc_div(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_div((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_div, return -1);
+	bmap->n_div -= n;
+	return 0;
+}
+
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_div((struct isl_basic_map *)bset, n);
+}
+
+/* Copy constraint from src to dst, putting the vars of src at offset
+ * dim_off in dst and the divs of src at offset div_off in dst.
+ * If both sets are actually map, then dim_off applies to the input
+ * variables.
+ */
+static void copy_constraint(struct isl_basic_map *dst_map, isl_int *dst,
+			    struct isl_basic_map *src_map, isl_int *src,
+			    unsigned in_off, unsigned out_off, unsigned div_off)
+{
+	unsigned src_nparam = isl_basic_map_n_param(src_map);
+	unsigned dst_nparam = isl_basic_map_n_param(dst_map);
+	unsigned src_in = isl_basic_map_n_in(src_map);
+	unsigned dst_in = isl_basic_map_n_in(dst_map);
+	unsigned src_out = isl_basic_map_n_out(src_map);
+	unsigned dst_out = isl_basic_map_n_out(dst_map);
+	isl_int_set(dst[0], src[0]);
+	isl_seq_cpy(dst+1, src+1, isl_min(dst_nparam, src_nparam));
+	if (dst_nparam > src_nparam)
+		isl_seq_clr(dst+1+src_nparam,
+				dst_nparam - src_nparam);
+	isl_seq_clr(dst+1+dst_nparam, in_off);
+	isl_seq_cpy(dst+1+dst_nparam+in_off,
+		    src+1+src_nparam,
+		    isl_min(dst_in-in_off, src_in));
+	if (dst_in-in_off > src_in)
+		isl_seq_clr(dst+1+dst_nparam+in_off+src_in,
+				dst_in - in_off - src_in);
+	isl_seq_clr(dst+1+dst_nparam+dst_in, out_off);
+	isl_seq_cpy(dst+1+dst_nparam+dst_in+out_off,
+		    src+1+src_nparam+src_in,
+		    isl_min(dst_out-out_off, src_out));
+	if (dst_out-out_off > src_out)
+		isl_seq_clr(dst+1+dst_nparam+dst_in+out_off+src_out,
+				dst_out - out_off - src_out);
+	isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out, div_off);
+	isl_seq_cpy(dst+1+dst_nparam+dst_in+dst_out+div_off,
+		    src+1+src_nparam+src_in+src_out,
+		    isl_min(dst_map->extra-div_off, src_map->n_div));
+	if (dst_map->n_div-div_off > src_map->n_div)
+		isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out+
+				div_off+src_map->n_div,
+				dst_map->n_div - div_off - src_map->n_div);
+}
+
+static void copy_div(struct isl_basic_map *dst_map, isl_int *dst,
+		     struct isl_basic_map *src_map, isl_int *src,
+		     unsigned in_off, unsigned out_off, unsigned div_off)
+{
+	isl_int_set(dst[0], src[0]);
+	copy_constraint(dst_map, dst+1, src_map, src+1, in_off, out_off, div_off);
+}
+
+static struct isl_basic_map *add_constraints(struct isl_basic_map *bmap1,
+		struct isl_basic_map *bmap2, unsigned i_pos, unsigned o_pos)
+{
+	int i;
+	unsigned div_off;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	div_off = bmap1->n_div;
+
+	for (i = 0; i < bmap2->n_eq; ++i) {
+		int i1 = isl_basic_map_alloc_equality(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_constraint(bmap1, bmap1->eq[i1], bmap2, bmap2->eq[i],
+				i_pos, o_pos, div_off);
+	}
+
+	for (i = 0; i < bmap2->n_ineq; ++i) {
+		int i1 = isl_basic_map_alloc_inequality(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_constraint(bmap1, bmap1->ineq[i1], bmap2, bmap2->ineq[i],
+				i_pos, o_pos, div_off);
+	}
+
+	for (i = 0; i < bmap2->n_div; ++i) {
+		int i1 = isl_basic_map_alloc_div(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_div(bmap1, bmap1->div[i1], bmap2, bmap2->div[i],
+			 i_pos, o_pos, div_off);
+	}
+
+	isl_basic_map_free(bmap2);
+
+	return bmap1;
+
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+		struct isl_basic_set *bset2, unsigned pos)
+{
+	return (struct isl_basic_set *)
+		add_constraints((struct isl_basic_map *)bset1,
+				(struct isl_basic_map *)bset2, 0, pos);
+}
+
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *ext;
+	unsigned flags;
+	int dims_ok;
+
+	if (!dim)
+		goto error;
+
+	if (!base)
+		goto error;
+
+	dims_ok = isl_space_is_equal(base->dim, dim) &&
+		  base->extra >= base->n_div + extra;
+
+	if (dims_ok && room_for_con(base, n_eq + n_ineq) &&
+		       room_for_ineq(base, n_ineq)) {
+		isl_space_free(dim);
+		return base;
+	}
+
+	isl_assert(base->ctx, base->dim->nparam <= dim->nparam, goto error);
+	isl_assert(base->ctx, base->dim->n_in <= dim->n_in, goto error);
+	isl_assert(base->ctx, base->dim->n_out <= dim->n_out, goto error);
+	extra += base->extra;
+	n_eq += base->n_eq;
+	n_ineq += base->n_ineq;
+
+	ext = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	dim = NULL;
+	if (!ext)
+		goto error;
+
+	if (dims_ok)
+		ext->sample = isl_vec_copy(base->sample);
+	flags = base->flags;
+	ext = add_constraints(ext, base, 0, 0);
+	if (ext) {
+		ext->flags = flags;
+		ISL_F_CLR(ext, ISL_BASIC_SET_FINAL);
+	}
+
+	return ext;
+
+error:
+	isl_space_free(dim);
+	isl_basic_map_free(base);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_extend_space((struct isl_basic_map *)base, dim,
+							extra, n_eq, n_ineq);
+}
+
+struct isl_basic_map *isl_basic_map_extend_constraints(
+		struct isl_basic_map *base, unsigned n_eq, unsigned n_ineq)
+{
+	if (!base)
+		return NULL;
+	return isl_basic_map_extend_space(base, isl_space_copy(base->dim),
+					0, n_eq, n_ineq);
+}
+
+struct isl_basic_map *isl_basic_map_extend(struct isl_basic_map *base,
+		unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *dim;
+
+	if (!base)
+		return NULL;
+	dim = isl_space_alloc(base->ctx, nparam, n_in, n_out);
+	if (!dim)
+		goto error;
+
+	bmap = isl_basic_map_extend_space(base, dim, extra, n_eq, n_ineq);
+	return bmap;
+error:
+	isl_basic_map_free(base);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_extend(struct isl_basic_set *base,
+		unsigned nparam, unsigned dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_extend((struct isl_basic_map *)base,
+					nparam, 0, dim, extra, n_eq, n_ineq);
+}
+
+struct isl_basic_set *isl_basic_set_extend_constraints(
+		struct isl_basic_set *base, unsigned n_eq, unsigned n_ineq)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_extend_constraints((struct isl_basic_map *)base,
+						    n_eq, n_ineq);
+}
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_cow((struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (bmap->ref > 1) {
+		bmap->ref--;
+		bmap = isl_basic_map_dup(bmap);
+	}
+	if (bmap)
+		ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+struct isl_set *isl_set_cow(struct isl_set *set)
+{
+	if (!set)
+		return NULL;
+
+	if (set->ref == 1)
+		return set;
+	set->ref--;
+	return isl_set_dup(set);
+}
+
+struct isl_map *isl_map_cow(struct isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (map->ref == 1)
+		return map;
+	map->ref--;
+	return isl_map_dup(map);
+}
+
+static void swap_vars(struct isl_blk blk, isl_int *a,
+			unsigned a_len, unsigned b_len)
+{
+	isl_seq_cpy(blk.data, a+a_len, b_len);
+	isl_seq_cpy(blk.data+b_len, a, a_len);
+	isl_seq_cpy(a, blk.data, b_len+a_len);
+}
+
+static __isl_give isl_basic_map *isl_basic_map_swap_vars(
+	__isl_take isl_basic_map *bmap, unsigned pos, unsigned n1, unsigned n2)
+{
+	int i;
+	struct isl_blk blk;
+
+	if (!bmap)
+		goto error;
+
+	isl_assert(bmap->ctx,
+		pos + n1 + n2 <= 1 + isl_basic_map_total_dim(bmap), goto error);
+
+	if (n1 == 0 || n2 == 0)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	blk = isl_blk_alloc(bmap->ctx, n1 + n2);
+	if (isl_blk_is_error(blk))
+		goto error;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		swap_vars(blk,
+			  bmap->eq[i] + pos, n1, n2);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		swap_vars(blk,
+			  bmap->ineq[i] + pos, n1, n2);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		swap_vars(blk,
+			  bmap->div[i]+1 + pos, n1, n2);
+
+	isl_blk_free(bmap->ctx, blk);
+
+	ISL_F_CLR(bmap, ISL_BASIC_SET_NORMALIZED);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *isl_basic_set_swap_vars(
+	__isl_take isl_basic_set *bset, unsigned n)
+{
+	unsigned dim;
+	unsigned nparam;
+
+	if (!bset)
+		return NULL;
+
+	nparam = isl_basic_set_n_param(bset);
+	dim = isl_basic_set_n_dim(bset);
+	isl_assert(bset->ctx, n <= dim, goto error);
+
+	return isl_basic_map_swap_vars(bset, 1 + nparam, n, dim - n);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap)
+{
+	int i = 0;
+	unsigned total;
+	if (!bmap)
+		goto error;
+	total = isl_basic_map_total_dim(bmap);
+	isl_basic_map_free_div(bmap, bmap->n_div);
+	isl_basic_map_free_inequality(bmap, bmap->n_ineq);
+	if (bmap->n_eq > 0)
+		isl_basic_map_free_equality(bmap, bmap->n_eq-1);
+	else {
+		i = isl_basic_map_alloc_equality(bmap);
+		if (i < 0)
+			goto error;
+	}
+	isl_int_set_si(bmap->eq[i][0], 1);
+	isl_seq_clr(bmap->eq[i]+1, total);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+	isl_vec_free(bmap->sample);
+	bmap->sample = NULL;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_set_to_empty((struct isl_basic_map *)bset);
+}
+
+/* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints
+ * of "bmap").
+ */
+static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b)
+{
+	isl_int *t = bmap->div[a];
+	bmap->div[a] = bmap->div[b];
+	bmap->div[b] = t;
+}
+
+/* Swap divs "a" and "b" in "bmap" and adjust the constraints and
+ * div definitions accordingly.
+ */
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
+{
+	int i;
+	unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
+
+	swap_div(bmap, a, b);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		isl_int_swap(bmap->ineq[i][1+off+a], bmap->ineq[i][1+off+b]);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		isl_int_swap(bmap->div[i][1+1+off+a], bmap->div[i][1+1+off+b]);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (n == 0)
+		return map;
+
+	if (first + n > isl_map_dim(map, type) || first + n < first)
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_eliminate((isl_map *)set, type, first, n);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set,
+	unsigned first, unsigned n)
+{
+	return isl_set_eliminate(set, isl_dim_set, first, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	bmap = isl_basic_map_eliminate_vars(bmap,
+			    isl_space_dim(bmap->dim, isl_dim_all), bmap->n_div);
+	if (!bmap)
+		return NULL;
+	bmap->n_div = 0;
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_remove_divs(
+			(struct isl_basic_map *)bset);
+}
+
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set)
+{
+	return isl_map_remove_divs(set);
+}
+
+struct isl_basic_map *isl_basic_map_remove_dims(struct isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+	if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+	bmap = isl_basic_map_eliminate_vars(bmap,
+			isl_basic_map_offset(bmap, type) - 1 + first, n);
+	if (!bmap)
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY) && type == isl_dim_div)
+		return bmap;
+	bmap = isl_basic_map_drop(bmap, type, first, n);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Return true if the definition of the given div (recursively) involves
+ * any of the given variables.
+ */
+static int div_involves_vars(__isl_keep isl_basic_map *bmap, int div,
+	unsigned first, unsigned n)
+{
+	int i;
+	unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return 0;
+	if (isl_seq_first_non_zero(bmap->div[div] + 1 + first, n) >= 0)
+		return 1;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		if (div_involves_vars(bmap, i, first, n))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Try and add a lower and/or upper bound on "div" to "bmap"
+ * based on inequality "i".
+ * "total" is the total number of variables (excluding the divs).
+ * "v" is a temporary object that can be used during the calculations.
+ * If "lb" is set, then a lower bound should be constructed.
+ * If "ub" is set, then an upper bound should be constructed.
+ *
+ * The calling function has already checked that the inequality does not
+ * reference "div", but we still need to check that the inequality is
+ * of the right form.  We'll consider the case where we want to construct
+ * a lower bound.  The construction of upper bounds is similar.
+ *
+ * Let "div" be of the form
+ *
+ *	q = floor((a + f(x))/d)
+ *
+ * We essentially check if constraint "i" is of the form
+ *
+ *	b + f(x) >= 0
+ *
+ * so that we can use it to derive a lower bound on "div".
+ * However, we allow a slightly more general form
+ *
+ *	b + g(x) >= 0
+ *
+ * with the condition that the coefficients of g(x) - f(x) are all
+ * divisible by d.
+ * Rewriting this constraint as
+ *
+ *	0 >= -b - g(x)
+ *
+ * adding a + f(x) to both sides and dividing by d, we obtain
+ *
+ *	(a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d
+ *
+ * Taking the floor on both sides, we obtain
+ *
+ *	q >= floor((a-b)/d) + (f(x)-g(x))/d
+ *
+ * or
+ *
+ *	(g(x)-f(x))/d + ceil((b-a)/d) + q >= 0
+ *
+ * In the case of an upper bound, we construct the constraint
+ *
+ *	(g(x)+f(x))/d + floor((b+a)/d) - q >= 0
+ *
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq(
+	__isl_take isl_basic_map *bmap, int div, int i,
+	unsigned total, isl_int v, int lb, int ub)
+{
+	int j;
+
+	for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) {
+		if (lb) {
+			isl_int_sub(v, bmap->ineq[i][1 + j],
+					bmap->div[div][1 + 1 + j]);
+			lb = isl_int_is_divisible_by(v, bmap->div[div][0]);
+		}
+		if (ub) {
+			isl_int_add(v, bmap->ineq[i][1 + j],
+					bmap->div[div][1 + 1 + j]);
+			ub = isl_int_is_divisible_by(v, bmap->div[div][0]);
+		}
+	}
+	if (!lb && !ub)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub);
+	if (lb) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+			isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j],
+					bmap->div[div][1 + j]);
+			isl_int_cdiv_q(bmap->ineq[k][j],
+					bmap->ineq[k][j], bmap->div[div][0]);
+		}
+		isl_int_set_si(bmap->ineq[k][1 + total + div], 1);
+	}
+	if (ub) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+			isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j],
+					bmap->div[div][1 + j]);
+			isl_int_fdiv_q(bmap->ineq[k][j],
+					bmap->ineq[k][j], bmap->div[div][0]);
+		}
+		isl_int_set_si(bmap->ineq[k][1 + total + div], -1);
+	}
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* This function is called right before "div" is eliminated from "bmap"
+ * using Fourier-Motzkin.
+ * Look through the constraints of "bmap" for constraints on the argument
+ * of the integer division and use them to construct constraints on the
+ * integer division itself.  These constraints can then be combined
+ * during the Fourier-Motzkin elimination.
+ * Note that it is only useful to introduce lower bounds on "div"
+ * if "bmap" already contains upper bounds on "div" as the newly
+ * introduce lower bounds can then be combined with the pre-existing
+ * upper bounds.  Similarly for upper bounds.
+ * We therefore first check if "bmap" contains any lower and/or upper bounds
+ * on "div".
+ *
+ * It is interesting to note that the introduction of these constraints
+ * can indeed lead to more accurate results, even when compared to
+ * deriving constraints on the argument of "div" from constraints on "div".
+ * Consider, for example, the set
+ *
+ *	{ [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }
+ *
+ * The second constraint can be rewritten as
+ *
+ *	2 * [(-i-2j+3)/4] + k >= 0
+ *
+ * from which we can derive
+ *
+ *	-i - 2j + 3 >= -2k
+ *
+ * or
+ *
+ *	i + 2j <= 3 + 2k
+ *
+ * Combined with the first constraint, we obtain
+ *
+ *	-3 <= 3 + 2k	or	k >= -3
+ *
+ * If, on the other hand we derive a constraint on [(i+2j)/4] from
+ * the first constraint, we obtain
+ *
+ *	[(i + 2j)/4] >= [-3/4] = -1
+ *
+ * Combining this constraint with the second constraint, we obtain
+ *
+ *	k >= -2
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div(
+	__isl_take isl_basic_map *bmap, int div)
+{
+	int i;
+	int check_lb, check_ub;
+	isl_int v;
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return bmap;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+
+	check_lb = 0;
+	check_ub = 0;
+	for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) {
+		int s = isl_int_sgn(bmap->ineq[i][1 + total + div]);
+		if (s > 0)
+			check_ub = 1;
+		if (s < 0)
+			check_lb = 1;
+	}
+
+	if (!check_lb && !check_ub)
+		return bmap;
+
+	isl_int_init(v);
+
+	for (i = 0; bmap && i < bmap->n_ineq; ++i) {
+		if (!isl_int_is_zero(bmap->ineq[i][1 + total + div]))
+			continue;
+
+		bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v,
+							check_lb, check_ub);
+	}
+
+	isl_int_clear(v);
+
+	return bmap;
+}
+
+/* Remove all divs (recursively) involving any of the given dimensions
+ * in their definitions.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+	first += isl_basic_map_offset(bmap, type);
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (!div_involves_vars(bmap, i, first, n))
+			continue;
+		bmap = insert_bounds_on_div(bmap, i);
+		bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+		if (!bmap)
+			return NULL;
+		i = bmap->n_div;
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_remove_divs_involving_dims(bset, type, first, n);
+}
+
+__isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_divs_involving_dims(map->p[i],
+								type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_remove_divs_involving_dims((isl_map *)set,
+							      type, first, n);
+}
+
+/* Does the desciption of "bmap" depend on the specified dimensions?
+ * We also check whether the dimensions appear in any of the div definitions.
+ * In principle there is no need for this check.  If the dimensions appear
+ * in a div definition, they also appear in the defining constraints of that
+ * div.
+ */
+int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!bmap)
+		return -1;
+
+	if (first + n > isl_basic_map_dim(bmap, type))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", return -1);
+
+	first += isl_basic_map_offset(bmap, type);
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (isl_seq_first_non_zero(bmap->eq[i] + first, n) >= 0)
+			return 1;
+	for (i = 0; i < bmap->n_ineq; ++i)
+		if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0)
+			return 1;
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+int isl_map_involves_dims(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	if (first + n > isl_map_dim(map, type))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", return -1);
+
+	for (i = 0; i < map->n; ++i) {
+		int involves = isl_basic_map_involves_dims(map->p[i],
+							    type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+
+	return 0;
+}
+
+int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_involves_dims(bset, type, first, n);
+}
+
+int isl_set_involves_dims(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_map_involves_dims(set, type, first, n);
+}
+
+/* Return true if the definition of the given div is unknown or depends
+ * on unknown divs.
+ */
+static int div_is_unknown(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return 1;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		if (div_is_unknown(bmap, i))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_unknown_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (!div_is_unknown(bmap, i))
+			continue;
+		bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+		if (!bmap)
+			return NULL;
+		i = bmap->n_div;
+	}
+
+	return bmap;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_remove_unknown_divs(bset);
+}
+
+__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_unknown_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set)
+{
+	return (isl_set *)isl_map_remove_unknown_divs((isl_map *)set);
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_basic_set *)
+	    isl_basic_map_remove_dims((isl_basic_map *)bset, type, first, n);
+}
+
+struct isl_map *isl_map_remove_dims(struct isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+	
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_eliminate_vars(map->p[i],
+			isl_basic_map_offset(map->p[i], type) - 1 + first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	map = isl_map_drop(map, type, first, n);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_remove_dims((isl_map *)bset, type, first, n);
+}
+
+/* Project out n inputs starting at first using Fourier-Motzkin */
+struct isl_map *isl_map_remove_inputs(struct isl_map *map,
+	unsigned first, unsigned n)
+{
+	return isl_map_remove_dims(map, isl_dim_in, first, n);
+}
+
+static void dump_term(struct isl_basic_map *bmap,
+			isl_int c, int pos, FILE *out)
+{
+	const char *name;
+	unsigned in = isl_basic_map_n_in(bmap);
+	unsigned dim = in + isl_basic_map_n_out(bmap);
+	unsigned nparam = isl_basic_map_n_param(bmap);
+	if (!pos)
+		isl_int_print(out, c, 0);
+	else {
+		if (!isl_int_is_one(c))
+			isl_int_print(out, c, 0);
+		if (pos < 1 + nparam) {
+			name = isl_space_get_dim_name(bmap->dim,
+						isl_dim_param, pos - 1);
+			if (name)
+				fprintf(out, "%s", name);
+			else
+				fprintf(out, "p%d", pos - 1);
+		} else if (pos < 1 + nparam + in)
+			fprintf(out, "i%d", pos - 1 - nparam);
+		else if (pos < 1 + nparam + dim)
+			fprintf(out, "o%d", pos - 1 - nparam - in);
+		else
+			fprintf(out, "e%d", pos - 1 - nparam - dim);
+	}
+}
+
+static void dump_constraint_sign(struct isl_basic_map *bmap, isl_int *c,
+				int sign, FILE *out)
+{
+	int i;
+	int first;
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+	isl_int v;
+
+	isl_int_init(v);
+	for (i = 0, first = 1; i < len; ++i) {
+		if (isl_int_sgn(c[i]) * sign <= 0)
+			continue;
+		if (!first)
+			fprintf(out, " + ");
+		first = 0;
+		isl_int_abs(v, c[i]);
+		dump_term(bmap, v, i, out);
+	}
+	isl_int_clear(v);
+	if (first)
+		fprintf(out, "0");
+}
+
+static void dump_constraint(struct isl_basic_map *bmap, isl_int *c,
+				const char *op, FILE *out, int indent)
+{
+	int i;
+
+	fprintf(out, "%*s", indent, "");
+
+	dump_constraint_sign(bmap, c, 1, out);
+	fprintf(out, " %s ", op);
+	dump_constraint_sign(bmap, c, -1, out);
+
+	fprintf(out, "\n");
+
+	for (i = bmap->n_div; i < bmap->extra; ++i) {
+		if (isl_int_is_zero(c[1+isl_space_dim(bmap->dim, isl_dim_all)+i]))
+			continue;
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "ERROR: unused div coefficient not zero\n");
+		abort();
+	}
+}
+
+static void dump_constraints(struct isl_basic_map *bmap,
+				isl_int **c, unsigned n,
+				const char *op, FILE *out, int indent)
+{
+	int i;
+
+	for (i = 0; i < n; ++i)
+		dump_constraint(bmap, c[i], op, out, indent);
+}
+
+static void dump_affine(struct isl_basic_map *bmap, isl_int *exp, FILE *out)
+{
+	int j;
+	int first = 1;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	for (j = 0; j < 1 + total; ++j) {
+		if (isl_int_is_zero(exp[j]))
+			continue;
+		if (!first && isl_int_is_pos(exp[j]))
+			fprintf(out, "+");
+		dump_term(bmap, exp[j], j, out);
+		first = 0;
+	}
+}
+
+static void dump(struct isl_basic_map *bmap, FILE *out, int indent)
+{
+	int i;
+
+	dump_constraints(bmap, bmap->eq, bmap->n_eq, "=", out, indent);
+	dump_constraints(bmap, bmap->ineq, bmap->n_ineq, ">=", out, indent);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "e%d = [(", i);
+		dump_affine(bmap, bmap->div[i]+1, out);
+		fprintf(out, ")/");
+		isl_int_print(out, bmap->div[i][0], 0);
+		fprintf(out, "]\n");
+	}
+}
+
+void isl_basic_set_print_internal(struct isl_basic_set *bset,
+	FILE *out, int indent)
+{
+	if (!bset) {
+		fprintf(out, "null basic set\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, nparam: %d, dim: %d, extra: %d, flags: %x\n",
+			bset->ref, bset->dim->nparam, bset->dim->n_out,
+			bset->extra, bset->flags);
+	dump((struct isl_basic_map *)bset, out, indent);
+}
+
+void isl_basic_map_print_internal(struct isl_basic_map *bmap,
+	FILE *out, int indent)
+{
+	if (!bmap) {
+		fprintf(out, "null basic map\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, nparam: %d, in: %d, out: %d, extra: %d, "
+			"flags: %x, n_name: %d\n",
+		bmap->ref,
+		bmap->dim->nparam, bmap->dim->n_in, bmap->dim->n_out,
+		bmap->extra, bmap->flags, bmap->dim->n_id);
+	dump(bmap, out, indent);
+}
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos)
+{
+	unsigned total;
+	if (!bmap)
+		return -1;
+	total = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+	isl_seq_neg(bmap->ineq[pos], bmap->ineq[pos], 1 + total);
+	isl_int_sub_ui(bmap->ineq[pos][0], bmap->ineq[pos][0], 1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return 0;
+}
+
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags)
+{
+	struct isl_set *set;
+
+	if (!dim)
+		return NULL;
+	isl_assert(dim->ctx, dim->n_in == 0, goto error);
+	isl_assert(dim->ctx, n >= 0, goto error);
+	set = isl_alloc(dim->ctx, struct isl_set,
+			sizeof(struct isl_set) +
+			(n - 1) * sizeof(struct isl_basic_set *));
+	if (!set)
+		goto error;
+
+	set->ctx = dim->ctx;
+	isl_ctx_ref(set->ctx);
+	set->ref = 1;
+	set->size = n;
+	set->n = 0;
+	set->dim = dim;
+	set->flags = flags;
+	return set;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_set *isl_set_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned dim, int n, unsigned flags)
+{
+	struct isl_set *set;
+	isl_space *dims;
+
+	dims = isl_space_alloc(ctx, nparam, 0, dim);
+	if (!dims)
+		return NULL;
+
+	set = isl_set_alloc_space(dims, n, flags);
+	return set;
+}
+
+/* Make sure "map" has room for at least "n" more basic maps.
+ */
+struct isl_map *isl_map_grow(struct isl_map *map, int n)
+{
+	int i;
+	struct isl_map *grown = NULL;
+
+	if (!map)
+		return NULL;
+	isl_assert(map->ctx, n >= 0, goto error);
+	if (map->n + n <= map->size)
+		return map;
+	grown = isl_map_alloc_space(isl_map_get_space(map), map->n + n, map->flags);
+	if (!grown)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		grown->p[i] = isl_basic_map_copy(map->p[i]);
+		if (!grown->p[i])
+			goto error;
+		grown->n++;
+	}
+	isl_map_free(map);
+	return grown;
+error:
+	isl_map_free(grown);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Make sure "set" has room for at least "n" more basic sets.
+ */
+struct isl_set *isl_set_grow(struct isl_set *set, int n)
+{
+	return (struct isl_set *)isl_map_grow((struct isl_map *)set, n);
+}
+
+struct isl_set *isl_set_dup(struct isl_set *set)
+{
+	int i;
+	struct isl_set *dup;
+
+	if (!set)
+		return NULL;
+
+	dup = isl_set_alloc_space(isl_space_copy(set->dim), set->n, set->flags);
+	if (!dup)
+		return NULL;
+	for (i = 0; i < set->n; ++i)
+		dup = isl_set_add_basic_set(dup, isl_basic_set_copy(set->p[i]));
+	return dup;
+}
+
+struct isl_set *isl_set_from_basic_set(struct isl_basic_set *bset)
+{
+	return isl_map_from_basic_map(bset);
+}
+
+struct isl_map *isl_map_from_basic_map(struct isl_basic_map *bmap)
+{
+	struct isl_map *map;
+
+	if (!bmap)
+		return NULL;
+
+	map = isl_map_alloc_space(isl_space_copy(bmap->dim), 1, ISL_MAP_DISJOINT);
+	return isl_map_add_basic_map(map, bmap);
+}
+
+__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set,
+						__isl_take isl_basic_set *bset)
+{
+	return (struct isl_set *)isl_map_add_basic_map((struct isl_map *)set,
+						(struct isl_basic_map *)bset);
+}
+
+__isl_null isl_set *isl_set_free(__isl_take isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+
+	if (--set->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(set->ctx);
+	for (i = 0; i < set->n; ++i)
+		isl_basic_set_free(set->p[i]);
+	isl_space_free(set->dim);
+	free(set);
+
+	return NULL;
+}
+
+void isl_set_print_internal(struct isl_set *set, FILE *out, int indent)
+{
+	int i;
+
+	if (!set) {
+		fprintf(out, "null set\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, n: %d, nparam: %d, dim: %d, flags: %x\n",
+			set->ref, set->n, set->dim->nparam, set->dim->n_out,
+			set->flags);
+	for (i = 0; i < set->n; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "basic set %d:\n", i);
+		isl_basic_set_print_internal(set->p[i], out, indent+4);
+	}
+}
+
+void isl_map_print_internal(struct isl_map *map, FILE *out, int indent)
+{
+	int i;
+
+	if (!map) {
+		fprintf(out, "null map\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, n: %d, nparam: %d, in: %d, out: %d, "
+		     "flags: %x, n_name: %d\n",
+			map->ref, map->n, map->dim->nparam, map->dim->n_in,
+			map->dim->n_out, map->flags, map->dim->n_id);
+	for (i = 0; i < map->n; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "basic map %d:\n", i);
+		isl_basic_map_print_internal(map->p[i], out, indent+4);
+	}
+}
+
+struct isl_basic_map *isl_basic_map_intersect_domain(
+		struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_domain;
+
+	if (!bmap || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+					bset->dim, isl_dim_param), goto error);
+
+	if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+		isl_assert(bset->ctx,
+		    isl_basic_map_compatible_domain(bmap, bset), goto error);
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+			bset->n_div, bset->n_eq, bset->n_ineq);
+	bmap_domain = isl_basic_map_from_domain(bset);
+	bmap = add_constraints(bmap, bmap_domain, 0, 0);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_intersect_range(
+		struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_range;
+
+	if (!bmap || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+					bset->dim, isl_dim_param), goto error);
+
+	if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+		isl_assert(bset->ctx,
+		    isl_basic_map_compatible_range(bmap, bset), goto error);
+
+	if (isl_basic_set_is_universe(bset)) {
+		isl_basic_set_free(bset);
+		return bmap;
+	}
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+			bset->n_div, bset->n_eq, bset->n_ineq);
+	bmap_range = isl_basic_map_from_basic_set(bset, isl_space_copy(bset->dim));
+	bmap = add_constraints(bmap, bmap_range, 0, 0);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+int isl_basic_map_contains(struct isl_basic_map *bmap, struct isl_vec *vec)
+{
+	int i;
+	unsigned total;
+	isl_int s;
+
+	if (!bmap || !vec)
+		return -1;
+
+	total = 1 + isl_basic_map_total_dim(bmap);
+	if (total != vec->size)
+		return -1;
+
+	isl_int_init(s);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		isl_seq_inner_product(vec->el, bmap->eq[i], total, &s);
+		if (!isl_int_is_zero(s)) {
+			isl_int_clear(s);
+			return 0;
+		}
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		isl_seq_inner_product(vec->el, bmap->ineq[i], total, &s);
+		if (isl_int_is_neg(s)) {
+			isl_int_clear(s);
+			return 0;
+		}
+	}
+
+	isl_int_clear(s);
+
+	return 1;
+}
+
+int isl_basic_set_contains(struct isl_basic_set *bset, struct isl_vec *vec)
+{
+	return isl_basic_map_contains((struct isl_basic_map *)bset, vec);
+}
+
+struct isl_basic_map *isl_basic_map_intersect(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	struct isl_vec *sample = NULL;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+				     bmap2->dim, isl_dim_param), goto error);
+	if (isl_space_dim(bmap1->dim, isl_dim_all) ==
+				isl_space_dim(bmap1->dim, isl_dim_param) &&
+	    isl_space_dim(bmap2->dim, isl_dim_all) !=
+				isl_space_dim(bmap2->dim, isl_dim_param))
+		return isl_basic_map_intersect(bmap2, bmap1);
+
+	if (isl_space_dim(bmap2->dim, isl_dim_all) !=
+					isl_space_dim(bmap2->dim, isl_dim_param))
+		isl_assert(bmap1->ctx,
+			    isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+	if (bmap1->sample &&
+	    isl_basic_map_contains(bmap1, bmap1->sample) > 0 &&
+	    isl_basic_map_contains(bmap2, bmap1->sample) > 0)
+		sample = isl_vec_copy(bmap1->sample);
+	else if (bmap2->sample &&
+	    isl_basic_map_contains(bmap1, bmap2->sample) > 0 &&
+	    isl_basic_map_contains(bmap2, bmap2->sample) > 0)
+		sample = isl_vec_copy(bmap2->sample);
+
+	bmap1 = isl_basic_map_cow(bmap1);
+	if (!bmap1)
+		goto error;
+	bmap1 = isl_basic_map_extend_space(bmap1, isl_space_copy(bmap1->dim),
+			bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+	bmap1 = add_constraints(bmap1, bmap2, 0, 0);
+
+	if (!bmap1)
+		isl_vec_free(sample);
+	else if (sample) {
+		isl_vec_free(bmap1->sample);
+		bmap1->sample = sample;
+	}
+
+	bmap1 = isl_basic_map_simplify(bmap1);
+	return isl_basic_map_finalize(bmap1);
+error:
+	if (sample)
+		isl_vec_free(sample);
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_intersect(
+		struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_intersect(
+			(struct isl_basic_map *)bset1,
+			(struct isl_basic_map *)bset2);
+}
+
+__isl_give isl_basic_set *isl_basic_set_intersect_params(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	return isl_basic_set_intersect(bset1, bset2);
+}
+
+/* Special case of isl_map_intersect, where both map1 and map2
+ * are convex, without any divs and such that either map1 or map2
+ * contains a single constraint.  This constraint is then simply
+ * added to the other map.
+ */
+static __isl_give isl_map *map_intersect_add_constraint(
+	__isl_take isl_map *map1, __isl_take isl_map *map2)
+{
+	isl_assert(map1->ctx, map1->n == 1, goto error);
+	isl_assert(map2->ctx, map1->n == 1, goto error);
+	isl_assert(map1->ctx, map1->p[0]->n_div == 0, goto error);
+	isl_assert(map2->ctx, map1->p[0]->n_div == 0, goto error);
+
+	if (map2->p[0]->n_eq + map2->p[0]->n_ineq != 1)
+		return isl_map_intersect(map2, map1);
+
+	isl_assert(map2->ctx,
+		    map2->p[0]->n_eq + map2->p[0]->n_ineq == 1, goto error);
+
+	map1 = isl_map_cow(map1);
+	if (!map1)
+		goto error;
+	if (isl_map_plain_is_empty(map1)) {
+		isl_map_free(map2);
+		return map1;
+	}
+	map1->p[0] = isl_basic_map_cow(map1->p[0]);
+	if (map2->p[0]->n_eq == 1)
+		map1->p[0] = isl_basic_map_add_eq(map1->p[0], map2->p[0]->eq[0]);
+	else
+		map1->p[0] = isl_basic_map_add_ineq(map1->p[0],
+							map2->p[0]->ineq[0]);
+
+	map1->p[0] = isl_basic_map_simplify(map1->p[0]);
+	map1->p[0] = isl_basic_map_finalize(map1->p[0]);
+	if (!map1->p[0])
+		goto error;
+
+	if (isl_basic_map_plain_is_empty(map1->p[0])) {
+		isl_basic_map_free(map1->p[0]);
+		map1->n = 0;
+	}
+
+	isl_map_free(map2);
+
+	return map1;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* map2 may be either a parameter domain or a map living in the same
+ * space as map1.
+ */
+static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	unsigned flags = 0;
+	isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	if ((isl_map_plain_is_empty(map1) ||
+	     isl_map_plain_is_universe(map2)) &&
+	    isl_space_is_equal(map1->dim, map2->dim)) {
+		isl_map_free(map2);
+		return map1;
+	}
+	if ((isl_map_plain_is_empty(map2) ||
+	     isl_map_plain_is_universe(map1)) &&
+	    isl_space_is_equal(map1->dim, map2->dim)) {
+		isl_map_free(map1);
+		return map2;
+	}
+
+	if (map1->n == 1 && map2->n == 1 &&
+	    map1->p[0]->n_div == 0 && map2->p[0]->n_div == 0 &&
+	    isl_space_is_equal(map1->dim, map2->dim) &&
+	    (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 ||
+	     map2->p[0]->n_eq + map2->p[0]->n_ineq == 1))
+		return map_intersect_add_constraint(map1, map2);
+
+	if (isl_space_dim(map2->dim, isl_dim_all) !=
+				isl_space_dim(map2->dim, isl_dim_param))
+		isl_assert(map1->ctx,
+			    isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n * map2->n, flags);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = isl_basic_map_intersect(
+				    isl_basic_map_copy(map1->p[i]),
+				    isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part) < 0)
+				part = isl_basic_map_free(part);
+			result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	if (!map1 || !map2)
+		goto error;
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"spaces don't match", goto error);
+	return map_intersect_internal(map1, map2);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_intersect);
+}
+
+struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_intersect((struct isl_map *)set1,
+				  (struct isl_map *)set2);
+}
+
+/* map_intersect_internal accepts intersections
+ * with parameter domains, so we can just call that function.
+ */
+static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map,
+		__isl_take isl_set *params)
+{
+	return map_intersect_internal(map, params);
+}
+
+__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_intersect_params);
+}
+
+__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set,
+		__isl_take isl_set *params)
+{
+	return isl_map_intersect_params(set, params);
+}
+
+struct isl_basic_map *isl_basic_map_reverse(struct isl_basic_map *bmap)
+{
+	isl_space *dim;
+	struct isl_basic_set *bset;
+	unsigned in;
+
+	if (!bmap)
+		return NULL;
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	dim = isl_space_reverse(isl_space_copy(bmap->dim));
+	in = isl_basic_map_n_in(bmap);
+	bset = isl_basic_set_from_basic_map(bmap);
+	bset = isl_basic_set_swap_vars(bset, in);
+	return isl_basic_map_from_basic_set(bset, dim);
+}
+
+static __isl_give isl_basic_map *basic_map_space_reset(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!bmap)
+		return NULL;
+	if (!isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	space = isl_basic_map_get_space(bmap);
+	space = isl_space_reset(space, type);
+	bmap = isl_basic_map_reset_space(bmap, space);
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_insert_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	unsigned pos, unsigned n)
+{
+	isl_space *res_dim;
+	struct isl_basic_map *res;
+	struct isl_dim_map *dim_map;
+	unsigned total, off;
+	enum isl_dim_type t;
+
+	if (n == 0)
+		return basic_map_space_reset(bmap, type);
+
+	if (!bmap)
+		return NULL;
+
+	res_dim = isl_space_insert_dims(isl_basic_map_get_space(bmap), type, pos, n);
+
+	total = isl_basic_map_total_dim(bmap) + n;
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		if (t != type) {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+		} else {
+			unsigned size = isl_basic_map_dim(bmap, t);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+						0, pos, off);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+						pos, size - pos, off + pos + n);
+		}
+		off += isl_space_dim(res_dim, t);
+	}
+	isl_dim_map_div(dim_map, bmap, off);
+
+	res = isl_basic_map_alloc_space(res_dim,
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	if (isl_basic_map_is_rational(bmap))
+		res = isl_basic_map_set_rational(res);
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(bmap);
+		free(dim_map);
+		return isl_basic_map_set_to_empty(res);
+	}
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	return isl_basic_map_finalize(res);
+}
+
+__isl_give isl_basic_set *isl_basic_set_insert_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	return isl_basic_map_insert_dims(bset, type, pos, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!bmap)
+		return NULL;
+	return isl_basic_map_insert_dims(bmap, type,
+					isl_basic_map_dim(bmap, type), n);
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!bset)
+		return NULL;
+	isl_assert(bset->ctx, type != isl_dim_in, goto error);
+	return (isl_basic_set *)isl_basic_map_add((isl_basic_map *)bset, type, n);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static __isl_give isl_map *map_space_reset(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!map || !isl_space_is_named_or_nested(map->dim, type))
+		return map;
+
+	space = isl_map_get_space(map);
+	space = isl_space_reset(space, type);
+	map = isl_map_reset_space(map, space);
+	return map;
+}
+
+__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return map_space_reset(map, type);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_insert_dims(map->dim, type, pos, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_insert_dims(map->p[i], type, pos, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	return isl_map_insert_dims(set, type, pos, n);
+}
+
+__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!map)
+		return NULL;
+	return isl_map_insert_dims(map, type, isl_map_dim(map, type), n);
+}
+
+__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!set)
+		return NULL;
+	isl_assert(set->ctx, type != isl_dim_in, goto error);
+	return (isl_set *)isl_map_add_dims((isl_map *)set, type, n);
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_move_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	struct isl_dim_map *dim_map;
+	struct isl_basic_map *res;
+	enum isl_dim_type t;
+	unsigned total, off;
+
+	if (!bmap)
+		return NULL;
+	if (n == 0)
+		return bmap;
+
+	isl_assert(bmap->ctx, src_pos + n <= isl_basic_map_dim(bmap, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return bmap;
+
+	isl_assert(bmap->ctx, dst_type != src_type, goto error);
+
+	if (pos(bmap->dim, dst_type) + dst_pos ==
+	    pos(bmap->dim, src_type) + src_pos +
+					    ((src_type < dst_type) ? n : 0)) {
+		bmap = isl_basic_map_cow(bmap);
+		if (!bmap)
+			return NULL;
+
+		bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!bmap->dim)
+			goto error;
+
+		bmap = isl_basic_map_finalize(bmap);
+
+		return bmap;
+	}
+
+	total = isl_basic_map_total_dim(bmap);
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		unsigned size = isl_space_dim(bmap->dim, t);
+		if (t == dst_type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, dst_pos, off);
+			off += dst_pos;
+			isl_dim_map_dim_range(dim_map, bmap->dim, src_type,
+					    src_pos, n, off);
+			off += n;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    dst_pos, size - dst_pos, off);
+			off += size - dst_pos;
+		} else if (t == src_type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, src_pos, off);
+			off += src_pos;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					src_pos + n, size - src_pos - n, off);
+			off += size - src_pos - n;
+		} else {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+			off += size;
+		}
+	}
+	isl_dim_map_div(dim_map, bmap, off);
+
+	res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	if (!bmap)
+		goto error;
+
+	bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+					src_type, src_pos, n);
+	if (!bmap->dim)
+		goto error;
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	return (isl_basic_set *)isl_basic_map_move_dims(
+		(isl_basic_map *)bset, dst_type, dst_pos, src_type, src_pos, n);
+}
+
+__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	if (!set)
+		return NULL;
+	isl_assert(set->ctx, dst_type != isl_dim_in, goto error);
+	return (isl_set *)isl_map_move_dims((isl_map *)set, dst_type, dst_pos,
+					src_type, src_pos, n);
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (n == 0)
+		return map;
+
+	isl_assert(map->ctx, src_pos + n <= isl_map_dim(map, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return map;
+
+	isl_assert(map->ctx, dst_type != src_type, goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_move_dims(map->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_move_dims(map->p[i],
+						dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Move the specified dimensions to the last columns right before
+ * the divs.  Don't change the dimension specification of bmap.
+ * That's the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	struct isl_dim_map *dim_map;
+	struct isl_basic_map *res;
+	enum isl_dim_type t;
+	unsigned total, off;
+
+	if (!bmap)
+		return NULL;
+	if (pos(bmap->dim, type) + first + n ==
+				1 + isl_space_dim(bmap->dim, isl_dim_all))
+		return bmap;
+
+	total = isl_basic_map_total_dim(bmap);
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		unsigned size = isl_space_dim(bmap->dim, t);
+		if (t == type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, first, off);
+			off += first;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    first, n, total - bmap->n_div - n);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    first + n, size - (first + n), off);
+			off += size - (first + n);
+		} else {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+			off += size;
+		}
+	}
+	isl_dim_map_div(dim_map, bmap, off + n);
+
+	res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	return res;
+}
+
+/* Insert "n" rows in the divs of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the new divs.
+ * The space of "bmap" is not adjusted, however, which means
+ * that "bmap" is left in an inconsistent state.  Removing "n" dimensions
+ * from the space of "bmap" is the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap,
+	int n)
+{
+	int i;
+	size_t row_size;
+	isl_int **new_div;
+	isl_int *old;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + bmap->extra;
+	old = bmap->block2.data;
+	bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2,
+					(bmap->extra + n) * (1 + row_size));
+	if (!bmap->block2.data)
+		return isl_basic_map_free(bmap);
+	new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n);
+	if (!new_div)
+		return isl_basic_map_free(bmap);
+	for (i = 0; i < n; ++i) {
+		new_div[i] = bmap->block2.data +
+				(bmap->extra + i) * (1 + row_size);
+		isl_seq_clr(new_div[i], 1 + row_size);
+	}
+	for (i = 0; i < bmap->extra; ++i)
+		new_div[n + i] = bmap->block2.data + (bmap->div[i] - old);
+	free(bmap->div);
+	bmap->div = new_div;
+	bmap->n_div += n;
+	bmap->extra += n;
+
+	return bmap;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_basic_map *isl_basic_map_project_out(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (n == 0)
+		return basic_map_space_reset(bmap, type);
+
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return isl_basic_map_remove_dims(bmap, type, first, n);
+
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+
+	bmap = move_last(bmap, type, first, n);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = insert_div_rows(bmap, n);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+struct isl_basic_set *isl_basic_set_project_out(struct isl_basic_set *bset,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_basic_set *)isl_basic_map_project_out(
+			(isl_basic_map *)bset, type, first, n);
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (n == 0)
+		return map_space_reset(map, type);
+
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_drop_dims(map->dim, type, first, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_project_out(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_project_out((isl_map *)set, type, first, n);
+}
+
+static struct isl_basic_map *add_divs(struct isl_basic_map *bmap, unsigned n)
+{
+	int i, j;
+
+	for (i = 0; i < n; ++i) {
+		j = isl_basic_map_alloc_div(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->div[j], 1+1+isl_basic_map_total_dim(bmap));
+	}
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_range(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	isl_space *dim_result = NULL;
+	struct isl_basic_map *bmap;
+	unsigned n_in, n_out, n, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+	if (!isl_space_match(bmap1->dim, isl_dim_param,
+				bmap2->dim, isl_dim_param))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"parameters don't match", goto error);
+	if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_out,
+				    bmap2->dim, isl_dim_in))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	dim_result = isl_space_join(isl_space_copy(bmap1->dim),
+				  isl_space_copy(bmap2->dim));
+
+	n_in = isl_basic_map_n_in(bmap1);
+	n_out = isl_basic_map_n_out(bmap2);
+	n = isl_basic_map_n_out(bmap1);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + n;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_in);
+	isl_dim_map_div(dim_map1, bmap1, pos += n_out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div + n,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = add_divs(bmap, n);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_apply(
+		struct isl_basic_set *bset, struct isl_basic_map *bmap)
+{
+	if (!bset || !bmap)
+		goto error;
+
+	isl_assert(bset->ctx, isl_basic_map_compatible_domain(bmap, bset),
+		    goto error);
+
+	return (struct isl_basic_set *)
+		isl_basic_map_apply_range((struct isl_basic_map *)bset, bmap);
+error:
+	isl_basic_set_free(bset);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_domain(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx,
+	    isl_basic_map_n_in(bmap1) == isl_basic_map_n_in(bmap2), goto error);
+	isl_assert(bmap1->ctx,
+	    isl_basic_map_n_param(bmap1) == isl_basic_map_n_param(bmap2),
+	    goto error);
+
+	bmap1 = isl_basic_map_reverse(bmap1);
+	bmap1 = isl_basic_map_apply_range(bmap1, bmap2);
+	return isl_basic_map_reverse(bmap1);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+/* Given two basic maps A -> f(A) and B -> g(B), construct a basic map
+ * A \cap B -> f(A) + f(B)
+ */
+struct isl_basic_map *isl_basic_map_sum(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	unsigned n_in, n_out, nparam, total, pos;
+	struct isl_basic_map *bmap = NULL;
+	struct isl_dim_map *dim_map1, *dim_map2;
+	int i;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+		goto error);
+
+	nparam = isl_basic_map_n_param(bmap1);
+	n_in = isl_basic_map_n_in(bmap1);
+	n_out = isl_basic_map_n_out(bmap1);
+
+	total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + 2 * n_out;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap2->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+	isl_dim_map_div(dim_map1, bmap1, pos += n_in + n_out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_out);
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(bmap1->dim),
+			bmap1->n_div + bmap2->n_div + 2 * n_out,
+			bmap1->n_eq + bmap2->n_eq + n_out,
+			bmap1->n_ineq + bmap2->n_ineq);
+	for (i = 0; i < n_out; ++i) {
+		int j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[j], 1+total);
+		isl_int_set_si(bmap->eq[j][1+nparam+n_in+i], -1);
+		isl_int_set_si(bmap->eq[j][1+pos+i], 1);
+		isl_int_set_si(bmap->eq[j][1+pos-n_out+i], 1);
+	}
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = add_divs(bmap, 2 * n_out);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+/* Given two maps A -> f(A) and B -> g(B), construct a map
+ * A \cap B -> f(A) + f(B)
+ */
+struct isl_map *isl_map_sum(struct isl_map *map1, struct isl_map *map2)
+{
+	struct isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	result = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n * map2->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = isl_basic_map_sum(
+				    isl_basic_map_copy(map1->p[i]),
+				    isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part))
+				isl_basic_map_free(part);
+			else
+				result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	return (isl_set *)isl_map_sum((isl_map *)set1, (isl_map *)set2);
+}
+
+/* Given a basic map A -> f(A), construct A -> -f(A).
+ */
+struct isl_basic_map *isl_basic_map_neg(struct isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned off, n;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	n = isl_basic_map_dim(bmap, isl_dim_out);
+	off = isl_basic_map_offset(bmap, isl_dim_out);
+	for (i = 0; i < bmap->n_eq; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->eq[i][off+j], bmap->eq[i][off+j]);
+	for (i = 0; i < bmap->n_ineq; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->ineq[i][off+j], bmap->ineq[i][off+j]);
+	for (i = 0; i < bmap->n_div; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_neg(bset);
+}
+
+/* Given a map A -> f(A), construct A -> -f(A).
+ */
+struct isl_map *isl_map_neg(struct isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_neg(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_neg(__isl_take isl_set *set)
+{
+	return (isl_set *)isl_map_neg((isl_map *)set);
+}
+
+/* Given a basic map A -> f(A) and an integer d, construct a basic map
+ * A -> floor(f(A)/d).
+ */
+struct isl_basic_map *isl_basic_map_floordiv(struct isl_basic_map *bmap,
+		isl_int d)
+{
+	unsigned n_in, n_out, nparam, total, pos;
+	struct isl_basic_map *result = NULL;
+	struct isl_dim_map *dim_map;
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	n_out = isl_basic_map_n_out(bmap);
+
+	total = nparam + n_in + n_out + bmap->n_div + n_out;
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_div(dim_map, bmap, pos += n_in + n_out);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_out, pos += bmap->n_div);
+
+	result = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+			bmap->n_div + n_out,
+			bmap->n_eq, bmap->n_ineq + 2 * n_out);
+	result = isl_basic_map_add_constraints_dim_map(result, bmap, dim_map);
+	result = add_divs(result, n_out);
+	for (i = 0; i < n_out; ++i) {
+		int j;
+		j = isl_basic_map_alloc_inequality(result);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(result->ineq[j], 1+total);
+		isl_int_neg(result->ineq[j][1+nparam+n_in+i], d);
+		isl_int_set_si(result->ineq[j][1+pos+i], 1);
+		j = isl_basic_map_alloc_inequality(result);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(result->ineq[j], 1+total);
+		isl_int_set(result->ineq[j][1+nparam+n_in+i], d);
+		isl_int_set_si(result->ineq[j][1+pos+i], -1);
+		isl_int_sub_ui(result->ineq[j][0], d, 1);
+	}
+
+	result = isl_basic_map_simplify(result);
+	return isl_basic_map_finalize(result);
+error:
+	isl_basic_map_free(result);
+	return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+struct isl_map *isl_map_floordiv(struct isl_map *map, isl_int d)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_floordiv(map->p[i], d);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map,
+	__isl_take isl_val *d)
+{
+	if (!map || !d)
+		goto error;
+	if (!isl_val_is_int(d))
+		isl_die(isl_val_get_ctx(d), isl_error_invalid,
+			"expecting integer denominator", goto error);
+	map = isl_map_floordiv(map, d->n);
+	isl_val_free(d);
+	return map;
+error:
+	isl_map_free(map);
+	isl_val_free(d);
+	return NULL;
+}
+
+static struct isl_basic_map *var_equal(struct isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->eq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraints to "bmap" expressing i_pos < o_pos
+ */
+static struct isl_basic_map *var_less(struct isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos <= o_pos
+ */
+static __isl_give isl_basic_map *var_less_or_equal(
+	__isl_take isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraints to "bmap" expressing i_pos > o_pos
+ */
+static struct isl_basic_map *var_more(struct isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos >= o_pos
+ */
+static __isl_give isl_basic_map *var_more_or_equal(
+	__isl_take isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_equal(
+	__isl_take isl_space *dim, unsigned n_equal)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, n_equal, 0);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < n_equal && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] << o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim,
+	unsigned pos)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < pos && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	if (bmap)
+		bmap = var_less(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] <<= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_or_equal_at(
+	__isl_take isl_space *dim, unsigned pos)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	for (i = 0; i < pos; ++i)
+		bmap = var_equal(bmap, i);
+	bmap = var_less_or_equal(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on pairs of sets of dimension "dim" expressing i_pos > o_pos
+ */
+__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim,
+	unsigned pos)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < pos && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	if (bmap)
+		bmap = var_more(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] >>= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_more_or_equal_at(
+	__isl_take isl_space *dim, unsigned pos)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	for (i = 0; i < pos; ++i)
+		bmap = var_equal(bmap, i);
+	bmap = var_more_or_equal(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *dims,
+	unsigned n, int equal)
+{
+	struct isl_map *map;
+	int i;
+
+	if (n == 0 && equal)
+		return isl_map_universe(dims);
+
+	map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+	for (i = 0; i + 1 < n; ++i)
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_less_at(isl_space_copy(dims), i));
+	if (n > 0) {
+		if (equal)
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_less_or_equal_at(dims, n - 1));
+		else
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_less_at(dims, n - 1));
+	} else
+		isl_space_free(dims);
+
+	return map;
+}
+
+static __isl_give isl_map *map_lex_lte(__isl_take isl_space *dims, int equal)
+{
+	if (!dims)
+		return NULL;
+	return map_lex_lte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_lte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_lte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim)
+{
+	return map_lex_lte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim)
+{
+	return map_lex_lte(isl_space_map_from_set(set_dim), 1);
+}
+
+static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *dims,
+	unsigned n, int equal)
+{
+	struct isl_map *map;
+	int i;
+
+	if (n == 0 && equal)
+		return isl_map_universe(dims);
+
+	map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+	for (i = 0; i + 1 < n; ++i)
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_more_at(isl_space_copy(dims), i));
+	if (n > 0) {
+		if (equal)
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_more_or_equal_at(dims, n - 1));
+		else
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_more_at(dims, n - 1));
+	} else
+		isl_space_free(dims);
+
+	return map;
+}
+
+static __isl_give isl_map *map_lex_gte(__isl_take isl_space *dims, int equal)
+{
+	if (!dims)
+		return NULL;
+	return map_lex_gte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_gte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_gte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim)
+{
+	return map_lex_gte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim)
+{
+	return map_lex_gte(isl_space_map_from_set(set_dim), 1);
+}
+
+__isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_le(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_lt(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_ge(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_gt(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_le(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_lt(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_ge(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_gt(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_basic_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !dim)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_compatible(bset->dim, dim), goto error);
+	isl_space_free(bset->dim);
+	bmap = (struct isl_basic_map *) bset;
+	bmap->dim = dim;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_set_free(bset);
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_basic_map(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		goto error;
+	if (bmap->dim->n_in == 0)
+		return (struct isl_basic_set *)bmap;
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap->dim = isl_space_as_set_space(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_finalize(bmap);
+	return (struct isl_basic_set *)bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		f - m d >= 0
+ */
+static int add_upper_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return -1;
+	isl_seq_cpy(bmap->ineq[i], div + 1, 1 + total);
+	isl_int_neg(bmap->ineq[i][1 + pos], div[0]);
+
+	return 0;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		-(f-(n-1)) + m d >= 0
+ */
+static int add_lower_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return -1;
+	isl_seq_neg(bmap->ineq[i], div + 1, 1 + total);
+	isl_int_set(bmap->ineq[i][1 + pos], div[0]);
+	isl_int_add(bmap->ineq[i][0], bmap->ineq[i][0], bmap->ineq[i][1 + pos]);
+	isl_int_sub_ui(bmap->ineq[i][0], bmap->ineq[i][0], 1);
+
+	return 0;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(n-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ *		f - m d >= n
+ */
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	if (add_upper_div_constraint(bmap, pos, div) < 0)
+		return -1;
+	if (add_lower_div_constraint(bmap, pos, div) < 0)
+		return -1;
+	return 0;
+}
+
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+	unsigned pos, isl_int *div)
+{
+	return isl_basic_map_add_div_constraints_var((isl_basic_map *)bset,
+							pos, div);
+}
+
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	unsigned div_pos = total - bmap->n_div + div;
+
+	return isl_basic_map_add_div_constraints_var(bmap, div_pos,
+							bmap->div[div]);
+}
+
+/* For each known div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(n-1)) + m d >= 0
+ */
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	unsigned n_div;
+
+	if (!bmap)
+		return NULL;
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (n_div == 0)
+		return bmap;
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 2 * n_div);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+			return isl_basic_map_free(bmap);
+	}
+
+	bmap = isl_basic_map_remove_duplicate_constraints(bmap, NULL, 0);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+}
+
+/* Add the div constraint of sign "sign" for div "div" of "bmap".
+ *
+ * In particular, if this div is of the form d = floor(f/m),
+ * then add the constraint
+ *
+ *		f - m d >= 0
+ *
+ * if sign < 0 or the constraint
+ *
+ *		-(f-(n-1)) + m d >= 0
+ *
+ * if sign > 0.
+ */
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned div, int sign)
+{
+	unsigned total;
+	unsigned div_pos;
+
+	if (!bmap)
+		return -1;
+
+	total = isl_basic_map_total_dim(bmap);
+	div_pos = total - bmap->n_div + div;
+
+	if (sign < 0)
+		return add_upper_div_constraint(bmap, div_pos, bmap->div[div]);
+	else
+		return add_lower_div_constraint(bmap, div_pos, bmap->div[div]);
+}
+
+int isl_basic_set_add_div_constraints(struct isl_basic_set *bset, unsigned div)
+{
+	return isl_basic_map_add_div_constraints(bset, div);
+}
+
+struct isl_basic_set *isl_basic_map_underlying_set(
+		struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		goto error;
+	if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 &&
+	    bmap->n_div == 0 &&
+	    !isl_space_is_named_or_nested(bmap->dim, isl_dim_in) &&
+	    !isl_space_is_named_or_nested(bmap->dim, isl_dim_out))
+		return (struct isl_basic_set *)bmap;
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap->dim = isl_space_underlying(bmap->dim, bmap->n_div);
+	if (!bmap->dim)
+		goto error;
+	bmap->extra -= bmap->n_div;
+	bmap->n_div = 0;
+	bmap = isl_basic_map_finalize(bmap);
+	return (struct isl_basic_set *)bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+		__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_underlying_set((isl_basic_map *)bset);
+}
+
+/* Replace each element in "list" by the result of applying
+ * isl_basic_set_underlying_set to the element.
+ */
+__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set(
+	__isl_take isl_basic_set_list *list)
+{
+	int i, n;
+
+	if (!list)
+		return NULL;
+
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		bset = isl_basic_set_underlying_set(bset);
+		list = isl_basic_set_list_set_basic_set(list, i, bset);
+	}
+
+	return list;
+}
+
+struct isl_basic_map *isl_basic_map_overlying_set(
+	struct isl_basic_set *bset, struct isl_basic_map *like)
+{
+	struct isl_basic_map *bmap;
+	struct isl_ctx *ctx;
+	unsigned total;
+	int i;
+
+	if (!bset || !like)
+		goto error;
+	ctx = bset->ctx;
+	isl_assert(ctx, bset->n_div == 0, goto error);
+	isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(ctx, bset->dim->n_out == isl_basic_map_total_dim(like),
+			goto error);
+	if (isl_space_is_equal(bset->dim, like->dim) && like->n_div == 0) {
+		isl_basic_map_free(like);
+		return (struct isl_basic_map *)bset;
+	}
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+	total = bset->dim->n_out + bset->extra;
+	bmap = (struct isl_basic_map *)bset;
+	isl_space_free(bmap->dim);
+	bmap->dim = isl_space_copy(like->dim);
+	if (!bmap->dim)
+		goto error;
+	bmap->n_div = like->n_div;
+	bmap->extra += like->n_div;
+	if (bmap->extra) {
+		unsigned ltotal;
+		isl_int **div;
+		ltotal = total - bmap->extra + like->extra;
+		if (ltotal > total)
+			ltotal = total;
+		bmap->block2 = isl_blk_extend(ctx, bmap->block2,
+					bmap->extra * (1 + 1 + total));
+		if (isl_blk_is_error(bmap->block2))
+			goto error;
+		div = isl_realloc_array(ctx, bmap->div, isl_int *, bmap->extra);
+		if (!div)
+			goto error;
+		bmap->div = div;
+		for (i = 0; i < bmap->extra; ++i)
+			bmap->div[i] = bmap->block2.data + i * (1 + 1 + total);
+		for (i = 0; i < like->n_div; ++i) {
+			isl_seq_cpy(bmap->div[i], like->div[i], 1 + 1 + ltotal);
+			isl_seq_clr(bmap->div[i]+1+1+ltotal, total - ltotal);
+		}
+		bmap = isl_basic_map_add_known_div_constraints(bmap);
+	}
+	isl_basic_map_free(like);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(like);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_underlying_set(
+	struct isl_basic_set *bset, struct isl_basic_set *like)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_overlying_set(bset, (struct isl_basic_map *)like);
+}
+
+struct isl_set *isl_set_from_underlying_set(
+	struct isl_set *set, struct isl_basic_set *like)
+{
+	int i;
+
+	if (!set || !like)
+		goto error;
+	isl_assert(set->ctx, set->dim->n_out == isl_basic_set_total_dim(like),
+		    goto error);
+	if (isl_space_is_equal(set->dim, like->dim) && like->n_div == 0) {
+		isl_basic_set_free(like);
+		return set;
+	}
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_from_underlying_set(set->p[i],
+						      isl_basic_set_copy(like));
+		if (!set->p[i])
+			goto error;
+	}
+	isl_space_free(set->dim);
+	set->dim = isl_space_copy(like->dim);
+	if (!set->dim)
+		goto error;
+	isl_basic_set_free(like);
+	return set;
+error:
+	isl_basic_set_free(like);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_set *isl_map_underlying_set(struct isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	map->dim = isl_space_cow(map->dim);
+	if (!map->dim)
+		goto error;
+
+	for (i = 1; i < map->n; ++i)
+		isl_assert(map->ctx, map->p[0]->n_div == map->p[i]->n_div,
+				goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = (struct isl_basic_map *)
+				isl_basic_map_underlying_set(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	if (map->n == 0)
+		map->dim = isl_space_underlying(map->dim, 0);
+	else {
+		isl_space_free(map->dim);
+		map->dim = isl_space_copy(map->p[0]->dim);
+	}
+	if (!map->dim)
+		goto error;
+	return (struct isl_set *)map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_to_underlying_set(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_underlying_set((struct isl_map *)set);
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *dim)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !dim)
+		goto error;
+
+	isl_space_free(bmap->dim);
+	bmap->dim = dim;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+	return (isl_basic_set *)isl_basic_map_reset_space((isl_basic_map *)bset,
+							dim);
+}
+
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+	__isl_take isl_space *dim)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reset_space(map->p[i],
+						    isl_space_copy(dim));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = dim;
+
+	return map;
+error:
+	isl_map_free(map);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set,
+	__isl_take isl_space *dim)
+{
+	return (struct isl_set *) isl_map_reset_space((struct isl_map *)set, dim);
+}
+
+/* Compute the parameter domain of the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset)
+{
+	isl_space *space;
+	unsigned n;
+
+	if (isl_basic_set_is_params(bset))
+		return bset;
+
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_params(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return bset;
+}
+
+/* Construct a zero-dimensional basic set with the given parameter domain.
+ */
+__isl_give isl_basic_set *isl_basic_set_from_params(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *space;
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_set_from_params(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return bset;
+}
+
+/* Compute the parameter domain of the given set.
+ */
+__isl_give isl_set *isl_set_params(__isl_take isl_set *set)
+{
+	isl_space *space;
+	unsigned n;
+
+	if (isl_set_is_params(set))
+		return set;
+
+	n = isl_set_dim(set, isl_dim_set);
+	set = isl_set_project_out(set, isl_dim_set, 0, n);
+	space = isl_set_get_space(set);
+	space = isl_space_params(space);
+	set = isl_set_reset_space(set, space);
+	return set;
+}
+
+/* Construct a zero-dimensional set with the given parameter domain.
+ */
+__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set)
+{
+	isl_space *space;
+	space = isl_set_get_space(set);
+	space = isl_space_set_from_params(space);
+	set = isl_set_reset_space(set, space);
+	return set;
+}
+
+/* Compute the parameter domain of the given map.
+ */
+__isl_give isl_set *isl_map_params(__isl_take isl_map *map)
+{
+	isl_space *space;
+	unsigned n;
+
+	n = isl_map_dim(map, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, 0, n);
+	n = isl_map_dim(map, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, 0, n);
+	space = isl_map_get_space(map);
+	space = isl_space_params(space);
+	map = isl_map_reset_space(map, space);
+	return map;
+}
+
+struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap)
+{
+	isl_space *dim;
+	struct isl_basic_set *domain;
+	unsigned n_in;
+	unsigned n_out;
+
+	if (!bmap)
+		return NULL;
+	dim = isl_space_domain(isl_basic_map_get_space(bmap));
+
+	n_in = isl_basic_map_n_in(bmap);
+	n_out = isl_basic_map_n_out(bmap);
+	domain = isl_basic_set_from_basic_map(bmap);
+	domain = isl_basic_set_project_out(domain, isl_dim_set, n_in, n_out);
+
+	domain = isl_basic_set_reset_space(domain, dim);
+
+	return domain;
+}
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return isl_space_may_be_set(bmap->dim);
+}
+
+/* Is this basic map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_basic_map_is_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return isl_space_is_set(bmap->dim);
+}
+
+struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_is_set(bmap))
+		return bmap;
+	return isl_basic_map_domain(isl_basic_map_reverse(bmap));
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *domain;
+	int nparam, n_in, n_out;
+	unsigned total;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+	domain = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, domain);
+	bmap = isl_basic_map_extend_constraints(bmap, n_in, 0);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n_in; ++i) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[k], 1 + total);
+		isl_int_set_si(bmap->eq[k][1 + nparam + i], -1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n_in + n_out + i], 1);
+	}
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *range;
+	int nparam, n_in, n_out;
+	unsigned total;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	dim = isl_space_from_range(isl_space_range(isl_basic_map_get_space(bmap)));
+	range = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, range);
+	bmap = isl_basic_map_extend_constraints(bmap, n_out, 0);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n_out; ++i) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[k], 1 + total);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n_in + i], -1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n_in + n_out + i], 1);
+	}
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+int isl_map_may_be_set(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	return isl_space_may_be_set(map->dim);
+}
+
+/* Is this map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_map_is_set(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	return isl_space_is_set(map->dim);
+}
+
+struct isl_set *isl_map_range(struct isl_map *map)
+{
+	int i;
+	struct isl_set *set;
+
+	if (!map)
+		goto error;
+	if (isl_map_is_set(map))
+		return (isl_set *)map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	set = (struct isl_set *) map;
+	set->dim = isl_space_range(set->dim);
+	if (!set->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		set->p[i] = isl_basic_map_range(map->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	ISL_F_CLR(set, ISL_MAP_DISJOINT);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_domain_map(map->dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_domain_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *range_dim;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	range_dim = isl_space_range(isl_map_get_space(map));
+	range_dim = isl_space_from_range(range_dim);
+	map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+	map->dim = isl_space_join(map->dim, range_dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_range_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Given a wrapped map of the form A[B -> C],
+ * return the map A[B -> C] -> B.
+ */
+__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set)
+{
+	isl_id *id;
+	isl_map *map;
+
+	if (!set)
+		return NULL;
+	if (!isl_set_has_tuple_id(set))
+		return isl_map_domain_map(isl_set_unwrap(set));
+
+	id = isl_set_get_tuple_id(set);
+	map = isl_map_domain_map(isl_set_unwrap(set));
+	map = isl_map_set_tuple_id(map, isl_dim_in, id);
+
+	return map;
+}
+
+__isl_give isl_map *isl_map_from_set(__isl_take isl_set *set,
+	__isl_take isl_space *dim)
+{
+	int i;
+	struct isl_map *map = NULL;
+
+	set = isl_set_cow(set);
+	if (!set || !dim)
+		goto error;
+	isl_assert(set->ctx, isl_space_compatible(set->dim, dim), goto error);
+	map = (struct isl_map *)set;
+	for (i = 0; i < set->n; ++i) {
+		map->p[i] = isl_basic_map_from_basic_set(
+				set->p[i], isl_space_copy(dim));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = dim;
+	return map;
+error:
+	isl_space_free(dim);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_reverse(isl_basic_map_from_range(bset));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_range(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *space;
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_from_range(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return (isl_basic_map *)bset;
+}
+
+/* Create a relation with the given set as range.
+ * The domain of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set)
+{
+	isl_space *space;
+	space = isl_set_get_space(set);
+	space = isl_space_from_range(space);
+	set = isl_set_reset_space(set, space);
+	return (struct isl_map *)set;
+}
+
+/* Create a relation with the given set as domain.
+ * The range of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set)
+{
+	return isl_map_reverse(isl_map_from_range(set));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain_and_range(
+	__isl_take isl_basic_set *domain, __isl_take isl_basic_set *range)
+{
+	return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range);
+}
+
+__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain,
+	__isl_take isl_set *range)
+{
+	return isl_map_apply_range(isl_map_reverse(domain), range);
+}
+
+struct isl_set *isl_set_from_map(struct isl_map *map)
+{
+	int i;
+	struct isl_set *set = NULL;
+
+	if (!map)
+		return NULL;
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	map->dim = isl_space_as_set_space(map->dim);
+	if (!map->dim)
+		goto error;
+	set = (struct isl_set *)map;
+	for (i = 0; i < map->n; ++i) {
+		set->p[i] = isl_basic_set_from_basic_map(map->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags)
+{
+	struct isl_map *map;
+
+	if (!dim)
+		return NULL;
+	if (n < 0)
+		isl_die(dim->ctx, isl_error_internal,
+			"negative number of basic maps", goto error);
+	map = isl_alloc(dim->ctx, struct isl_map,
+			sizeof(struct isl_map) +
+			(n - 1) * sizeof(struct isl_basic_map *));
+	if (!map)
+		goto error;
+
+	map->ctx = dim->ctx;
+	isl_ctx_ref(map->ctx);
+	map->ref = 1;
+	map->size = n;
+	map->n = 0;
+	map->dim = dim;
+	map->flags = flags;
+	return map;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_map *isl_map_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned in, unsigned out, int n,
+		unsigned flags)
+{
+	struct isl_map *map;
+	isl_space *dims;
+
+	dims = isl_space_alloc(ctx, nparam, in, out);
+	if (!dims)
+		return NULL;
+
+	map = isl_map_alloc_space(dims, n, flags);
+	return map;
+}
+
+__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
+	bmap = isl_basic_map_set_to_empty(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *dim)
+{
+	struct isl_basic_set *bset;
+	bset = isl_basic_set_alloc_space(dim, 0, 1, 0);
+	bset = isl_basic_set_set_to_empty(bset);
+	return bset;
+}
+
+struct isl_basic_map *isl_basic_map_empty_like(struct isl_basic_map *model)
+{
+	struct isl_basic_map *bmap;
+	if (!model)
+		return NULL;
+	bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+	bmap = isl_basic_map_set_to_empty(bmap);
+	return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_empty_like_map(struct isl_map *model)
+{
+	struct isl_basic_map *bmap;
+	if (!model)
+		return NULL;
+	bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+	bmap = isl_basic_map_set_to_empty(bmap);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_empty_like(struct isl_basic_set *model)
+{
+	struct isl_basic_set *bset;
+	if (!model)
+		return NULL;
+	bset = isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+	bset = isl_basic_set_set_to_empty(bset);
+	return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, 0, 0);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *dim)
+{
+	struct isl_basic_set *bset;
+	bset = isl_basic_set_alloc_space(dim, 0, 0, 0);
+	bset = isl_basic_set_finalize(bset);
+	return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim)
+{
+	int i;
+	unsigned total = isl_space_dim(dim, isl_dim_all);
+	isl_basic_map *bmap;
+
+	bmap= isl_basic_map_alloc_space(dim, 0, 0, total);
+	for (i = 0; i < total; ++i) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->ineq[k], 1 + total);
+		isl_int_set_si(bmap->ineq[k][1 + i], 1);
+	}
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_basic_map_nat_universe(dim);
+}
+
+__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_map_from_basic_map(isl_basic_map_nat_universe(dim));
+}
+
+__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_map_nat_universe(dim);
+}
+
+__isl_give isl_basic_map *isl_basic_map_universe_like(
+		__isl_keep isl_basic_map *model)
+{
+	if (!model)
+		return NULL;
+	return isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+struct isl_basic_set *isl_basic_set_universe_like(struct isl_basic_set *model)
+{
+	if (!model)
+		return NULL;
+	return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+__isl_give isl_basic_set *isl_basic_set_universe_like_set(
+	__isl_keep isl_set *model)
+{
+	if (!model)
+		return NULL;
+	return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+__isl_give isl_map *isl_map_empty(__isl_take isl_space *dim)
+{
+	return isl_map_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_map *isl_map_empty_like(struct isl_map *model)
+{
+	if (!model)
+		return NULL;
+	return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_map *isl_map_empty_like_basic_map(struct isl_basic_map *model)
+{
+	if (!model)
+		return NULL;
+	return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
+}
+
+__isl_give isl_set *isl_set_empty(__isl_take isl_space *dim)
+{
+	return isl_set_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_set *isl_set_empty_like(struct isl_set *model)
+{
+	if (!model)
+		return NULL;
+	return isl_set_empty(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_map_universe(__isl_take isl_space *dim)
+{
+	struct isl_map *map;
+	if (!dim)
+		return NULL;
+	map = isl_map_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+	map = isl_map_add_basic_map(map, isl_basic_map_universe(dim));
+	return map;
+}
+
+__isl_give isl_set *isl_set_universe(__isl_take isl_space *dim)
+{
+	struct isl_set *set;
+	if (!dim)
+		return NULL;
+	set = isl_set_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+	set = isl_set_add_basic_set(set, isl_basic_set_universe(dim));
+	return set;
+}
+
+__isl_give isl_set *isl_set_universe_like(__isl_keep isl_set *model)
+{
+	if (!model)
+		return NULL;
+	return isl_set_universe(isl_space_copy(model->dim));
+}
+
+struct isl_map *isl_map_dup(struct isl_map *map)
+{
+	int i;
+	struct isl_map *dup;
+
+	if (!map)
+		return NULL;
+	dup = isl_map_alloc_space(isl_space_copy(map->dim), map->n, map->flags);
+	for (i = 0; i < map->n; ++i)
+		dup = isl_map_add_basic_map(dup, isl_basic_map_copy(map->p[i]));
+	return dup;
+}
+
+__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
+						__isl_take isl_basic_map *bmap)
+{
+	if (!bmap || !map)
+		goto error;
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(bmap);
+		return map;
+	}
+	isl_assert(map->ctx, isl_space_is_equal(map->dim, bmap->dim), goto error);
+	isl_assert(map->ctx, map->n < map->size, goto error);
+	map->p[map->n] = bmap;
+	map->n++;
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	if (map)
+		isl_map_free(map);
+	if (bmap)
+		isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_null isl_map *isl_map_free(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (--map->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(map->ctx);
+	for (i = 0; i < map->n; ++i)
+		isl_basic_map_free(map->p[i]);
+	isl_space_free(map->dim);
+	free(map);
+
+	return NULL;
+}
+
+struct isl_map *isl_map_extend(struct isl_map *base,
+		unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	int i;
+
+	base = isl_map_cow(base);
+	if (!base)
+		return NULL;
+
+	base->dim = isl_space_extend(base->dim, nparam, n_in, n_out);
+	if (!base->dim)
+		goto error;
+	for (i = 0; i < base->n; ++i) {
+		base->p[i] = isl_basic_map_extend_space(base->p[i],
+				isl_space_copy(base->dim), 0, 0, 0);
+		if (!base->p[i])
+			goto error;
+	}
+	return base;
+error:
+	isl_map_free(base);
+	return NULL;
+}
+
+struct isl_set *isl_set_extend(struct isl_set *base,
+		unsigned nparam, unsigned dim)
+{
+	return (struct isl_set *)isl_map_extend((struct isl_map *)base,
+							nparam, 0, dim);
+}
+
+static struct isl_basic_map *isl_basic_map_fix_pos_si(
+	struct isl_basic_map *bmap, unsigned pos, int value)
+{
+	int j;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	j = isl_basic_map_alloc_equality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[j][pos], -1);
+	isl_int_set_si(bmap->eq[j][0], value);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *isl_basic_map_fix_pos(
+	__isl_take isl_basic_map *bmap, unsigned pos, isl_int value)
+{
+	int j;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	j = isl_basic_map_alloc_equality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[j][pos], -1);
+	isl_int_set(bmap->eq[j][0], value);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_fix_si(struct isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	return isl_basic_map_fix_pos_si(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	return isl_basic_map_fix_pos(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bmap"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	if (!bmap || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"expecting integer value", goto error);
+	if (pos >= isl_basic_map_dim(bmap, type))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"index out of bounds", goto error);
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_fix_pos(bmap, pos, v->n);
+	isl_val_free(v);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bset"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	return isl_basic_map_fix_val(bset, type, pos, v);
+}
+
+struct isl_basic_set *isl_basic_set_fix_si(struct isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_fix_si((struct isl_basic_map *)bset,
+					type, pos, value);
+}
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_fix((struct isl_basic_map *)bset,
+					type, pos, value);
+}
+
+struct isl_basic_map *isl_basic_map_fix_input_si(struct isl_basic_map *bmap,
+		unsigned input, int value)
+{
+	return isl_basic_map_fix_si(bmap, isl_dim_in, input, value);
+}
+
+struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset,
+		unsigned dim, int value)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_fix_si((struct isl_basic_map *)bset,
+					isl_dim_set, dim, value);
+}
+
+static int remove_if_empty(__isl_keep isl_map *map, int i)
+{
+	int empty = isl_basic_map_plain_is_empty(map->p[i]);
+
+	if (empty < 0)
+		return -1;
+	if (!empty)
+		return 0;
+
+	isl_basic_map_free(map->p[i]);
+	if (i != map->n - 1) {
+		ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+		map->p[i] = map->p[map->n - 1];
+	}
+	map->n--;
+
+	return 0;
+}
+
+/* Perform "fn" on each basic map of "map", where we may not be holding
+ * the only reference to "map".
+ * In particular, "fn" should be a semantics preserving operation
+ * that we want to apply to all copies of "map".  We therefore need
+ * to be careful not to modify "map" in a way that breaks "map"
+ * in case anything goes wrong.
+ */
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+	__isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap))
+{
+	struct isl_basic_map *bmap;
+	int i;
+
+	if (!map)
+		return NULL;
+
+	for (i = map->n - 1; i >= 0; --i) {
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = fn(bmap);
+		if (!bmap)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_map *isl_map_fix_si(struct isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value);
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return (struct isl_set *)
+		isl_map_fix_si((struct isl_map *)set, type, pos, value);
+}
+
+__isl_give isl_map *isl_map_fix(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_fix(map->p[i], type, pos, value);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return (struct isl_set *)isl_map_fix((isl_map *)set, type, pos, value);
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "map"
+ * to be equal to "v".
+ */
+__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !v)
+		goto error;
+
+	if (!isl_val_is_int(v))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"expecting integer value", goto error);
+	if (pos >= isl_map_dim(map, type))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"index out of bounds", goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_fix_val(map->p[i], type, pos,
+							isl_val_copy(v));
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	isl_val_free(v);
+	return map;
+error:
+	isl_map_free(map);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "set"
+ * to be equal to "v".
+ */
+__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	return isl_map_fix_val(set, type, pos, v);
+}
+
+struct isl_map *isl_map_fix_input_si(struct isl_map *map,
+		unsigned input, int value)
+{
+	return isl_map_fix_si(map, isl_dim_in, input, value);
+}
+
+struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value)
+{
+	return (struct isl_set *)
+		isl_map_fix_si((struct isl_map *)set, isl_dim_set, dim, value);
+}
+
+static __isl_give isl_basic_map *basic_map_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+	int j;
+
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	j = isl_basic_map_alloc_inequality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+	if (upper) {
+		isl_int_set_si(bmap->ineq[j][pos], -1);
+		isl_int_set_si(bmap->ineq[j][0], value);
+	} else {
+		isl_int_set_si(bmap->ineq[j][pos], 1);
+		isl_int_set_si(bmap->ineq[j][0], -value);
+	}
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return basic_map_bound_si(bmap, type, pos, value, 0);
+}
+
+/* Constrain the values of the given dimension to be no greater than "value".
+ */
+__isl_give isl_basic_map *isl_basic_map_upper_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return basic_map_bound_si(bmap, type, pos, value, 1);
+}
+
+struct isl_basic_set *isl_basic_set_lower_bound_dim(struct isl_basic_set *bset,
+	unsigned dim, isl_int value)
+{
+	int j;
+
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_extend_constraints(bset, 0, 1);
+	j = isl_basic_set_alloc_inequality(bset);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bset->ineq[j], 1 + isl_basic_set_total_dim(bset));
+	isl_int_set_si(bset->ineq[j][1 + isl_basic_set_n_param(bset) + dim], 1);
+	isl_int_neg(bset->ineq[j][0], value);
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static __isl_give isl_map *map_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = basic_map_bound_si(map->p[i],
+						 type, pos, value, upper);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return map_bound_si(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return map_bound_si(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return (struct isl_set *)
+		isl_map_lower_bound_si((struct isl_map *)set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return isl_map_upper_bound_si(set, type, pos, value);
+}
+
+/* Bound the given variable of "bmap" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_map *basic_map_bound(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+	int j;
+
+	if (!bmap)
+		return NULL;
+	if (pos >= isl_basic_map_dim(bmap, type))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	j = isl_basic_map_alloc_inequality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+	if (upper) {
+		isl_int_set_si(bmap->ineq[j][pos], -1);
+		isl_int_set(bmap->ineq[j][0], value);
+	} else {
+		isl_int_set_si(bmap->ineq[j][pos], 1);
+		isl_int_neg(bmap->ineq[j][0], value);
+	}
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Bound the given variable of "map" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_map *map_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	if (pos >= isl_map_dim(map, type))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper);
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return map_bound(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return map_bound(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return isl_map_lower_bound(set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return isl_map_upper_bound(set, type, pos, value);
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no smaller than "value".
+ */
+__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+	if (!value)
+		goto error;
+	if (!isl_val_is_int(value))
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"expecting integer value", goto error);
+	set = isl_set_lower_bound(set, type, pos, value->n);
+	isl_val_free(value);
+	return set;
+error:
+	isl_val_free(value);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no greater than "value".
+ */
+__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+	if (!value)
+		goto error;
+	if (!isl_val_is_int(value))
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"expecting integer value", goto error);
+	set = isl_set_upper_bound(set, type, pos, value->n);
+	isl_val_free(value);
+	return set;
+error:
+	isl_val_free(value);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_set *isl_set_lower_bound_dim(struct isl_set *set, unsigned dim,
+					isl_int value)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	isl_assert(set->ctx, dim < isl_set_n_dim(set), goto error);
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_lower_bound_dim(set->p[i], dim, value);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_map *isl_map_reverse(struct isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_reverse(map->dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reverse(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static struct isl_map *isl_basic_map_partial_lexopt(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty, int max)
+{
+	return isl_tab_basic_map_partial_lexopt(bmap, dom, empty, max);
+}
+
+struct isl_map *isl_basic_map_partial_lexmax(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt(bmap, dom, empty, 1);
+}
+
+struct isl_map *isl_basic_map_partial_lexmin(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt(bmap, dom, empty, 0);
+}
+
+struct isl_set *isl_basic_set_partial_lexmin(
+		struct isl_basic_set *bset, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_basic_map_partial_lexmin((struct isl_basic_map *)bset,
+			dom, empty);
+}
+
+struct isl_set *isl_basic_set_partial_lexmax(
+		struct isl_basic_set *bset, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_basic_map_partial_lexmax((struct isl_basic_map *)bset,
+			dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 0);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 1);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return isl_basic_map_partial_lexmin_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return isl_basic_map_partial_lexmax_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexopt_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, int max)
+{
+	isl_basic_set *dom = NULL;
+	isl_space *dom_space;
+
+	if (!bmap)
+		goto error;
+	dom_space = isl_space_domain(isl_space_copy(bmap->dim));
+	dom = isl_basic_set_universe(dom_space);
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, NULL, max);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff(
+	__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt_pw_multi_aff(bmap, 0);
+}
+
+#undef TYPE
+#define TYPE	isl_pw_multi_aff
+#undef SUFFIX
+#define SUFFIX	_pw_multi_aff
+#undef EMPTY
+#define EMPTY	isl_pw_multi_aff_empty
+#undef ADD
+#define ADD	isl_pw_multi_aff_union_add
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom,
+ * in the form of an isl_pw_multi_aff.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first compute the lexicographically minimal or maximal element
+ * in the first basic map.  This results in a partial solution "res"
+ * and a subset "todo" of dom that still need to be handled.
+ * We then consider each of the remaining maps in "map" and successively
+ * update both "res" and "todo".
+ */
+static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	int i;
+	isl_pw_multi_aff *res;
+	isl_set *todo;
+
+	if (!map || !dom)
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		return isl_pw_multi_aff_from_map(map);
+	}
+
+	res = basic_map_partial_lexopt_pw_multi_aff(
+					    isl_basic_map_copy(map->p[0]),
+					    isl_set_copy(dom), &todo, max);
+
+	for (i = 1; i < map->n; ++i) {
+		isl_pw_multi_aff *res_i;
+		isl_set *todo_i;
+
+		res_i = basic_map_partial_lexopt_pw_multi_aff(
+					    isl_basic_map_copy(map->p[i]),
+					    isl_set_copy(dom), &todo_i, max);
+
+		if (max)
+			res = isl_pw_multi_aff_union_lexmax(res, res_i);
+		else
+			res = isl_pw_multi_aff_union_lexmin(res, res_i);
+
+		todo = isl_set_intersect(todo, todo_i);
+	}
+
+	isl_set_free(dom);
+	isl_map_free(map);
+
+	if (empty)
+		*empty = todo;
+	else
+		isl_set_free(todo);
+
+	return res;
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+#undef TYPE
+#define TYPE	isl_map
+#undef SUFFIX
+#define SUFFIX
+#undef EMPTY
+#define EMPTY	isl_map_empty
+#undef ADD
+#define ADD	isl_map_union_disjoint
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first compute the lexicographically minimal or maximal element
+ * in the first basic map.  This results in a partial solution "res"
+ * and a subset "todo" of dom that still need to be handled.
+ * We then consider each of the remaining maps in "map" and successively
+ * update both "res" and "todo".
+ *
+ * Let res^k and todo^k be the results after k steps and let i = k + 1.
+ * Assume we are computing the lexicographical maximum.
+ * We first compute the lexicographically maximal element in basic map i.
+ * This results in a partial solution res_i and a subset todo_i.
+ * Then we combine these results with those obtain for the first k basic maps
+ * to obtain a result that is valid for the first k+1 basic maps.
+ * In particular, the set where there is no solution is the set where
+ * there is no solution for the first k basic maps and also no solution
+ * for the ith basic map, i.e.,
+ *
+ *	todo^i = todo^k * todo_i
+ *
+ * On dom(res^k) * dom(res_i), we need to pick the larger of the two
+ * solutions, arbitrarily breaking ties in favor of res^k.
+ * That is, when res^k(a) >= res_i(a), we pick res^k and
+ * when res^k(a) < res_i(a), we pick res_i.  (Here, ">=" and "<" denote
+ * the lexicographic order.)
+ * In practice, we compute
+ *
+ *	res^k * (res_i . "<=")
+ *
+ * and
+ *
+ *	res_i * (res^k . "<")
+ *
+ * Finally, we consider the symmetric difference of dom(res^k) and dom(res_i),
+ * where only one of res^k and res_i provides a solution and we simply pick
+ * that one, i.e.,
+ *
+ *	res^k * todo_i
+ * and
+ *	res_i * todo^k
+ *
+ * Note that we only compute these intersections when dom(res^k) intersects
+ * dom(res_i).  Otherwise, the only effect of these intersections is to
+ * potentially break up res^k and res_i into smaller pieces.
+ * We want to avoid such splintering as much as possible.
+ * In fact, an earlier implementation of this function would look for
+ * better results in the domain of res^k and for extra results in todo^k,
+ * but this would always result in a splintering according to todo^k,
+ * even when the domain of basic map i is disjoint from the domains of
+ * the previous basic maps.
+ */
+static __isl_give isl_map *isl_map_partial_lexopt_aligned(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty, int max)
+{
+	int i;
+	struct isl_map *res;
+	struct isl_set *todo;
+
+	if (!map || !dom)
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		return map;
+	}
+
+	res = basic_map_partial_lexopt(isl_basic_map_copy(map->p[0]),
+					isl_set_copy(dom), &todo, max);
+
+	for (i = 1; i < map->n; ++i) {
+		isl_map *lt, *le;
+		isl_map *res_i;
+		isl_set *todo_i;
+		isl_space *dim = isl_space_range(isl_map_get_space(res));
+
+		res_i = basic_map_partial_lexopt(isl_basic_map_copy(map->p[i]),
+					isl_set_copy(dom), &todo_i, max);
+
+		if (max) {
+			lt = isl_map_lex_lt(isl_space_copy(dim));
+			le = isl_map_lex_le(dim);
+		} else {
+			lt = isl_map_lex_gt(isl_space_copy(dim));
+			le = isl_map_lex_ge(dim);
+		}
+		lt = isl_map_apply_range(isl_map_copy(res), lt);
+		lt = isl_map_intersect(lt, isl_map_copy(res_i));
+		le = isl_map_apply_range(isl_map_copy(res_i), le);
+		le = isl_map_intersect(le, isl_map_copy(res));
+
+		if (!isl_map_is_empty(lt) || !isl_map_is_empty(le)) {
+			res = isl_map_intersect_domain(res,
+							isl_set_copy(todo_i));
+			res_i = isl_map_intersect_domain(res_i,
+							isl_set_copy(todo));
+		}
+
+		res = isl_map_union_disjoint(res, res_i);
+		res = isl_map_union_disjoint(res, lt);
+		res = isl_map_union_disjoint(res, le);
+
+		todo = isl_set_intersect(todo, todo_i);
+	}
+
+	isl_set_free(dom);
+	isl_map_free(map);
+
+	if (empty)
+		*empty = todo;
+	else
+		isl_set_free(todo);
+
+	return res;
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_partial_lexmax(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return isl_map_partial_lexopt(map, dom, empty, 1);
+}
+
+__isl_give isl_map *isl_map_partial_lexmin(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return isl_map_partial_lexopt(map, dom, empty, 0);
+}
+
+__isl_give isl_set *isl_set_partial_lexmin(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_map_partial_lexmin((struct isl_map *)set,
+			dom, empty);
+}
+
+__isl_give isl_set *isl_set_partial_lexmax(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_map_partial_lexmax((struct isl_map *)set,
+			dom, empty);
+}
+
+/* Compute the lexicographic minimum (or maximum if "max" is set)
+ * of "bmap" over its domain.
+ *
+ * Since we are not interested in the part of the domain space where
+ * there is no solution, we initialize the domain to those constraints
+ * of "bmap" that only involve the parameters and the input dimensions.
+ * This relieves the parametric programming engine from detecting those
+ * inequalities and transferring them to the context.  More importantly,
+ * it ensures that those inequalities are transferred first and not
+ * intermixed with inequalities that actually split the domain.
+ */
+__isl_give isl_map *isl_basic_map_lexopt(__isl_take isl_basic_map *bmap, int max)
+{
+	int n_div;
+	int n_out;
+	isl_basic_map *copy;
+	isl_basic_set *dom;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	copy = isl_basic_map_copy(bmap);
+	copy = isl_basic_map_drop_constraints_involving_dims(copy,
+							isl_dim_div, 0, n_div);
+	copy = isl_basic_map_drop_constraints_involving_dims(copy,
+							isl_dim_out, 0, n_out);
+	dom = isl_basic_map_domain(copy);
+	return isl_basic_map_partial_lexopt(bmap, dom, NULL, max);
+}
+
+__isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt(bmap, 0);
+}
+
+__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt(bmap, 1);
+}
+
+__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset)
+{
+	return (isl_set *)isl_basic_map_lexmin((isl_basic_map *)bset);
+}
+
+__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
+{
+	return (isl_set *)isl_basic_map_lexmax((isl_basic_map *)bset);
+}
+
+/* Extract the first and only affine expression from list
+ * and then add it to *pwaff with the given dom.
+ * This domain is known to be disjoint from other domains
+ * because of the way isl_basic_map_foreach_lexmax works.
+ */
+static int update_dim_opt(__isl_take isl_basic_set *dom,
+	__isl_take isl_aff_list *list, void *user)
+{
+	isl_ctx *ctx = isl_basic_set_get_ctx(dom);
+	isl_aff *aff;
+	isl_pw_aff **pwaff = user;
+	isl_pw_aff *pwaff_i;
+
+	if (!list)
+		goto error;
+	if (isl_aff_list_n_aff(list) != 1)
+		isl_die(ctx, isl_error_internal,
+			"expecting single element list", goto error);
+
+	aff = isl_aff_list_get_aff(list, 0);
+	pwaff_i = isl_pw_aff_alloc(isl_set_from_basic_set(dom), aff);
+
+	*pwaff = isl_pw_aff_add_disjoint(*pwaff, pwaff_i);
+
+	isl_aff_list_free(list);
+
+	return 0;
+error:
+	isl_basic_set_free(dom);
+	isl_aff_list_free(list);
+	return -1;
+}
+
+/* Given a basic map with one output dimension, compute the minimum or
+ * maximum of that dimension as an isl_pw_aff.
+ *
+ * The isl_pw_aff is constructed by having isl_basic_map_foreach_lexopt
+ * call update_dim_opt on each leaf of the result.
+ */
+static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap,
+	int max)
+{
+	isl_space *dim = isl_basic_map_get_space(bmap);
+	isl_pw_aff *pwaff;
+	int r;
+
+	dim = isl_space_from_domain(isl_space_domain(dim));
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	pwaff = isl_pw_aff_empty(dim);
+
+	r = isl_basic_map_foreach_lexopt(bmap, max, &update_dim_opt, &pwaff);
+	if (r < 0)
+		return isl_pw_aff_free(pwaff);
+
+	return pwaff;
+}
+
+/* Compute the minimum or maximum of the given output dimension
+ * as a function of the parameters and the input dimensions,
+ * but independently of the other output dimensions.
+ *
+ * We first project out the other output dimension and then compute
+ * the "lexicographic" maximum in each basic map, combining the results
+ * using isl_pw_aff_union_max.
+ */
+static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos,
+	int max)
+{
+	int i;
+	isl_pw_aff *pwaff;
+	unsigned n_out;
+
+	n_out = isl_map_dim(map, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1));
+	map = isl_map_project_out(map, isl_dim_out, 0, pos);
+	if (!map)
+		return NULL;
+
+	if (map->n == 0) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_pw_aff_empty(dim);
+	}
+
+	pwaff = basic_map_dim_opt(map->p[0], max);
+	for (i = 1; i < map->n; ++i) {
+		isl_pw_aff *pwaff_i;
+
+		pwaff_i = basic_map_dim_opt(map->p[i], max);
+		pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max);
+	}
+
+	isl_map_free(map);
+
+	return pwaff;
+}
+
+/* Compute the maximum of the given output dimension as a function of the
+ * parameters and input dimensions, but independently of
+ * the other output dimensions.
+ */
+__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos)
+{
+	return map_dim_opt(map, pos, 1);
+}
+
+/* Compute the minimum or maximum of the given set dimension
+ * as a function of the parameters,
+ * but independently of the other set dimensions.
+ */
+static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos,
+	int max)
+{
+	return map_dim_opt(set, pos, max);
+}
+
+/* Compute the maximum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos)
+{
+	return set_dim_opt(set, pos, 1);
+}
+
+/* Compute the minimum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos)
+{
+	return set_dim_opt(set, pos, 0);
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "bset".
+ * bset is assumed to have only parameters and divs.
+ */
+static struct isl_basic_set *basic_set_parameter_preimage(
+	struct isl_basic_set *bset, struct isl_mat *mat)
+{
+	unsigned nparam;
+
+	if (!bset || !mat)
+		goto error;
+
+	bset->dim = isl_space_cow(bset->dim);
+	if (!bset->dim)
+		goto error;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	isl_assert(bset->ctx, mat->n_row == 1 + nparam, goto error);
+
+	bset->dim->nparam = 0;
+	bset->dim->n_out = nparam;
+	bset = isl_basic_set_preimage(bset, mat);
+	if (bset) {
+		bset->dim->nparam = bset->dim->n_out;
+		bset->dim->n_out = 0;
+	}
+	return bset;
+error:
+	isl_mat_free(mat);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "set".
+ * set is assumed to have only parameters and divs.
+ */
+static struct isl_set *set_parameter_preimage(
+	struct isl_set *set, struct isl_mat *mat)
+{
+	isl_space *dim = NULL;
+	unsigned nparam;
+
+	if (!set || !mat)
+		goto error;
+
+	dim = isl_space_copy(set->dim);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+
+	isl_assert(set->ctx, mat->n_row == 1 + nparam, goto error);
+
+	dim->nparam = 0;
+	dim->n_out = nparam;
+	isl_set_reset_space(set, dim);
+	set = isl_set_preimage(set, mat);
+	if (!set)
+		goto error2;
+	dim = isl_space_copy(set->dim);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error2;
+	dim->nparam = dim->n_out;
+	dim->n_out = 0;
+	isl_set_reset_space(set, dim);
+	return set;
+error:
+	isl_space_free(dim);
+	isl_mat_free(mat);
+error2:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Intersect the basic set "bset" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_basic_set *basic_set_append_equalities(
+	struct isl_basic_set *bset, struct isl_mat *eq)
+{
+	int i, k;
+	unsigned len;
+
+	if (!bset || !eq)
+		goto error;
+
+	bset = isl_basic_set_extend_space(bset, isl_space_copy(bset->dim), 0,
+					eq->n_row, 0);
+	if (!bset)
+		goto error;
+
+	len = 1 + isl_space_dim(bset->dim, isl_dim_all) + bset->extra;
+	for (i = 0; i < eq->n_row; ++i) {
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k], eq->row[i], eq->n_col);
+		isl_seq_clr(bset->eq[k] + eq->n_col, len - eq->n_col);
+	}
+	isl_mat_free(eq);
+
+	bset = isl_basic_set_gauss(bset, NULL);
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_mat_free(eq);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Intersect the set "set" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_set *set_append_equalities(struct isl_set *set,
+	struct isl_mat *eq)
+{
+	int i;
+
+	if (!set || !eq)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = basic_set_append_equalities(set->p[i],
+					isl_mat_copy(eq));
+		if (!set->p[i])
+			goto error;
+	}
+	isl_mat_free(eq);
+	return set;
+error:
+	isl_mat_free(eq);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given a basic set "bset" that only involves parameters and existentially
+ * quantified variables, return the index of the first equality
+ * that only involves parameters.  If there is no such equality then
+ * return bset->n_eq.
+ *
+ * This function assumes that isl_basic_set_gauss has been called on "bset".
+ */
+static int first_parameter_equality(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned nparam, n_div;
+
+	if (!bset)
+		return -1;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+	for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) {
+		if (!isl_int_is_zero(bset->eq[i][1 + nparam + j]))
+			++i;
+	}
+
+	return i;
+}
+
+/* Compute an explicit representation for the existentially quantified
+ * variables in "bset" by computing the "minimal value" of the set
+ * variables.  Since there are no set variables, the computation of
+ * the minimal value essentially computes an explicit representation
+ * of the non-empty part(s) of "bset".
+ *
+ * The input only involves parameters and existentially quantified variables.
+ * All equalities among parameters have been removed.
+ *
+ * Since the existentially quantified variables in the result are in general
+ * going to be different from those in the input, we first replace
+ * them by the minimal number of variables based on their equalities.
+ * This should simplify the parametric integer programming.
+ */
+static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset)
+{
+	isl_morph *morph1, *morph2;
+	isl_set *set;
+	unsigned n;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_eq == 0)
+		return isl_basic_set_lexmin(bset);
+
+	morph1 = isl_basic_set_parameter_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph1), bset);
+	bset = isl_basic_set_lift(bset);
+	morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+	bset = isl_morph_basic_set(morph2, bset);
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+
+	set = isl_basic_set_lexmin(bset);
+
+	set = isl_morph_set(isl_morph_inverse(morph1), set);
+
+	return set;
+}
+
+/* Project the given basic set onto its parameter domain, possibly introducing
+ * new, explicit, existential variables in the constraints.
+ * The input has parameters and (possibly implicit) existential variables.
+ * The output has the same parameters, but only
+ * explicit existentially quantified variables.
+ *
+ * The actual projection is performed by pip, but pip doesn't seem
+ * to like equalities very much, so we first remove the equalities
+ * among the parameters by performing a variable compression on
+ * the parameters.  Afterward, an inverse transformation is performed
+ * and the equalities among the parameters are inserted back in.
+ *
+ * The variable compression on the parameters may uncover additional
+ * equalities that were only implicit before.  We therefore check
+ * if there are any new parameter equalities in the result and
+ * if so recurse.  The removal of parameter equalities is required
+ * for the parameter compression performed by base_compute_divs.
+ */
+static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
+{
+	int i;
+	struct isl_mat *eq;
+	struct isl_mat *T, *T2;
+	struct isl_set *set;
+	unsigned nparam;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	if (bset->n_eq == 0)
+		return base_compute_divs(bset);
+
+	bset = isl_basic_set_gauss(bset, NULL);
+	if (!bset)
+		return NULL;
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_set_from_basic_set(bset);
+
+	i = first_parameter_equality(bset);
+	if (i == bset->n_eq)
+		return base_compute_divs(bset);
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, i, bset->n_eq - i,
+		0, 1 + nparam);
+	eq = isl_mat_cow(eq);
+	T = isl_mat_variable_compression(isl_mat_copy(eq), &T2);
+	if (T && T->n_col == 0) {
+		isl_mat_free(T);
+		isl_mat_free(T2);
+		isl_mat_free(eq);
+		bset = isl_basic_set_set_to_empty(bset);
+		return isl_set_from_basic_set(bset);
+	}
+	bset = basic_set_parameter_preimage(bset, T);
+
+	i = first_parameter_equality(bset);
+	if (!bset)
+		set = NULL;
+	else if (i == bset->n_eq)
+		set = base_compute_divs(bset);
+	else
+		set = parameter_compute_divs(bset);
+	set = set_parameter_preimage(set, T2);
+	set = set_append_equalities(set, eq);
+	return set;
+}
+
+/* Insert the divs from "ls" before those of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the divs from "ls".
+ * The caller is responsible for removing the same number of dimensions
+ * from the space of "bmap".
+ */
+static __isl_give isl_basic_map *insert_divs_from_local_space(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls)
+{
+	int i;
+	int n_div;
+	int old_n_div;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	if (n_div == 0)
+		return bmap;
+
+	old_n_div = bmap->n_div;
+	bmap = insert_div_rows(bmap, n_div);
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < n_div; ++i) {
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+		isl_seq_clr(bmap->div[i] + ls->div->n_col, old_n_div);
+	}
+
+	return bmap;
+}
+
+/* Replace the space of "bmap" by the space and divs of "ls".
+ *
+ * If "ls" has any divs, then we simplify the result since we may
+ * have discovered some additional equalities that could simplify
+ * the div expressions.
+ */
+static __isl_give isl_basic_map *basic_replace_space_by_local_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls)
+{
+	int n_div;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !ls)
+		goto error;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	bmap = insert_divs_from_local_space(bmap, ls);
+	if (!bmap)
+		goto error;
+
+	isl_space_free(bmap->dim);
+	bmap->dim = isl_local_space_get_space(ls);
+	if (!bmap->dim)
+		goto error;
+
+	isl_local_space_free(ls);
+	if (n_div > 0)
+		bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Replace the space of "map" by the space and divs of "ls".
+ */
+static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map,
+	__isl_take isl_local_space *ls)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !ls)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = basic_replace_space_by_local_space(map->p[i],
+						    isl_local_space_copy(ls));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = isl_local_space_get_space(ls);
+	if (!map->dim)
+		goto error;
+
+	isl_local_space_free(ls);
+	return map;
+error:
+	isl_local_space_free(ls);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute an explicit representation for the existentially
+ * quantified variables for which do not know any explicit representation yet.
+ *
+ * We first sort the existentially quantified variables so that the
+ * existentially quantified variables for which we already have an explicit
+ * representation are placed before those for which we do not.
+ * The input dimensions, the output dimensions and the existentially
+ * quantified variables for which we already have an explicit
+ * representation are then turned into parameters.
+ * compute_divs returns a map with the same parameters and
+ * no input or output dimensions and the dimension specification
+ * is reset to that of the input, including the existentially quantified
+ * variables for which we already had an explicit representation.
+ */
+static struct isl_map *compute_divs(struct isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset;
+	struct isl_set *set;
+	struct isl_map *map;
+	isl_space *dim;
+	isl_local_space *ls;
+	unsigned	 nparam;
+	unsigned	 n_in;
+	unsigned	 n_out;
+	unsigned n_known;
+	int i;
+
+	bmap = isl_basic_map_sort_divs(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	for (n_known = 0; n_known < bmap->n_div; ++n_known)
+		if (isl_int_is_zero(bmap->div[n_known][0]))
+			break;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	dim = isl_space_set_alloc(bmap->ctx,
+				    nparam + n_in + n_out + n_known, 0);
+	if (!dim)
+		goto error;
+
+	ls = isl_basic_map_get_local_space(bmap);
+	ls = isl_local_space_drop_dims(ls, isl_dim_div,
+					n_known, bmap->n_div - n_known);
+	if (n_known > 0) {
+		for (i = n_known; i < bmap->n_div; ++i)
+			swap_div(bmap, i - n_known, i);
+		bmap->n_div -= n_known;
+		bmap->extra -= n_known;
+	}
+	bmap = isl_basic_map_reset_space(bmap, dim);
+	bset = (struct isl_basic_set *)bmap;
+
+	set = parameter_compute_divs(bset);
+	map = (struct isl_map *)set;
+	map = replace_space_by_local_space(map, ls);
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned off;
+
+	if (!bmap)
+		return -1;
+
+	off = isl_space_dim(bmap->dim, isl_dim_all);
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			return 0;
+		isl_assert(bmap->ctx, isl_int_is_zero(bmap->div[i][1+1+off+i]),
+				return -1);
+	}
+	return 1;
+}
+
+static int map_divs_known(__isl_keep isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int known = isl_basic_map_divs_known(map->p[i]);
+		if (known <= 0)
+			return known;
+	}
+
+	return 1;
+}
+
+/* If bmap contains any unknown divs, then compute explicit
+ * expressions for them.  However, this computation may be
+ * quite expensive, so first try to remove divs that aren't
+ * strictly needed.
+ */
+struct isl_map *isl_basic_map_compute_divs(struct isl_basic_map *bmap)
+{
+	int known;
+	struct isl_map *map;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		goto error;
+	if (known)
+		return isl_map_from_basic_map(bmap);
+
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		goto error;
+	if (known)
+		return isl_map_from_basic_map(bmap);
+
+	map = compute_divs(bmap);
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_map *isl_map_compute_divs(struct isl_map *map)
+{
+	int i;
+	int known;
+	struct isl_map *res;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	known = map_divs_known(map);
+	if (known < 0) {
+		isl_map_free(map);
+		return NULL;
+	}
+	if (known)
+		return map;
+
+	res = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[0]));
+	for (i = 1 ; i < map->n; ++i) {
+		struct isl_map *r2;
+		r2 = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[i]));
+		if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
+			res = isl_map_union_disjoint(res, r2);
+		else
+			res = isl_map_union(res, r2);
+	}
+	isl_map_free(map);
+
+	return res;
+}
+
+struct isl_set *isl_basic_set_compute_divs(struct isl_basic_set *bset)
+{
+	return (struct isl_set *)
+		isl_basic_map_compute_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_compute_divs(struct isl_set *set)
+{
+	return (struct isl_set *)
+		isl_map_compute_divs((struct isl_map *)set);
+}
+
+struct isl_set *isl_map_domain(struct isl_map *map)
+{
+	int i;
+	struct isl_set *set;
+
+	if (!map)
+		goto error;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	set = (struct isl_set *)map;
+	set->dim = isl_space_domain(set->dim);
+	if (!set->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		set->p[i] = isl_basic_map_domain(map->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	ISL_F_CLR(set, ISL_MAP_DISJOINT);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where we assume for now that
+ * "map1" and "map2" are disjoint.  Note that the basic maps inside
+ * "map1" or "map2" may not be disjoint from each other.
+ * Also note that this function is also called from isl_map_union,
+ * which takes care of handling the situation where "map1" and "map2"
+ * may not be disjoint.
+ *
+ * If one of the inputs is empty, we can simply return the other input.
+ * Similarly, if one of the inputs is universal, then it is equal to the union.
+ */
+static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int i;
+	unsigned flags = 0;
+	struct isl_map *map = NULL;
+	int is_universe;
+
+	if (!map1 || !map2)
+		goto error;
+
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	if (map1->n == 0) {
+		isl_map_free(map1);
+		return map2;
+	}
+	if (map2->n == 0) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	is_universe = isl_map_plain_is_universe(map1);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	is_universe = isl_map_plain_is_universe(map2);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(map1);
+		return map2;
+	}
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	map = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n + map2->n, flags);
+	if (!map)
+		goto error;
+	for (i = 0; i < map1->n; ++i) {
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_copy(map1->p[i]));
+		if (!map)
+			goto error;
+	}
+	for (i = 0; i < map2->n; ++i) {
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_copy(map2->p[i]));
+		if (!map)
+			goto error;
+	}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return map;
+error:
+	isl_map_free(map);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" are
+ * guaranteed to be disjoint by the caller.
+ *
+ * Note that this functions is called from within isl_map_make_disjoint,
+ * so we have to be careful not to touch the constraints of the inputs
+ * in any way.
+ */
+__isl_give isl_map *isl_map_union_disjoint(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_union_disjoint);
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint.  The parameters are assumed to have been aligned.
+ *
+ * We currently simply call map_union_disjoint, the internal operation
+ * of which does not really depend on the inputs being disjoint.
+ * If the result contains more than one basic map, then we clear
+ * the disjoint flag since the result may contain basic maps from
+ * both inputs and these are not guaranteed to be disjoint.
+ *
+ * As a special case, if "map1" and "map2" are obviously equal,
+ * then we simply return "map1".
+ */
+static __isl_give isl_map *map_union_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int equal;
+
+	if (!map1 || !map2)
+		goto error;
+
+	equal = isl_map_plain_is_equal(map1, map2);
+	if (equal < 0)
+		goto error;
+	if (equal) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	map1 = map_union_disjoint(map1, map2);
+	if (!map1)
+		return NULL;
+	if (map1->n > 1)
+		ISL_F_CLR(map1, ISL_MAP_DISJOINT);
+	return map1;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint.
+ */
+__isl_give isl_map *isl_map_union(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_union_aligned);
+}
+
+struct isl_set *isl_set_union_disjoint(
+			struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_union_disjoint(
+			(struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+struct isl_set *isl_set_union(struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_union((struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+/* Apply "fn" to pairs of elements from "map" and "set" and collect
+ * the results.
+ *
+ * "map" and "set" are assumed to be compatible and non-NULL.
+ */
+static __isl_give isl_map *map_intersect_set(__isl_take isl_map *map,
+	__isl_take isl_set *set,
+	__isl_give isl_basic_map *fn(__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset))
+{
+	unsigned flags = 0;
+	struct isl_map *result;
+	int i, j;
+
+	if (isl_set_plain_is_universe(set)) {
+		isl_set_free(set);
+		return map;
+	}
+
+	if (ISL_F_ISSET(map, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(set, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(isl_space_copy(map->dim),
+					map->n * set->n, flags);
+	for (i = 0; result && i < map->n; ++i)
+		for (j = 0; j < set->n; ++j) {
+			result = isl_map_add_basic_map(result,
+					fn(isl_basic_map_copy(map->p[i]),
+					    isl_basic_set_copy(set->p[j])));
+			if (!result)
+				break;
+		}
+
+	isl_map_free(map);
+	isl_set_free(set);
+	return result;
+}
+
+static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	if (!map || !set)
+		goto error;
+
+	if (!isl_map_compatible_range(map, set))
+		isl_die(set->ctx, isl_error_invalid,
+			"incompatible spaces", goto error);
+
+	return map_intersect_set(map, set, &isl_basic_map_intersect_range);
+error:
+	isl_map_free(map);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_range(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	return isl_map_align_params_map_map_and(map, set, &map_intersect_range);
+}
+
+static __isl_give isl_map *map_intersect_domain(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	if (!map || !set)
+		goto error;
+
+	if (!isl_map_compatible_domain(map, set))
+		isl_die(set->ctx, isl_error_invalid,
+			"incompatible spaces", goto error);
+
+	return map_intersect_set(map, set, &isl_basic_map_intersect_domain);
+error:
+	isl_map_free(map);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_domain(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	return isl_map_align_params_map_map_and(map, set,
+						&map_intersect_domain);
+}
+
+static __isl_give isl_map *map_apply_domain(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	if (!map1 || !map2)
+		goto error;
+	map1 = isl_map_reverse(map1);
+	map1 = isl_map_apply_range(map1, map2);
+	return isl_map_reverse(map1);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_apply_domain);
+}
+
+static __isl_give isl_map *map_apply_range(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_space *dim_result;
+	struct isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	dim_result = isl_space_join(isl_space_copy(map1->dim),
+				  isl_space_copy(map2->dim));
+
+	result = isl_map_alloc_space(dim_result, map1->n * map2->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			result = isl_map_add_basic_map(result,
+			    isl_basic_map_apply_range(
+				isl_basic_map_copy(map1->p[i]),
+				isl_basic_map_copy(map2->p[j])));
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	if (result && result->n <= 1)
+		ISL_F_SET(result, ISL_MAP_DISJOINT);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_apply_range);
+}
+
+/*
+ * returns range - domain
+ */
+struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
+{
+	isl_space *dims, *target_dim;
+	struct isl_basic_set *bset;
+	unsigned dim;
+	unsigned nparam;
+	int i;
+
+	if (!bmap)
+		goto error;
+	isl_assert(bmap->ctx, isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+						  bmap->dim, isl_dim_out),
+		   goto error);
+	target_dim = isl_space_domain(isl_basic_map_get_space(bmap));
+	dim = isl_basic_map_n_in(bmap);
+	nparam = isl_basic_map_n_param(bmap);
+	bset = isl_basic_set_from_basic_map(bmap);
+	bset = isl_basic_set_cow(bset);
+	dims = isl_basic_set_get_space(bset);
+	dims = isl_space_add_dims(dims, isl_dim_set, dim);
+	bset = isl_basic_set_extend_space(bset, dims, 0, dim, 0);
+	bset = isl_basic_set_swap_vars(bset, 2*dim);
+	for (i = 0; i < dim; ++i) {
+		int j = isl_basic_map_alloc_equality(
+					    (struct isl_basic_map *)bset);
+		if (j < 0) {
+			bset = isl_basic_set_free(bset);
+			break;
+		}
+		isl_seq_clr(bset->eq[j], 1 + isl_basic_set_total_dim(bset));
+		isl_int_set_si(bset->eq[j][1+nparam+i], 1);
+		isl_int_set_si(bset->eq[j][1+nparam+dim+i], 1);
+		isl_int_set_si(bset->eq[j][1+nparam+2*dim+i], -1);
+	}
+	bset = isl_basic_set_project_out(bset, isl_dim_set, dim, 2*dim);
+	bset = isl_basic_set_reset_space(bset, target_dim);
+	return bset;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/*
+ * returns range - domain
+ */
+__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *dim;
+	struct isl_set *result;
+
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, isl_space_tuple_is_equal(map->dim, isl_dim_in,
+						 map->dim, isl_dim_out),
+		   goto error);
+	dim = isl_map_get_space(map);
+	dim = isl_space_domain(dim);
+	result = isl_set_alloc_space(dim, map->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map->n; ++i)
+		result = isl_set_add_basic_set(result,
+			  isl_basic_map_deltas(isl_basic_map_copy(map->p[i])));
+	isl_map_free(map);
+	return result;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_basic_map *isl_basic_map_deltas_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *domain;
+	int nparam, n;
+	unsigned total;
+
+	if (!isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+					bmap->dim, isl_dim_out))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"domain and range don't match", goto error);
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n = isl_basic_map_dim(bmap, isl_dim_in);
+
+	dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+	domain = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, domain);
+	bmap = isl_basic_map_extend_constraints(bmap, n, 0);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[k], 1 + total);
+		isl_int_set_si(bmap->eq[k][1 + nparam + i], 1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n + i], -1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n + n + i], 1);
+	}
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *domain_dim;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out))
+		isl_die(map->ctx, isl_error_invalid,
+			"domain and range don't match", goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map)));
+	map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+	map->dim = isl_space_join(map->dim, domain_dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_deltas_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_identity(__isl_take isl_space *dims)
+{
+	struct isl_basic_map *bmap;
+	unsigned nparam;
+	unsigned dim;
+	int i;
+
+	if (!dims)
+		return NULL;
+
+	nparam = dims->nparam;
+	dim = dims->n_out;
+	bmap = isl_basic_map_alloc_space(dims, 0, dim, 0);
+	if (!bmap)
+		goto error;
+
+	for (i = 0; i < dim; ++i) {
+		int j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap));
+		isl_int_set_si(bmap->eq[j][1+nparam+i], 1);
+		isl_int_set_si(bmap->eq[j][1+nparam+dim+i], -1);
+	}
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (dim->n_in != dim->n_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"number of input and output dimensions needs to be "
+			"the same", goto error);
+	return basic_map_identity(dim);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_identity_like(struct isl_basic_map *model)
+{
+	if (!model || !model->dim)
+		return NULL;
+	return isl_basic_map_identity(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim)
+{
+	return isl_map_from_basic_map(isl_basic_map_identity(dim));
+}
+
+struct isl_map *isl_map_identity_like(struct isl_map *model)
+{
+	if (!model || !model->dim)
+		return NULL;
+	return isl_map_identity(isl_space_copy(model->dim));
+}
+
+struct isl_map *isl_map_identity_like_basic_map(struct isl_basic_map *model)
+{
+	if (!model || !model->dim)
+		return NULL;
+	return isl_map_identity(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_set_identity(__isl_take isl_set *set)
+{
+	isl_space *dim = isl_set_get_space(set);
+	isl_map *id;
+	id = isl_map_identity(isl_space_map_from_set(dim));
+	return isl_map_intersect_range(id, set);
+}
+
+/* Construct a basic set with all set dimensions having only non-negative
+ * values.
+ */
+__isl_give isl_basic_set *isl_basic_set_positive_orthant(
+	__isl_take isl_space *space)
+{
+	int i;
+	unsigned nparam;
+	unsigned dim;
+	struct isl_basic_set *bset;
+
+	if (!space)
+		return NULL;
+	nparam = space->nparam;
+	dim = space->n_out;
+	bset = isl_basic_set_alloc_space(space, 0, 0, dim);
+	if (!bset)
+		return NULL;
+	for (i = 0; i < dim; ++i) {
+		int k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset));
+		isl_int_set_si(bset->ineq[k][1 + nparam + i], 1);
+	}
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct the half-space x_pos >= 0.
+ */
+static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *dim,
+	int pos)
+{
+	int k;
+	isl_basic_set *nonneg;
+
+	nonneg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+	k = isl_basic_set_alloc_inequality(nonneg);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(nonneg->ineq[k], 1 + isl_basic_set_total_dim(nonneg));
+	isl_int_set_si(nonneg->ineq[k][pos], 1);
+
+	return isl_basic_set_finalize(nonneg);
+error:
+	isl_basic_set_free(nonneg);
+	return NULL;
+}
+
+/* Construct the half-space x_pos <= -1.
+ */
+static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *dim, int pos)
+{
+	int k;
+	isl_basic_set *neg;
+
+	neg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+	k = isl_basic_set_alloc_inequality(neg);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(neg->ineq[k], 1 + isl_basic_set_total_dim(neg));
+	isl_int_set_si(neg->ineq[k][0], -1);
+	isl_int_set_si(neg->ineq[k][pos], -1);
+
+	return isl_basic_set_finalize(neg);
+error:
+	isl_basic_set_free(neg);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	isl_basic_set *nonneg;
+	isl_basic_set *neg;
+
+	if (!set)
+		return NULL;
+	if (n == 0)
+		return set;
+
+	isl_assert(set->ctx, first + n <= isl_set_dim(set, type), goto error);
+
+	for (i = 0; i < n; ++i) {
+		nonneg = nonneg_halfspace(isl_set_get_space(set),
+					  pos(set->dim, type) + first + i);
+		neg = neg_halfspace(isl_set_get_space(set),
+					  pos(set->dim, type) + first + i);
+
+		set = isl_set_intersect(set, isl_basic_set_union(nonneg, neg));
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+static int foreach_orthant(__isl_take isl_set *set, int *signs, int first,
+	int len, int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	isl_set *half;
+
+	if (!set)
+		return -1;
+	if (isl_set_plain_is_empty(set)) {
+		isl_set_free(set);
+		return 0;
+	}
+	if (first == len)
+		return fn(set, signs, user);
+
+	signs[first] = 1;
+	half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_space(set),
+							1 + first));
+	half = isl_set_intersect(half, isl_set_copy(set));
+	if (foreach_orthant(half, signs, first + 1, len, fn, user) < 0)
+		goto error;
+
+	signs[first] = -1;
+	half = isl_set_from_basic_set(neg_halfspace(isl_set_get_space(set),
+							1 + first));
+	half = isl_set_intersect(half, set);
+	return foreach_orthant(half, signs, first + 1, len, fn, user);
+error:
+	isl_set_free(set);
+	return -1;
+}
+
+/* Call "fn" on the intersections of "set" with each of the orthants
+ * (except for obviously empty intersections).  The orthant is identified
+ * by the signs array, with each entry having value 1 or -1 according
+ * to the sign of the corresponding variable.
+ */
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	unsigned nparam;
+	unsigned nvar;
+	int *signs;
+	int r;
+
+	if (!set)
+		return -1;
+	if (isl_set_plain_is_empty(set))
+		return 0;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+	nvar = isl_set_dim(set, isl_dim_set);
+
+	signs = isl_alloc_array(set->ctx, int, nparam + nvar);
+
+	r = foreach_orthant(isl_set_copy(set), signs, 0, nparam + nvar,
+			    fn, user);
+
+	free(signs);
+
+	return r;
+}
+
+int isl_set_is_equal(struct isl_set *set1, struct isl_set *set2)
+{
+	return isl_map_is_equal((struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+int isl_basic_map_is_subset(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	int is_subset;
+	struct isl_map *map1;
+	struct isl_map *map2;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+
+	map1 = isl_map_from_basic_map(isl_basic_map_copy(bmap1));
+	map2 = isl_map_from_basic_map(isl_basic_map_copy(bmap2));
+
+	is_subset = isl_map_is_subset(map1, map2);
+
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return is_subset;
+}
+
+int isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_is_subset(bset1, bset2);
+}
+
+int isl_basic_map_is_equal(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	int is_subset;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+	is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+	if (is_subset != 1)
+		return is_subset;
+	is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+	return is_subset;
+}
+
+int isl_basic_set_is_equal(
+		struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	return isl_basic_map_is_equal(
+		(struct isl_basic_map *)bset1, (struct isl_basic_map *)bset2);
+}
+
+int isl_map_is_empty(struct isl_map *map)
+{
+	int i;
+	int is_empty;
+
+	if (!map)
+		return -1;
+	for (i = 0; i < map->n; ++i) {
+		is_empty = isl_basic_map_is_empty(map->p[i]);
+		if (is_empty < 0)
+			return -1;
+		if (!is_empty)
+			return 0;
+	}
+	return 1;
+}
+
+int isl_map_plain_is_empty(__isl_keep isl_map *map)
+{
+	return map ? map->n == 0 : -1;
+}
+
+int isl_map_fast_is_empty(__isl_keep isl_map *map)
+{
+	return isl_map_plain_is_empty(map);
+}
+
+int isl_set_plain_is_empty(struct isl_set *set)
+{
+	return set ? set->n == 0 : -1;
+}
+
+int isl_set_fast_is_empty(__isl_keep isl_set *set)
+{
+	return isl_set_plain_is_empty(set);
+}
+
+int isl_set_is_empty(struct isl_set *set)
+{
+	return isl_map_is_empty((struct isl_map *)set);
+}
+
+int isl_map_has_equal_space(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	if (!map1 || !map2)
+		return -1;
+
+	return isl_space_is_equal(map1->dim, map2->dim);
+}
+
+int isl_set_has_equal_space(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	if (!set1 || !set2)
+		return -1;
+
+	return isl_space_is_equal(set1->dim, set2->dim);
+}
+
+static int map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	int is_subset;
+
+	if (!map1 || !map2)
+		return -1;
+	is_subset = isl_map_is_subset(map1, map2);
+	if (is_subset != 1)
+		return is_subset;
+	is_subset = isl_map_is_subset(map2, map1);
+	return is_subset;
+}
+
+int isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal);
+}
+
+int isl_basic_map_is_strict_subset(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	int is_subset;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+	is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+	if (is_subset != 1)
+		return is_subset;
+	is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+	if (is_subset == -1)
+		return is_subset;
+	return !is_subset;
+}
+
+int isl_map_is_strict_subset(struct isl_map *map1, struct isl_map *map2)
+{
+	int is_subset;
+
+	if (!map1 || !map2)
+		return -1;
+	is_subset = isl_map_is_subset(map1, map2);
+	if (is_subset != 1)
+		return is_subset;
+	is_subset = isl_map_is_subset(map2, map1);
+	if (is_subset == -1)
+		return is_subset;
+	return !is_subset;
+}
+
+int isl_set_is_strict_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_is_strict_subset((isl_map *)set1, (isl_map *)set2);
+}
+
+int isl_basic_map_is_universe(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return bmap->n_eq == 0 && bmap->n_ineq == 0;
+}
+
+int isl_basic_set_is_universe(struct isl_basic_set *bset)
+{
+	if (!bset)
+		return -1;
+	return bset->n_eq == 0 && bset->n_ineq == 0;
+}
+
+int isl_map_plain_is_universe(__isl_keep isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int r = isl_basic_map_is_universe(map->p[i]);
+		if (r < 0 || r)
+			return r;
+	}
+
+	return 0;
+}
+
+int isl_set_plain_is_universe(__isl_keep isl_set *set)
+{
+	return isl_map_plain_is_universe((isl_map *) set);
+}
+
+int isl_set_fast_is_universe(__isl_keep isl_set *set)
+{
+	return isl_set_plain_is_universe(set);
+}
+
+int isl_basic_map_is_empty(struct isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset = NULL;
+	struct isl_vec *sample = NULL;
+	int empty;
+	unsigned total;
+
+	if (!bmap)
+		return -1;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return 1;
+
+	if (isl_basic_map_is_universe(bmap))
+		return 0;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+		struct isl_basic_map *copy = isl_basic_map_copy(bmap);
+		copy = isl_basic_map_remove_redundancies(copy);
+		empty = isl_basic_map_plain_is_empty(copy);
+		isl_basic_map_free(copy);
+		return empty;
+	}
+
+	total = 1 + isl_basic_map_total_dim(bmap);
+	if (bmap->sample && bmap->sample->size == total) {
+		int contains = isl_basic_map_contains(bmap, bmap->sample);
+		if (contains < 0)
+			return -1;
+		if (contains)
+			return 0;
+	}
+	isl_vec_free(bmap->sample);
+	bmap->sample = NULL;
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	if (!bset)
+		return -1;
+	sample = isl_basic_set_sample_vec(bset);
+	if (!sample)
+		return -1;
+	empty = sample->size == 0;
+	isl_vec_free(bmap->sample);
+	bmap->sample = sample;
+	if (empty)
+		ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+
+	return empty;
+}
+
+int isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY);
+}
+
+int isl_basic_map_fast_is_empty(__isl_keep isl_basic_map *bmap)
+{
+	return isl_basic_map_plain_is_empty(bmap);
+}
+
+int isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return -1;
+	return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY);
+}
+
+int isl_basic_set_fast_is_empty(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_plain_is_empty(bset);
+}
+
+int isl_basic_set_is_empty(struct isl_basic_set *bset)
+{
+	return isl_basic_map_is_empty((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_basic_map_union(
+	struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	struct isl_map *map;
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+	map = isl_map_alloc_space(isl_space_copy(bmap1->dim), 2, 0);
+	if (!map)
+		goto error;
+	map = isl_map_add_basic_map(map, bmap1);
+	map = isl_map_add_basic_map(map, bmap2);
+	return map;
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_set *isl_basic_set_union(
+		struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	return (struct isl_set *)isl_basic_map_union(
+					    (struct isl_basic_map *)bset1,
+					    (struct isl_basic_map *)bset2);
+}
+
+/* Order divs such that any div only depends on previous divs */
+struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap)
+{
+	int i;
+	unsigned off;
+
+	if (!bmap)
+		return NULL;
+
+	off = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		int pos;
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		pos = isl_seq_first_non_zero(bmap->div[i]+1+1+off+i,
+							    bmap->n_div-i);
+		if (pos == -1)
+			continue;
+		isl_basic_map_swap_div(bmap, i, i + pos);
+		--i;
+	}
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_order_divs((struct isl_basic_map *)bset);
+}
+
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return 0;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_order_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ */
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp)
+{
+	int i, j;
+	int n_div;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !div)
+		goto error;
+
+	if (div->n_row < bset->n_div)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"not an expansion", goto error);
+
+	n_div = bset->n_div;
+	bset = isl_basic_map_extend_space(bset, isl_space_copy(bset->dim),
+					    div->n_row - n_div, 0,
+					    2 * (div->n_row - n_div));
+
+	for (i = n_div; i < div->n_row; ++i)
+		if (isl_basic_set_alloc_div(bset) < 0)
+			goto error;
+
+	j = n_div - 1;
+	for (i = div->n_row - 1; i >= 0; --i) {
+		if (j >= 0 && exp[j] == i) {
+			if (i != j)
+				isl_basic_map_swap_div(bset, i, j);
+			j--;
+		} else {
+			isl_seq_cpy(bset->div[i], div->row[i], div->n_col);
+			if (isl_basic_map_add_div_constraints(bset, i) < 0)
+				goto error;
+		}
+	}
+
+	isl_mat_free(div);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Look for a div in dst that corresponds to the div "div" in src.
+ * The divs before "div" in src and dst are assumed to be the same.
+ * 
+ * Returns -1 if no corresponding div was found and the position
+ * of the corresponding div in dst otherwise.
+ */
+static int find_div(struct isl_basic_map *dst,
+			struct isl_basic_map *src, unsigned div)
+{
+	int i;
+
+	unsigned total = isl_space_dim(src->dim, isl_dim_all);
+
+	isl_assert(dst->ctx, div <= dst->n_div, return -1);
+	for (i = div; i < dst->n_div; ++i)
+		if (isl_seq_eq(dst->div[i], src->div[div], 1+1+total+div) &&
+		    isl_seq_first_non_zero(dst->div[i]+1+1+total+div,
+						dst->n_div - div) == -1)
+			return i;
+	return -1;
+}
+
+/* Align the divs of "dst" to those of "src", adding divs from "src"
+ * if needed.  That is, make sure that the first src->n_div divs
+ * of the result are equal to those of src.
+ *
+ * The result is not finalized as by design it will have redundant
+ * divs if any divs from "src" were copied.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_divs(
+	__isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src)
+{
+	int i;
+	int known, extended;
+	unsigned total;
+
+	if (!dst || !src)
+		return isl_basic_map_free(dst);
+
+	if (src->n_div == 0)
+		return dst;
+
+	known = isl_basic_map_divs_known(src);
+	if (known < 0)
+		return isl_basic_map_free(dst);
+	if (!known)
+		isl_die(isl_basic_map_get_ctx(src), isl_error_invalid,
+			"some src divs are unknown",
+			return isl_basic_map_free(dst));
+
+	src = isl_basic_map_order_divs(src);
+
+	extended = 0;
+	total = isl_space_dim(src->dim, isl_dim_all);
+	for (i = 0; i < src->n_div; ++i) {
+		int j = find_div(dst, src, i);
+		if (j < 0) {
+			if (!extended) {
+				int extra = src->n_div - i;
+				dst = isl_basic_map_cow(dst);
+				if (!dst)
+					return NULL;
+				dst = isl_basic_map_extend_space(dst,
+						isl_space_copy(dst->dim),
+						extra, 0, 2 * extra);
+				extended = 1;
+			}
+			j = isl_basic_map_alloc_div(dst);
+			if (j < 0)
+				return isl_basic_map_free(dst);
+			isl_seq_cpy(dst->div[j], src->div[i], 1+1+total+i);
+			isl_seq_clr(dst->div[j]+1+1+total+i, dst->n_div - i);
+			if (isl_basic_map_add_div_constraints(dst, j) < 0)
+				return isl_basic_map_free(dst);
+		}
+		if (j != i)
+			isl_basic_map_swap_div(dst, i, j);
+	}
+	return dst;
+}
+
+struct isl_basic_set *isl_basic_set_align_divs(
+		struct isl_basic_set *dst, struct isl_basic_set *src)
+{
+	return (struct isl_basic_set *)isl_basic_map_align_divs(
+		(struct isl_basic_map *)dst, (struct isl_basic_map *)src);
+}
+
+struct isl_map *isl_map_align_divs(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+	map = isl_map_compute_divs(map);
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 1; i < map->n; ++i)
+		map->p[0] = isl_basic_map_align_divs(map->p[0], map->p[i]);
+	for (i = 1; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_align_divs(map->p[i], map->p[0]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+}
+
+struct isl_set *isl_set_align_divs(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_align_divs((struct isl_map *)set);
+}
+
+/* Align the divs of the basic sets in "set" to those
+ * of the basic sets in "list", as well as to the other basic sets in "set".
+ * The elements in "list" are assumed to have known divs.
+ */
+__isl_give isl_set *isl_set_align_divs_to_basic_set_list(
+	__isl_take isl_set *set, __isl_keep isl_basic_set_list *list)
+{
+	int i, n;
+
+	set = isl_set_compute_divs(set);
+	set = isl_set_cow(set);
+	if (!set || !list)
+		return isl_set_free(set);
+	if (set->n == 0)
+		return set;
+
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		set->p[0] = isl_basic_set_align_divs(set->p[0], bset);
+		isl_basic_set_free(bset);
+	}
+	if (!set->p[0])
+		return isl_set_free(set);
+
+	return isl_set_align_divs(set);
+}
+
+/* Align the divs of each element of "list" to those of "bset".
+ * Both "bset" and the elements of "list" are assumed to have known divs.
+ */
+__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set(
+	__isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset)
+{
+	int i, n;
+
+	if (!list || !bset)
+		return isl_basic_set_list_free(list);
+
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset_i;
+
+		bset_i = isl_basic_set_list_get_basic_set(list, i);
+		bset_i = isl_basic_set_align_divs(bset_i, bset);
+		list = isl_basic_set_list_set_basic_set(list, i, bset_i);
+	}
+
+	return list;
+}
+
+static __isl_give isl_set *set_apply( __isl_take isl_set *set,
+	__isl_take isl_map *map)
+{
+	if (!set || !map)
+		goto error;
+	isl_assert(set->ctx, isl_map_compatible_domain(map, set), goto error);
+	map = isl_map_intersect_domain(map, set);
+	set = isl_map_range(map);
+	return set;
+error:
+	isl_set_free(set);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_apply( __isl_take isl_set *set,
+	__isl_take isl_map *map)
+{
+	return isl_map_align_params_map_map_and(set, map, &set_apply);
+}
+
+/* There is no need to cow as removing empty parts doesn't change
+ * the meaning of the set.
+ */
+struct isl_map *isl_map_remove_empty_parts(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	for (i = map->n - 1; i >= 0; --i)
+		remove_if_empty(map, i);
+
+	return map;
+}
+
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set)
+{
+	return (struct isl_set *)
+		isl_map_remove_empty_parts((struct isl_map *)set);
+}
+
+struct isl_basic_map *isl_map_copy_basic_map(struct isl_map *map)
+{
+	struct isl_basic_map *bmap;
+	if (!map || map->n == 0)
+		return NULL;
+	bmap = map->p[map->n-1];
+	isl_assert(map->ctx, ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL), return NULL);
+	return isl_basic_map_copy(bmap);
+}
+
+struct isl_basic_set *isl_set_copy_basic_set(struct isl_set *set)
+{
+	return (struct isl_basic_set *)
+		isl_map_copy_basic_map((struct isl_map *)set);
+}
+
+__isl_give isl_map *isl_map_drop_basic_map(__isl_take isl_map *map,
+						__isl_keep isl_basic_map *bmap)
+{
+	int i;
+
+	if (!map || !bmap)
+		goto error;
+	for (i = map->n-1; i >= 0; --i) {
+		if (map->p[i] != bmap)
+			continue;
+		map = isl_map_cow(map);
+		if (!map)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		if (i != map->n-1) {
+			ISL_F_CLR(map, ISL_SET_NORMALIZED);
+			map->p[i] = map->p[map->n-1];
+		}
+		map->n--;
+		return map;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop_basic_set(struct isl_set *set,
+						struct isl_basic_set *bset)
+{
+	return (struct isl_set *)isl_map_drop_basic_map((struct isl_map *)set,
+						(struct isl_basic_map *)bset);
+}
+
+/* Given two basic sets bset1 and bset2, compute the maximal difference
+ * between the values of dimension pos in bset1 and those in bset2
+ * for any common value of the parameters and dimensions preceding pos.
+ */
+static enum isl_lp_result basic_set_maximal_difference_at(
+	__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,
+	int pos, isl_int *opt)
+{
+	isl_space *dims;
+	struct isl_basic_map *bmap1 = NULL;
+	struct isl_basic_map *bmap2 = NULL;
+	struct isl_ctx *ctx;
+	struct isl_vec *obj;
+	unsigned total;
+	unsigned nparam;
+	unsigned dim1, dim2;
+	enum isl_lp_result res;
+
+	if (!bset1 || !bset2)
+		return isl_lp_error;
+
+	nparam = isl_basic_set_n_param(bset1);
+	dim1 = isl_basic_set_n_dim(bset1);
+	dim2 = isl_basic_set_n_dim(bset2);
+	dims = isl_space_alloc(bset1->ctx, nparam, pos, dim1 - pos);
+	bmap1 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset1), dims);
+	dims = isl_space_alloc(bset2->ctx, nparam, pos, dim2 - pos);
+	bmap2 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset2), dims);
+	if (!bmap1 || !bmap2)
+		goto error;
+	bmap1 = isl_basic_map_cow(bmap1);
+	bmap1 = isl_basic_map_extend(bmap1, nparam,
+			pos, (dim1 - pos) + (dim2 - pos),
+			bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+	bmap1 = add_constraints(bmap1, bmap2, 0, dim1 - pos);
+	if (!bmap1)
+		goto error2;
+	total = isl_basic_map_total_dim(bmap1);
+	ctx = bmap1->ctx;
+	obj = isl_vec_alloc(ctx, 1 + total);
+	if (!obj)
+		goto error2;
+	isl_seq_clr(obj->block.data, 1 + total);
+	isl_int_set_si(obj->block.data[1+nparam+pos], 1);
+	isl_int_set_si(obj->block.data[1+nparam+pos+(dim1-pos)], -1);
+	res = isl_basic_map_solve_lp(bmap1, 1, obj->block.data, ctx->one,
+					opt, NULL, NULL);
+	isl_basic_map_free(bmap1);
+	isl_vec_free(obj);
+	return res;
+error:
+	isl_basic_map_free(bmap2);
+error2:
+	isl_basic_map_free(bmap1);
+	return isl_lp_error;
+}
+
+/* Given two _disjoint_ basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * in both basic sets, the values of dimension pos in bset1 are
+ * smaller or larger than those in bset2.
+ *
+ * Returns
+ *	 1 if bset1 follows bset2
+ *	-1 if bset1 precedes bset2
+ *	 0 if bset1 and bset2 are incomparable
+ *	-2 if some error occurred.
+ */
+int isl_basic_set_compare_at(struct isl_basic_set *bset1,
+	struct isl_basic_set *bset2, int pos)
+{
+	isl_int opt;
+	enum isl_lp_result res;
+	int cmp;
+
+	isl_int_init(opt);
+
+	res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+	if (res == isl_lp_empty)
+		cmp = 0;
+	else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+		  res == isl_lp_unbounded)
+		cmp = 1;
+	else if (res == isl_lp_ok && isl_int_is_neg(opt))
+		cmp = -1;
+	else
+		cmp = -2;
+
+	isl_int_clear(opt);
+	return cmp;
+}
+
+/* Given two basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in bset1 that is larger
+ * than a value of the same dimension in bset2.
+ *
+ * Return
+ *	 1 if there exists such a pair
+ *	 0 if there is no such pair, but there is a pair of equal values
+ *	-1 otherwise
+ *	-2 if some error occurred.
+ */
+int isl_basic_set_follows_at(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2, int pos)
+{
+	isl_int opt;
+	enum isl_lp_result res;
+	int cmp;
+
+	isl_int_init(opt);
+
+	res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+	if (res == isl_lp_empty)
+		cmp = -1;
+	else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+		  res == isl_lp_unbounded)
+		cmp = 1;
+	else if (res == isl_lp_ok && isl_int_is_neg(opt))
+		cmp = -1;
+	else if (res == isl_lp_ok)
+		cmp = 0;
+	else
+		cmp = -2;
+
+	isl_int_clear(opt);
+	return cmp;
+}
+
+/* Given two sets set1 and set2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in set1 that is larger
+ * than a value of the same dimension in set2.
+ *
+ * Return
+ *	 1 if there exists such a pair
+ *	 0 if there is no such pair, but there is a pair of equal values
+ *	-1 otherwise
+ *	-2 if some error occurred.
+ */
+int isl_set_follows_at(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2, int pos)
+{
+	int i, j;
+	int follows = -1;
+
+	if (!set1 || !set2)
+		return -2;
+
+	for (i = 0; i < set1->n; ++i)
+		for (j = 0; j < set2->n; ++j) {
+			int f;
+			f = isl_basic_set_follows_at(set1->p[i], set2->p[j], pos);
+			if (f == 1 || f == -2)
+				return f;
+			if (f > follows)
+				follows = f;
+		}
+
+	return follows;
+}
+
+static int isl_basic_map_plain_has_fixed_var(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *val)
+{
+	int i;
+	int d;
+	unsigned total;
+
+	if (!bmap)
+		return -1;
+	total = isl_basic_map_total_dim(bmap);
+	for (i = 0, d = total-1; i < bmap->n_eq && d+1 > pos; ++i) {
+		for (; d+1 > pos; --d)
+			if (!isl_int_is_zero(bmap->eq[i][1+d]))
+				break;
+		if (d != pos)
+			continue;
+		if (isl_seq_first_non_zero(bmap->eq[i]+1, d) != -1)
+			return 0;
+		if (isl_seq_first_non_zero(bmap->eq[i]+1+d+1, total-d-1) != -1)
+			return 0;
+		if (!isl_int_is_one(bmap->eq[i][1+d]))
+			return 0;
+		if (val)
+			isl_int_neg(*val, bmap->eq[i][0]);
+		return 1;
+	}
+	return 0;
+}
+
+static int isl_map_plain_has_fixed_var(__isl_keep isl_map *map,
+	unsigned pos, isl_int *val)
+{
+	int i;
+	isl_int v;
+	isl_int tmp;
+	int fixed;
+
+	if (!map)
+		return -1;
+	if (map->n == 0)
+		return 0;
+	if (map->n == 1)
+		return isl_basic_map_plain_has_fixed_var(map->p[0], pos, val); 
+	isl_int_init(v);
+	isl_int_init(tmp);
+	fixed = isl_basic_map_plain_has_fixed_var(map->p[0], pos, &v); 
+	for (i = 1; fixed == 1 && i < map->n; ++i) {
+		fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp); 
+		if (fixed == 1 && isl_int_ne(tmp, v))
+			fixed = 0;
+	}
+	if (val)
+		isl_int_set(*val, v);
+	isl_int_clear(tmp);
+	isl_int_clear(v);
+	return fixed;
+}
+
+static int isl_basic_set_plain_has_fixed_var(__isl_keep isl_basic_set *bset,
+	unsigned pos, isl_int *val)
+{
+	return isl_basic_map_plain_has_fixed_var((struct isl_basic_map *)bset,
+						pos, val);
+}
+
+static int isl_set_plain_has_fixed_var(__isl_keep isl_set *set, unsigned pos,
+	isl_int *val)
+{
+	return isl_map_plain_has_fixed_var((struct isl_map *)set, pos, val);
+}
+
+int isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	if (pos >= isl_basic_map_dim(bmap, type))
+		return -1;
+	return isl_basic_map_plain_has_fixed_var(bmap,
+		isl_basic_map_offset(bmap, type) - 1 + pos, val);
+}
+
+/* If "bmap" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed(
+	__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+	int fixed;
+
+	if (!bmap)
+		return NULL;
+	ctx = isl_basic_map_get_ctx(bmap);
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+	fixed = isl_basic_map_plain_is_fixed(bmap, type, pos, &v->n);
+	if (fixed < 0)
+		return isl_val_free(v);
+	if (fixed) {
+		isl_int_set_si(v->d, 1);
+		return v;
+	}
+	isl_val_free(v);
+	return isl_val_nan(ctx);
+}
+
+int isl_map_plain_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	if (pos >= isl_map_dim(map, type))
+		return -1;
+	return isl_map_plain_has_fixed_var(map,
+		map_offset(map, type) - 1 + pos, val);
+}
+
+/* If "map" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+	int fixed;
+
+	if (!map)
+		return NULL;
+	ctx = isl_map_get_ctx(map);
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+	fixed = isl_map_plain_is_fixed(map, type, pos, &v->n);
+	if (fixed < 0)
+		return isl_val_free(v);
+	if (fixed) {
+		isl_int_set_si(v->d, 1);
+		return v;
+	}
+	isl_val_free(v);
+	return isl_val_nan(ctx);
+}
+
+/* If "set" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_plain_get_val_if_fixed(set, type, pos);
+}
+
+int isl_set_plain_is_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	return isl_map_plain_is_fixed(set, type, pos, val);
+}
+
+int isl_map_fast_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	return isl_map_plain_is_fixed(map, type, pos, val);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+	unsigned dim, isl_int *val)
+{
+	return isl_basic_set_plain_has_fixed_var(bset,
+					isl_basic_set_n_param(bset) + dim, val);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_set_plain_dim_is_fixed(__isl_keep isl_set *set,
+	unsigned dim, isl_int *val)
+{
+	return isl_set_plain_has_fixed_var(set, isl_set_n_param(set) + dim, val);
+}
+
+int isl_set_fast_dim_is_fixed(__isl_keep isl_set *set,
+	unsigned dim, isl_int *val)
+{
+	return isl_set_plain_dim_is_fixed(set, dim, val);
+}
+
+/* Check if input variable in has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_map_plain_input_is_fixed(__isl_keep isl_map *map,
+	unsigned in, isl_int *val)
+{
+	return isl_map_plain_has_fixed_var(map, isl_map_n_param(map) + in, val);
+}
+
+/* Check if dimension dim has an (obvious) fixed lower bound and if so
+ * and if val is not NULL, then return this lower bound in *val.
+ */
+int isl_basic_set_plain_dim_has_fixed_lower_bound(
+	__isl_keep isl_basic_set *bset, unsigned dim, isl_int *val)
+{
+	int i, i_eq = -1, i_ineq = -1;
+	isl_int *c;
+	unsigned total;
+	unsigned nparam;
+
+	if (!bset)
+		return -1;
+	total = isl_basic_set_total_dim(bset);
+	nparam = isl_basic_set_n_param(bset);
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][1+nparam+dim]))
+			continue;
+		if (i_eq != -1)
+			return 0;
+		i_eq = i;
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (!isl_int_is_pos(bset->ineq[i][1+nparam+dim]))
+			continue;
+		if (i_eq != -1 || i_ineq != -1)
+			return 0;
+		i_ineq = i;
+	}
+	if (i_eq == -1 && i_ineq == -1)
+		return 0;
+	c = i_eq != -1 ? bset->eq[i_eq] : bset->ineq[i_ineq];
+	/* The coefficient should always be one due to normalization. */
+	if (!isl_int_is_one(c[1+nparam+dim]))
+		return 0;
+	if (isl_seq_first_non_zero(c+1, nparam+dim) != -1)
+		return 0;
+	if (isl_seq_first_non_zero(c+1+nparam+dim+1,
+					total - nparam - dim - 1) != -1)
+		return 0;
+	if (val)
+		isl_int_neg(*val, c[0]);
+	return 1;
+}
+
+int isl_set_plain_dim_has_fixed_lower_bound(__isl_keep isl_set *set,
+	unsigned dim, isl_int *val)
+{
+	int i;
+	isl_int v;
+	isl_int tmp;
+	int fixed;
+
+	if (!set)
+		return -1;
+	if (set->n == 0)
+		return 0;
+	if (set->n == 1)
+		return isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+								dim, val);
+	isl_int_init(v);
+	isl_int_init(tmp);
+	fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+								dim, &v);
+	for (i = 1; fixed == 1 && i < set->n; ++i) {
+		fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[i],
+								dim, &tmp);
+		if (fixed == 1 && isl_int_ne(tmp, v))
+			fixed = 0;
+	}
+	if (val)
+		isl_int_set(*val, v);
+	isl_int_clear(tmp);
+	isl_int_clear(v);
+	return fixed;
+}
+
+/* uset_gist depends on constraints without existentially quantified
+ * variables sorting first.
+ */
+static int sort_constraint_cmp(const void *p1, const void *p2, void *arg)
+{
+	isl_int **c1 = (isl_int **) p1;
+	isl_int **c2 = (isl_int **) p2;
+	int l1, l2;
+	unsigned size = *(unsigned *) arg;
+
+	l1 = isl_seq_last_non_zero(*c1 + 1, size);
+	l2 = isl_seq_last_non_zero(*c2 + 1, size);
+
+	if (l1 != l2)
+		return l1 - l2;
+
+	return isl_seq_cmp(*c1 + 1, *c2 + 1, size);
+}
+
+static struct isl_basic_map *isl_basic_map_sort_constraints(
+	struct isl_basic_map *bmap)
+{
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_ineq == 0)
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+		return bmap;
+	total = isl_basic_map_total_dim(bmap);
+	if (isl_sort(bmap->ineq, bmap->n_ineq, sizeof(isl_int *),
+		    &sort_constraint_cmp, &total) < 0)
+		return isl_basic_map_free(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+	__isl_take isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_sort_constraints(
+						(struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_normalize(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+		return bmap;
+	bmap = isl_basic_map_remove_redundancies(bmap);
+	bmap = isl_basic_map_sort_constraints(bmap);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_normalize(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_normalize(
+						(struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+	const __isl_keep isl_basic_map *bmap2)
+{
+	int i, cmp;
+	unsigned total;
+
+	if (bmap1 == bmap2)
+		return 0;
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) !=
+	    ISL_F_ISSET(bmap2, ISL_BASIC_MAP_RATIONAL))
+		return ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) ? -1 : 1;
+	if (isl_basic_map_n_param(bmap1) != isl_basic_map_n_param(bmap2))
+		return isl_basic_map_n_param(bmap1) - isl_basic_map_n_param(bmap2);
+	if (isl_basic_map_n_in(bmap1) != isl_basic_map_n_in(bmap2))
+		return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+	if (isl_basic_map_n_out(bmap1) != isl_basic_map_n_out(bmap2))
+		return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY) &&
+	    ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+		return 0;
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY))
+		return 1;
+	if (ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+		return -1;
+	if (bmap1->n_eq != bmap2->n_eq)
+		return bmap1->n_eq - bmap2->n_eq;
+	if (bmap1->n_ineq != bmap2->n_ineq)
+		return bmap1->n_ineq - bmap2->n_ineq;
+	if (bmap1->n_div != bmap2->n_div)
+		return bmap1->n_div - bmap2->n_div;
+	total = isl_basic_map_total_dim(bmap1);
+	for (i = 0; i < bmap1->n_eq; ++i) {
+		cmp = isl_seq_cmp(bmap1->eq[i], bmap2->eq[i], 1+total);
+		if (cmp)
+			return cmp;
+	}
+	for (i = 0; i < bmap1->n_ineq; ++i) {
+		cmp = isl_seq_cmp(bmap1->ineq[i], bmap2->ineq[i], 1+total);
+		if (cmp)
+			return cmp;
+	}
+	for (i = 0; i < bmap1->n_div; ++i) {
+		cmp = isl_seq_cmp(bmap1->div[i], bmap2->div[i], 1+1+total);
+		if (cmp)
+			return cmp;
+	}
+	return 0;
+}
+
+int isl_basic_set_plain_cmp(const __isl_keep isl_basic_set *bset1,
+	const __isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_cmp(bset1, bset2);
+}
+
+int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	int i, cmp;
+
+	if (set1 == set2)
+		return 0;
+	if (set1->n != set2->n)
+		return set1->n - set2->n;
+
+	for (i = 0; i < set1->n; ++i) {
+		cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]);
+		if (cmp)
+			return cmp;
+	}
+
+	return 0;
+}
+
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	return isl_basic_map_plain_cmp(bmap1, bmap2) == 0;
+}
+
+int isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_is_equal((isl_basic_map *)bset1,
+					    (isl_basic_map *)bset2);
+}
+
+static int qsort_bmap_cmp(const void *p1, const void *p2)
+{
+	const struct isl_basic_map *bmap1 = *(const struct isl_basic_map **)p1;
+	const struct isl_basic_map *bmap2 = *(const struct isl_basic_map **)p2;
+
+	return isl_basic_map_plain_cmp(bmap1, bmap2);
+}
+
+/* Sort the basic maps of "map" and remove duplicate basic maps.
+ *
+ * While removing basic maps, we make sure that the basic maps remain
+ * sorted because isl_map_normalize expects the basic maps of the result
+ * to be sorted.
+ */
+static __isl_give isl_map *sort_and_remove_duplicates(__isl_take isl_map *map)
+{
+	int i, j;
+
+	map = isl_map_remove_empty_parts(map);
+	if (!map)
+		return NULL;
+	qsort(map->p, map->n, sizeof(struct isl_basic_map *), qsort_bmap_cmp);
+	for (i = map->n - 1; i >= 1; --i) {
+		if (!isl_basic_map_plain_is_equal(map->p[i - 1], map->p[i]))
+			continue;
+		isl_basic_map_free(map->p[i-1]);
+		for (j = i; j < map->n; ++j)
+			map->p[j - 1] = map->p[j];
+		map->n--;
+	}
+
+	return map;
+}
+
+/* Remove obvious duplicates among the basic maps of "map".
+ *
+ * Unlike isl_map_normalize, this function does not remove redundant
+ * constraints and only removes duplicates that have exactly the same
+ * constraints in the input.  It does sort the constraints and
+ * the basic maps to ease the detection of duplicates.
+ *
+ * If "map" has already been normalized or if the basic maps are
+ * disjoint, then there can be no duplicates.
+ */
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	if (!map)
+		return NULL;
+	if (map->n <= 1)
+		return map;
+	if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED | ISL_MAP_DISJOINT))
+		return map;
+	for (i = 0; i < map->n; ++i) {
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = isl_basic_map_sort_constraints(bmap);
+		if (!bmap)
+			return isl_map_free(map);
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+	}
+
+	map = sort_and_remove_duplicates(map);
+	return map;
+}
+
+/* We normalize in place, but if anything goes wrong we need
+ * to return NULL, so we need to make sure we don't change the
+ * meaning of any possible other copies of map.
+ */
+__isl_give isl_map *isl_map_normalize(__isl_take isl_map *map)
+{
+	int i;
+	struct isl_basic_map *bmap;
+
+	if (!map)
+		return NULL;
+	if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED))
+		return map;
+	for (i = 0; i < map->n; ++i) {
+		bmap = isl_basic_map_normalize(isl_basic_map_copy(map->p[i]));
+		if (!bmap)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+	}
+
+	map = sort_and_remove_duplicates(map);
+	if (map)
+		ISL_F_SET(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_normalize(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_normalize((struct isl_map *)set);
+}
+
+int isl_map_plain_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	int i;
+	int equal;
+
+	if (!map1 || !map2)
+		return -1;
+
+	if (map1 == map2)
+		return 1;
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		return 0;
+
+	map1 = isl_map_copy(map1);
+	map2 = isl_map_copy(map2);
+	map1 = isl_map_normalize(map1);
+	map2 = isl_map_normalize(map2);
+	if (!map1 || !map2)
+		goto error;
+	equal = map1->n == map2->n;
+	for (i = 0; equal && i < map1->n; ++i) {
+		equal = isl_basic_map_plain_is_equal(map1->p[i], map2->p[i]);
+		if (equal < 0)
+			goto error;
+	}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return equal;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return -1;
+}
+
+int isl_map_fast_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	return isl_map_plain_is_equal(map1, map2);
+}
+
+int isl_set_plain_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_plain_is_equal((struct isl_map *)set1,
+						(struct isl_map *)set2);
+}
+
+int isl_set_fast_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_set_plain_is_equal(set1, set2);
+}
+
+/* Return an interval that ranges from min to max (inclusive)
+ */
+struct isl_basic_set *isl_basic_set_interval(struct isl_ctx *ctx,
+	isl_int min, isl_int max)
+{
+	int k;
+	struct isl_basic_set *bset = NULL;
+
+	bset = isl_basic_set_alloc(ctx, 0, 1, 0, 0, 2);
+	if (!bset)
+		goto error;
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_int_set_si(bset->ineq[k][1], 1);
+	isl_int_neg(bset->ineq[k][0], min);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_int_set_si(bset->ineq[k][1], -1);
+	isl_int_set(bset->ineq[k][0], max);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Return the basic sets in "set" as a list.
+ */
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+	__isl_keep isl_set *set)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_basic_set_list *list;
+
+	if (!set)
+		return NULL;
+	ctx = isl_set_get_ctx(set);
+	list = isl_basic_set_list_alloc(ctx, set->n);
+
+	for (i = 0; i < set->n; ++i) {
+		isl_basic_set *bset;
+
+		bset = isl_basic_set_copy(set->p[i]);
+		list = isl_basic_set_list_add(list, bset);
+	}
+
+	return list;
+}
+
+/* Return the intersection of the elements in the non-empty list "list".
+ * All elements are assumed to live in the same space.
+ */
+__isl_give isl_basic_set *isl_basic_set_list_intersect(
+	__isl_take struct isl_basic_set_list *list)
+{
+	int i, n;
+	isl_basic_set *bset;
+
+	if (!list)
+		return NULL;
+	n = isl_basic_set_list_n_basic_set(list);
+	if (n < 1)
+		isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid,
+			"expecting non-empty list", goto error);
+	
+	bset = isl_basic_set_list_get_basic_set(list, 0);
+	for (i = 1; i < n; ++i) {
+		isl_basic_set *bset_i;
+
+		bset_i = isl_basic_set_list_get_basic_set(list, i);
+		bset = isl_basic_set_intersect(bset, bset_i);
+	}
+
+	isl_basic_set_list_free(list);
+	return bset;
+error:
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Return the Cartesian product of the basic sets in list (in the given order).
+ */
+__isl_give isl_basic_set *isl_basic_set_list_product(
+	__isl_take struct isl_basic_set_list *list)
+{
+	int i;
+	unsigned dim;
+	unsigned nparam;
+	unsigned extra;
+	unsigned n_eq;
+	unsigned n_ineq;
+	struct isl_basic_set *product = NULL;
+
+	if (!list)
+		goto error;
+	isl_assert(list->ctx, list->n > 0, goto error);
+	isl_assert(list->ctx, list->p[0], goto error);
+	nparam = isl_basic_set_n_param(list->p[0]);
+	dim = isl_basic_set_n_dim(list->p[0]);
+	extra = list->p[0]->n_div;
+	n_eq = list->p[0]->n_eq;
+	n_ineq = list->p[0]->n_ineq;
+	for (i = 1; i < list->n; ++i) {
+		isl_assert(list->ctx, list->p[i], goto error);
+		isl_assert(list->ctx,
+		    nparam == isl_basic_set_n_param(list->p[i]), goto error);
+		dim += isl_basic_set_n_dim(list->p[i]);
+		extra += list->p[i]->n_div;
+		n_eq += list->p[i]->n_eq;
+		n_ineq += list->p[i]->n_ineq;
+	}
+	product = isl_basic_set_alloc(list->ctx, nparam, dim, extra,
+					n_eq, n_ineq);
+	if (!product)
+		goto error;
+	dim = 0;
+	for (i = 0; i < list->n; ++i) {
+		isl_basic_set_add_constraints(product,
+					isl_basic_set_copy(list->p[i]), dim);
+		dim += isl_basic_set_n_dim(list->p[i]);
+	}
+	isl_basic_set_list_free(list);
+	return product;
+error:
+	isl_basic_set_free(product);
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_product(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	isl_space *dim_result = NULL;
+	struct isl_basic_map *bmap;
+	unsigned in1, in2, out1, out2, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+				     bmap2->dim, isl_dim_param), goto error);
+	dim_result = isl_space_product(isl_space_copy(bmap1->dim),
+						   isl_space_copy(bmap2->dim));
+
+	in1 = isl_basic_map_n_in(bmap1);
+	in2 = isl_basic_map_n_in(bmap2);
+	out1 = isl_basic_map_n_out(bmap1);
+	out2 = isl_basic_map_n_out(bmap2);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	total = nparam + in1 + in2 + out1 + out2 + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+	isl_dim_map_div(dim_map1, bmap1, pos += out2);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_basic_map *prod;
+
+	prod = isl_basic_map_product(bmap1, bmap2);
+	prod = isl_basic_map_flatten(prod);
+	return prod;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flat_product(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	return isl_basic_map_flat_range_product(bset1, bset2);
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_space *space_result = NULL;
+	isl_basic_map *bmap;
+	unsigned in1, in2, out, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	space_result = isl_space_domain_product(isl_space_copy(bmap1->dim),
+						isl_space_copy(bmap2->dim));
+
+	in1 = isl_basic_map_dim(bmap1, isl_dim_in);
+	in2 = isl_basic_map_dim(bmap2, isl_dim_in);
+	out = isl_basic_map_dim(bmap1, isl_dim_out);
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+	total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos);
+	isl_dim_map_div(dim_map1, bmap1, pos += out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(space_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_space *dim_result = NULL;
+	isl_basic_map *bmap;
+	unsigned in, out1, out2, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	if (!isl_space_match(bmap1->dim, isl_dim_param,
+			    bmap2->dim, isl_dim_param))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"parameters don't match", goto error);
+
+	dim_result = isl_space_range_product(isl_space_copy(bmap1->dim),
+					   isl_space_copy(bmap2->dim));
+
+	in = isl_basic_map_dim(bmap1, isl_dim_in);
+	out1 = isl_basic_map_n_out(bmap1);
+	out2 = isl_basic_map_n_out(bmap2);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+	isl_dim_map_div(dim_map1, bmap1, pos += out2);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_basic_map *prod;
+
+	prod = isl_basic_map_range_product(bmap1, bmap2);
+	prod = isl_basic_map_flatten_range(prod);
+	return prod;
+}
+
+/* Apply "basic_map_product" to each pair of basic maps in "map1" and "map2"
+ * and collect the results.
+ * The result live in the space obtained by calling "space_product"
+ * on the spaces of "map1" and "map2".
+ * If "remove_duplicates" is set then the result may contain duplicates
+ * (even if the inputs do not) and so we try and remove the obvious
+ * duplicates.
+ */
+static __isl_give isl_map *map_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2,
+	__isl_give isl_space *(*space_product)(__isl_take isl_space *left,
+					   __isl_take isl_space *right),
+	__isl_give isl_basic_map *(*basic_map_product)(
+		__isl_take isl_basic_map *left,
+		__isl_take isl_basic_map *right),
+	int remove_duplicates)
+{
+	unsigned flags = 0;
+	struct isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_match(map1->dim, isl_dim_param,
+					 map2->dim, isl_dim_param), goto error);
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(space_product(isl_space_copy(map1->dim),
+					       isl_space_copy(map2->dim)),
+				map1->n * map2->n, flags);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = basic_map_product(isl_basic_map_copy(map1->p[i]),
+						 isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part))
+				isl_basic_map_free(part);
+			else
+				result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	if (remove_duplicates)
+		result = isl_map_remove_obvious_duplicates(result);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> [B -> D]
+ */
+static __isl_give isl_map *map_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_product,
+			&isl_basic_map_product, 0);
+}
+
+__isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_product_aligned);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_product(map1, map2);
+	prod = isl_map_flatten(prod);
+	return prod;
+}
+
+/* Given two set A and B, construct its Cartesian product A x B.
+ */
+struct isl_set *isl_set_product(struct isl_set *set1, struct isl_set *set2)
+{
+	return isl_map_range_product(set1, set2);
+}
+
+__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	return isl_map_flat_range_product(set1, set2);
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)
+ */
+static __isl_give isl_map *map_domain_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_domain_product,
+				&isl_basic_map_domain_product, 1);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D]
+ */
+static __isl_give isl_map *map_range_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_range_product,
+				&isl_basic_map_range_product, 1);
+}
+
+__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2,
+						&map_domain_product_aligned);
+}
+
+__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2,
+						&map_range_product_aligned);
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map A -> C.
+ */
+__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total1, keep1, total2, keep2;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim) ||
+	    !isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total1 = isl_space_dim(space, isl_dim_in);
+	total2 = isl_space_dim(space, isl_dim_out);
+	space = isl_space_factor_domain(space);
+	keep1 = isl_space_dim(space, isl_dim_in);
+	keep2 = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_in, keep1, total1 - keep1);
+	map = isl_map_project_out(map, isl_dim_out, keep2, total2 - keep2);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map B -> D.
+ */
+__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total1, keep1, total2, keep2;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim) ||
+	    !isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total1 = isl_space_dim(space, isl_dim_in);
+	total2 = isl_space_dim(space, isl_dim_out);
+	space = isl_space_factor_range(space);
+	keep1 = isl_space_dim(space, isl_dim_in);
+	keep2 = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_in, 0, total1 - keep1);
+	map = isl_map_project_out(map, isl_dim_out, 0, total2 - keep2);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map A -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"domain is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_in);
+	space = isl_space_domain_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, keep, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map B -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"domain is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_in);
+	space = isl_space_domain_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, 0, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> B.
+ */
+__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"range is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, keep, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> C.
+ */
+__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"range is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, 0, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D)
+ */
+__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_domain_product(map1, map2);
+	prod = isl_map_flatten_domain(prod);
+	return prod;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_range_product(map1, map2);
+	prod = isl_map_flatten_range(prod);
+	return prod;
+}
+
+uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	uint32_t hash = isl_hash_init();
+	unsigned total;
+
+	if (!bmap)
+		return 0;
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_normalize(bmap);
+	if (!bmap)
+		return 0;
+	total = isl_basic_map_total_dim(bmap);
+	isl_hash_byte(hash, bmap->n_eq & 0xFF);
+	for (i = 0; i < bmap->n_eq; ++i) {
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(bmap->eq[i], 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_hash_byte(hash, bmap->n_ineq & 0xFF);
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(bmap->ineq[i], 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_hash_byte(hash, bmap->n_div & 0xFF);
+	for (i = 0; i < bmap->n_div; ++i) {
+		uint32_t c_hash;
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		isl_hash_byte(hash, i & 0xFF);
+		c_hash = isl_seq_get_hash(bmap->div[i], 1 + 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_basic_map_free(bmap);
+	return hash;
+}
+
+uint32_t isl_basic_set_get_hash(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_hash((isl_basic_map *)bset);
+}
+
+uint32_t isl_map_get_hash(__isl_keep isl_map *map)
+{
+	int i;
+	uint32_t hash;
+
+	if (!map)
+		return 0;
+	map = isl_map_copy(map);
+	map = isl_map_normalize(map);
+	if (!map)
+		return 0;
+
+	hash = isl_hash_init();
+	for (i = 0; i < map->n; ++i) {
+		uint32_t bmap_hash;
+		bmap_hash = isl_basic_map_get_hash(map->p[i]);
+		isl_hash_hash(hash, bmap_hash);
+	}
+		
+	isl_map_free(map);
+
+	return hash;
+}
+
+uint32_t isl_set_get_hash(__isl_keep isl_set *set)
+{
+	return isl_map_get_hash((isl_map *)set);
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality.
+ */
+int isl_basic_set_dim_is_unique(struct isl_basic_set *bset, unsigned dim)
+{
+	int i;
+	unsigned nparam;
+
+	if (!bset)
+		return -1;
+	nparam = isl_basic_set_n_param(bset);
+	for (i = 0; i < bset->n_eq; ++i)
+		if (!isl_int_is_zero(bset->eq[i][1 + nparam + dim]))
+			return 1;
+	return 0;
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality
+ * for each of the subsets.
+ */
+int isl_set_dim_is_unique(struct isl_set *set, unsigned dim)
+{
+	int i;
+
+	if (!set)
+		return -1;
+	for (i = 0; i < set->n; ++i) {
+		int unique;
+		unique = isl_basic_set_dim_is_unique(set->p[i], dim);
+		if (unique != 1)
+			return unique;
+	}
+	return 1;
+}
+
+/* Return the number of basic maps in the (current) representation of "map".
+ */
+int isl_map_n_basic_map(__isl_keep isl_map *map)
+{
+	return map ? map->n : 0;
+}
+
+int isl_set_n_basic_set(__isl_keep isl_set *set)
+{
+	return set ? set->n : 0;
+}
+
+int isl_map_foreach_basic_map(__isl_keep isl_map *map,
+	int (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i)
+		if (fn(isl_basic_map_copy(map->p[i]), user) < 0)
+			return -1;
+
+	return 0;
+}
+
+int isl_set_foreach_basic_set(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_basic_set *bset, void *user), void *user)
+{
+	int i;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i)
+		if (fn(isl_basic_set_copy(set->p[i]), user) < 0)
+			return -1;
+
+	return 0;
+}
+
+__isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_lift(dim, bset->n_div);
+	if (!dim)
+		goto error;
+	isl_space_free(bset->dim);
+	bset->dim = dim;
+	bset->extra -= bset->n_div;
+	bset->n_div = 0;
+
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_lift(__isl_take isl_set *set)
+{
+	int i;
+	isl_space *dim;
+	unsigned n_div;
+
+	set = isl_set_align_divs(set);
+
+	if (!set)
+		return NULL;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	n_div = set->p[0]->n_div;
+	dim = isl_set_get_space(set);
+	dim = isl_space_lift(dim, n_div);
+	if (!dim)
+		goto error;
+	isl_space_free(set->dim);
+	set->dim = dim;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_lift(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_set_lifting(__isl_take isl_set *set)
+{
+	isl_space *dim;
+	struct isl_basic_map *bmap;
+	unsigned n_set;
+	unsigned n_div;
+	unsigned n_param;
+	unsigned total;
+	int i, k, l;
+
+	set = isl_set_align_divs(set);
+
+	if (!set)
+		return NULL;
+
+	dim = isl_set_get_space(set);
+	if (set->n == 0 || set->p[0]->n_div == 0) {
+		isl_set_free(set);
+		return isl_map_identity(isl_space_map_from_set(dim));
+	}
+
+	n_div = set->p[0]->n_div;
+	dim = isl_space_map_from_set(dim);
+	n_param = isl_space_dim(dim, isl_dim_param);
+	n_set = isl_space_dim(dim, isl_dim_in);
+	dim = isl_space_extend(dim, n_param, n_set, n_set + n_div);
+	bmap = isl_basic_map_alloc_space(dim, 0, n_set, 2 * n_div);
+	for (i = 0; i < n_set; ++i)
+		bmap = var_equal(bmap, i);
+
+	total = n_param + n_set + n_set + n_div;
+	for (i = 0; i < n_div; ++i) {
+		k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->ineq[k], set->p[0]->div[i]+1, 1+n_param);
+		isl_seq_clr(bmap->ineq[k]+1+n_param, n_set);
+		isl_seq_cpy(bmap->ineq[k]+1+n_param+n_set,
+			    set->p[0]->div[i]+1+1+n_param, n_set + n_div);
+		isl_int_neg(bmap->ineq[k][1+n_param+n_set+n_set+i],
+			    set->p[0]->div[i][0]);
+
+		l = isl_basic_map_alloc_inequality(bmap);
+		if (l < 0)
+			goto error;
+		isl_seq_neg(bmap->ineq[l], bmap->ineq[k], 1 + total);
+		isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0],
+			    set->p[0]->div[i][0]);
+		isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	}
+
+	isl_set_free(set);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return isl_map_from_basic_map(bmap);
+error:
+	isl_set_free(set);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+int isl_basic_set_size(__isl_keep isl_basic_set *bset)
+{
+	unsigned dim;
+	int size = 0;
+
+	if (!bset)
+		return -1;
+
+	dim = isl_basic_set_total_dim(bset);
+	size += bset->n_eq * (1 + dim);
+	size += bset->n_ineq * (1 + dim);
+	size += bset->n_div * (2 + dim);
+
+	return size;
+}
+
+int isl_set_size(__isl_keep isl_set *set)
+{
+	int i;
+	int size = 0;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i)
+		size += isl_basic_set_size(set->p[i]);
+
+	return size;
+}
+
+/* Check if there is any lower bound (if lower == 0) and/or upper
+ * bound (if upper == 0) on the specified dim.
+ */
+static int basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int lower, int upper)
+{
+	int i;
+
+	if (!bmap)
+		return -1;
+
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), return -1);
+
+	pos += isl_basic_map_offset(bmap, type);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1 + pos]))
+			return 1;
+	}
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][pos]))
+			return 1;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		int sgn = isl_int_sgn(bmap->ineq[i][pos]);
+		if (sgn > 0)
+			lower = 1;
+		if (sgn < 0)
+			upper = 1;
+	}
+
+	return lower && upper;
+}
+
+int isl_basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 0, 0);
+}
+
+int isl_basic_map_dim_has_lower_bound(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 0, 1);
+}
+
+int isl_basic_map_dim_has_upper_bound(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 1, 0);
+}
+
+int isl_map_dim_is_bounded(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int bounded;
+		bounded = isl_basic_map_dim_is_bounded(map->p[i], type, pos);
+		if (bounded < 0 || !bounded)
+			return bounded;
+	}
+
+	return 1;
+}
+
+/* Return 1 if the specified dim is involved in both an upper bound
+ * and a lower bound.
+ */
+int isl_set_dim_is_bounded(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_dim_is_bounded((isl_map *)set, type, pos);
+}
+
+/* Does "map" have a bound (according to "fn") for any of its basic maps?
+ */
+static int has_any_bound(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos,
+	int (*fn)(__isl_keep isl_basic_map *bmap,
+		  enum isl_dim_type type, unsigned pos))
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int bounded;
+		bounded = fn(map->p[i], type, pos);
+		if (bounded < 0 || bounded)
+			return bounded;
+	}
+
+	return 0;
+}
+
+/* Return 1 if the specified dim is involved in any lower bound.
+ */
+int isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_any_bound(set, type, pos,
+				&isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim is involved in any upper bound.
+ */
+int isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_any_bound(set, type, pos,
+				&isl_basic_map_dim_has_upper_bound);
+}
+
+/* Does "map" have a bound (according to "fn") for all of its basic maps?
+ */
+static int has_bound(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos,
+	int (*fn)(__isl_keep isl_basic_map *bmap,
+		  enum isl_dim_type type, unsigned pos))
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int bounded;
+		bounded = fn(map->p[i], type, pos);
+		if (bounded < 0 || !bounded)
+			return bounded;
+	}
+
+	return 1;
+}
+
+/* Return 1 if the specified dim has a lower bound (in each of its basic sets).
+ */
+int isl_set_dim_has_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_bound(set, type, pos, &isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim has an upper bound (in each of its basic sets).
+ */
+int isl_set_dim_has_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_bound(set, type, pos, &isl_basic_map_dim_has_upper_bound);
+}
+
+/* For each of the "n" variables starting at "first", determine
+ * the sign of the variable and put the results in the first "n"
+ * elements of the array "signs".
+ * Sign
+ *	1 means that the variable is non-negative
+ *	-1 means that the variable is non-positive
+ *	0 means the variable attains both positive and negative values.
+ */
+int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n, int *signs)
+{
+	isl_vec *bound = NULL;
+	struct isl_tab *tab = NULL;
+	struct isl_tab_undo *snap;
+	int i;
+
+	if (!bset || !signs)
+		return -1;
+
+	bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset));
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!bound || !tab)
+		goto error;
+
+	isl_seq_clr(bound->el, bound->size);
+	isl_int_set_si(bound->el[0], -1);
+
+	snap = isl_tab_snap(tab);
+	for (i = 0; i < n; ++i) {
+		int empty;
+
+		isl_int_set_si(bound->el[1 + first + i], -1);
+		if (isl_tab_add_ineq(tab, bound->el) < 0)
+			goto error;
+		empty = tab->empty;
+		isl_int_set_si(bound->el[1 + first + i], 0);
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+
+		if (empty) {
+			signs[i] = 1;
+			continue;
+		}
+
+		isl_int_set_si(bound->el[1 + first + i], 1);
+		if (isl_tab_add_ineq(tab, bound->el) < 0)
+			goto error;
+		empty = tab->empty;
+		isl_int_set_si(bound->el[1 + first + i], 0);
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+
+		signs[i] = empty ? -1 : 0;
+	}
+
+	isl_tab_free(tab);
+	isl_vec_free(bound);
+	return 0;
+error:
+	isl_tab_free(tab);
+	isl_vec_free(bound);
+	return -1;
+}
+
+int isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n, int *signs)
+{
+	if (!bset || !signs)
+		return -1;
+	isl_assert(bset->ctx, first + n <= isl_basic_set_dim(bset, type),
+		return -1);
+
+	first += pos(bset->dim, type) - 1;
+	return isl_basic_set_vars_get_sign(bset, first, n, signs);
+}
+
+/* Is it possible for the integer division "div" to depend (possibly
+ * indirectly) on any output dimensions?
+ *
+ * If the div is undefined, then we conservatively assume that it
+ * may depend on them.
+ * Otherwise, we check if it actually depends on them or on any integer
+ * divisions that may depend on them.
+ */
+static int div_may_involve_output(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned n_out, o_out;
+	unsigned n_div, o_div;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return 1;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+
+	if (isl_seq_first_non_zero(bmap->div[div] + 1 + o_out, n_out) != -1)
+		return 1;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+	for (i = 0; i < n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[div][1 + o_div + i]))
+			continue;
+		if (div_may_involve_output(bmap, i))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Return the index of the equality of "bmap" that defines
+ * the output dimension "pos" in terms of earlier dimensions.
+ * The equality may also involve integer divisions, as long
+ * as those integer divisions are defined in terms of
+ * parameters or input dimensions.
+ * Return bmap->n_eq if there is no such equality.
+ * Return -1 on error.
+ */
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+	int pos)
+{
+	int j, k;
+	unsigned n_out, o_out;
+	unsigned n_div, o_div;
+
+	if (!bmap)
+		return -1;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+	for (j = 0; j < bmap->n_eq; ++j) {
+		if (isl_int_is_zero(bmap->eq[j][o_out + pos]))
+			continue;
+		if (isl_seq_first_non_zero(bmap->eq[j] + o_out + pos + 1,
+					n_out - (pos + 1)) != -1)
+			continue;
+		for (k = 0; k < n_div; ++k) {
+			if (isl_int_is_zero(bmap->eq[j][o_div + k]))
+				continue;
+			if (div_may_involve_output(bmap, k))
+				break;
+		}
+		if (k >= n_div)
+			return j;
+	}
+
+	return bmap->n_eq;
+}
+
+/* Check if the given basic map is obviously single-valued.
+ * In particular, for each output dimension, check that there is
+ * an equality that defines the output dimension in terms of
+ * earlier dimensions.
+ */
+int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned n_out;
+
+	if (!bmap)
+		return -1;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	for (i = 0; i < n_out; ++i) {
+		int eq;
+
+		eq = isl_basic_map_output_defining_equality(bmap, i);
+		if (eq < 0)
+			return -1;
+		if (eq >= bmap->n_eq)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Check if the given basic map is single-valued.
+ * We simply compute
+ *
+ *	M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+	isl_space *space;
+	isl_basic_map *test;
+	isl_basic_map *id;
+	int sv;
+
+	sv = isl_basic_map_plain_is_single_valued(bmap);
+	if (sv < 0 || sv)
+		return sv;
+
+	test = isl_basic_map_reverse(isl_basic_map_copy(bmap));
+	test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap));
+
+	space = isl_basic_map_get_space(bmap);
+	space = isl_space_map_from_set(isl_space_range(space));
+	id = isl_basic_map_identity(space);
+
+	sv = isl_basic_map_is_subset(test, id);
+
+	isl_basic_map_free(test);
+	isl_basic_map_free(id);
+
+	return sv;
+}
+
+/* Check if the given map is obviously single-valued.
+ */
+int isl_map_plain_is_single_valued(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	if (map->n == 0)
+		return 1;
+	if (map->n >= 2)
+		return 0;
+
+	return isl_basic_map_plain_is_single_valued(map->p[0]);
+}
+
+/* Check if the given map is single-valued.
+ * We simply compute
+ *
+ *	M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_map_is_single_valued(__isl_keep isl_map *map)
+{
+	isl_space *dim;
+	isl_map *test;
+	isl_map *id;
+	int sv;
+
+	sv = isl_map_plain_is_single_valued(map);
+	if (sv < 0 || sv)
+		return sv;
+
+	test = isl_map_reverse(isl_map_copy(map));
+	test = isl_map_apply_range(test, isl_map_copy(map));
+
+	dim = isl_space_map_from_set(isl_space_range(isl_map_get_space(map)));
+	id = isl_map_identity(dim);
+
+	sv = isl_map_is_subset(test, id);
+
+	isl_map_free(test);
+	isl_map_free(id);
+
+	return sv;
+}
+
+int isl_map_is_injective(__isl_keep isl_map *map)
+{
+	int in;
+
+	map = isl_map_copy(map);
+	map = isl_map_reverse(map);
+	in = isl_map_is_single_valued(map);
+	isl_map_free(map);
+
+	return in;
+}
+
+/* Check if the given map is obviously injective.
+ */
+int isl_map_plain_is_injective(__isl_keep isl_map *map)
+{
+	int in;
+
+	map = isl_map_copy(map);
+	map = isl_map_reverse(map);
+	in = isl_map_plain_is_single_valued(map);
+	isl_map_free(map);
+
+	return in;
+}
+
+int isl_map_is_bijective(__isl_keep isl_map *map)
+{
+	int sv;
+
+	sv = isl_map_is_single_valued(map);
+	if (sv < 0 || !sv)
+		return sv;
+
+	return isl_map_is_injective(map);
+}
+
+int isl_set_is_singleton(__isl_keep isl_set *set)
+{
+	return isl_map_is_single_valued((isl_map *)set);
+}
+
+int isl_map_is_translation(__isl_keep isl_map *map)
+{
+	int ok;
+	isl_set *delta;
+
+	delta = isl_map_deltas(isl_map_copy(map));
+	ok = isl_set_is_singleton(delta);
+	isl_set_free(delta);
+
+	return ok;
+}
+
+static int unique(isl_int *p, unsigned pos, unsigned len)
+{
+	if (isl_seq_first_non_zero(p, pos) != -1)
+		return 0;
+	if (isl_seq_first_non_zero(p + pos + 1, len - pos - 1) != -1)
+		return 0;
+	return 1;
+}
+
+int isl_basic_set_is_box(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned nvar;
+	unsigned ovar;
+
+	if (!bset)
+		return -1;
+
+	if (isl_basic_set_dim(bset, isl_dim_div) != 0)
+		return 0;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	ovar = isl_space_offset(bset->dim, isl_dim_set);
+	for (j = 0; j < nvar; ++j) {
+		int lower = 0, upper = 0;
+		for (i = 0; i < bset->n_eq; ++i) {
+			if (isl_int_is_zero(bset->eq[i][1 + ovar + j]))
+				continue;
+			if (!unique(bset->eq[i] + 1 + ovar, j, nvar))
+				return 0;
+			break;
+		}
+		if (i < bset->n_eq)
+			continue;
+		for (i = 0; i < bset->n_ineq; ++i) {
+			if (isl_int_is_zero(bset->ineq[i][1 + ovar + j]))
+				continue;
+			if (!unique(bset->ineq[i] + 1 + ovar, j, nvar))
+				return 0;
+			if (isl_int_is_pos(bset->ineq[i][1 + ovar + j]))
+				lower = 1;
+			else
+				upper = 1;
+		}
+		if (!lower || !upper)
+			return 0;
+	}
+
+	return 1;
+}
+
+int isl_set_is_box(__isl_keep isl_set *set)
+{
+	if (!set)
+		return -1;
+	if (set->n != 1)
+		return 0;
+
+	return isl_basic_set_is_box(set->p[0]);
+}
+
+int isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return -1;
+	
+	return isl_space_is_wrapping(bset->dim);
+}
+
+int isl_set_is_wrapping(__isl_keep isl_set *set)
+{
+	if (!set)
+		return -1;
+	
+	return isl_space_is_wrapping(set->dim);
+}
+
+/* Is the domain of "map" a wrapped relation?
+ */
+int isl_map_domain_is_wrapping(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+
+	return isl_space_domain_is_wrapping(map->dim);
+}
+
+/* Is the range of "map" a wrapped relation?
+ */
+int isl_map_range_is_wrapping(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+
+	return isl_space_range_is_wrapping(map->dim);
+}
+
+__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_wrap(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return (isl_basic_set *)bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = (isl_basic_map *)isl_basic_map_wrap(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_wrap(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return (isl_set *)map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset)
+{
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	bset->dim = isl_space_unwrap(bset->dim);
+	if (!bset->dim)
+		goto error;
+
+	bset = isl_basic_set_finalize(bset);
+
+	return (isl_basic_map *)bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+
+	if (!isl_set_is_wrapping(set))
+		isl_die(set->ctx, isl_error_invalid, "not a wrapping set",
+			goto error);
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = (isl_basic_set *)isl_basic_set_unwrap(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	set->dim = isl_space_unwrap(set->dim);
+	if (!set->dim)
+		goto error;
+
+	return (isl_map *)set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_reset(bmap->dim, type);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_space_is_named_or_nested(map->dim, type))
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reset(map->p[i], type);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_reset(map->dim, type);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[0] && !bmap->dim->nested[1])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset)
+{
+	return (isl_basic_set *)isl_basic_map_flatten((isl_basic_map *)bset);
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[0])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten_domain(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_range(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[1])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten_range(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[0] && !map->dim->nested[1])
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_flatten(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set)
+{
+	return (isl_set *)isl_map_flatten((isl_map *)set);
+}
+
+__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set)
+{
+	isl_space *dim, *flat_dim;
+	isl_map *map;
+
+	dim = isl_set_get_space(set);
+	flat_dim = isl_space_flatten(isl_space_copy(dim));
+	map = isl_map_identity(isl_space_join(isl_space_reverse(dim), flat_dim));
+	map = isl_map_intersect_domain(map, set);
+
+	return map;
+}
+
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[0])
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_flatten_domain(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten_domain(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[1])
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_flatten_range(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten_range(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Reorder the dimensions of "bmap" according to the given dim_map
+ * and set the dimension specification to "dim".
+ */
+__isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap,
+	__isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map)
+{
+	isl_basic_map *res;
+	unsigned flags;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !dim || !dim_map)
+		goto error;
+
+	flags = bmap->flags;
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL);
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED);
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	res = isl_basic_map_alloc_space(dim,
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	if (res)
+		res->flags = flags;
+	res = isl_basic_map_finalize(res);
+	return res;
+error:
+	free(dim_map);
+	isl_basic_map_free(bmap);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reorder the dimensions of "map" according to given reordering.
+ */
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+	__isl_take isl_reordering *r)
+{
+	int i;
+	struct isl_dim_map *dim_map;
+
+	map = isl_map_cow(map);
+	dim_map = isl_dim_map_from_reordering(r);
+	if (!map || !r || !dim_map)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		struct isl_dim_map *dim_map_i;
+
+		dim_map_i = isl_dim_map_extend(dim_map, map->p[i]);
+
+		map->p[i] = isl_basic_map_realign(map->p[i],
+					    isl_space_copy(r->dim), dim_map_i);
+
+		if (!map->p[i])
+			goto error;
+	}
+
+	map = isl_map_reset_space(map, isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+	free(dim_map);
+	return map;
+error:
+	free(dim_map);
+	isl_map_free(map);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+	__isl_take isl_reordering *r)
+{
+	return (isl_set *)isl_map_realign((isl_map *)set, r);
+}
+
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+	__isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+
+	if (!map || !model)
+		goto error;
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (!isl_space_has_named_params(map->dim))
+		isl_die(ctx, isl_error_invalid,
+			"relation has unnamed parameters", goto error);
+	if (!isl_space_match(map->dim, isl_dim_param, model, isl_dim_param)) {
+		isl_reordering *exp;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(map->dim, model);
+		exp = isl_reordering_extend_space(exp, isl_map_get_space(map));
+		map = isl_map_realign(map, exp);
+	}
+
+	isl_space_free(model);
+	return map;
+error:
+	isl_space_free(model);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+	__isl_take isl_space *model)
+{
+	return isl_map_align_params(set, model);
+}
+
+/* Align the parameters of "bmap" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_params(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+
+	if (!bmap || !model)
+		goto error;
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (!isl_space_has_named_params(bmap->dim))
+		isl_die(ctx, isl_error_invalid,
+			"relation has unnamed parameters", goto error);
+	if (!isl_space_match(bmap->dim, isl_dim_param, model, isl_dim_param)) {
+		isl_reordering *exp;
+		struct isl_dim_map *dim_map;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(bmap->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					isl_basic_map_get_space(bmap));
+		dim_map = isl_dim_map_from_reordering(exp);
+		bmap = isl_basic_map_realign(bmap,
+				    exp ? isl_space_copy(exp->dim) : NULL,
+				    isl_dim_map_extend(dim_map, bmap));
+		isl_reordering_free(exp);
+		free(dim_map);
+	}
+
+	isl_space_free(model);
+	return bmap;
+error:
+	isl_space_free(model);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Align the parameters of "bset" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_set *isl_basic_set_align_params(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *model)
+{
+	return isl_basic_map_align_params(bset, model);
+}
+
+__isl_give isl_mat *isl_basic_map_equalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	struct isl_mat *mat;
+	int i, j, k;
+	int pos;
+
+	if (!bmap)
+		return NULL;
+	mat = isl_mat_alloc(bmap->ctx, bmap->n_eq,
+				isl_basic_map_total_dim(bmap) + 1);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < bmap->n_eq; ++i)
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(mat->row[i][pos],
+					    bmap->eq[i][off + k]);
+				++pos;
+			}
+		}
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_basic_map_inequalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	struct isl_mat *mat;
+	int i, j, k;
+	int pos;
+
+	if (!bmap)
+		return NULL;
+	mat = isl_mat_alloc(bmap->ctx, bmap->n_ineq,
+				isl_basic_map_total_dim(bmap) + 1);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < bmap->n_ineq; ++i)
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(mat->row[i][pos],
+					    bmap->ineq[i][off + k]);
+				++pos;
+			}
+		}
+
+	return mat;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3,
+	enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	isl_basic_map *bmap;
+	unsigned total;
+	unsigned extra;
+	int i, j, k, l;
+	int pos;
+
+	if (!dim || !eq || !ineq)
+		goto error;
+
+	if (eq->n_col != ineq->n_col)
+		isl_die(dim->ctx, isl_error_invalid,
+			"equalities and inequalities matrices should have "
+			"same number of columns", goto error);
+
+	total = 1 + isl_space_dim(dim, isl_dim_all);
+
+	if (eq->n_col < total)
+		isl_die(dim->ctx, isl_error_invalid,
+			"number of columns too small", goto error);
+
+	extra = eq->n_col - total;
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(dim), extra,
+				       eq->n_row, ineq->n_row);
+	if (!bmap)
+		goto error;
+	for (i = 0; i < extra; ++i) {
+		k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(bmap->div[k][0], 0);
+	}
+	for (i = 0; i < eq->n_row; ++i) {
+		l = isl_basic_map_alloc_equality(bmap);
+		if (l < 0)
+			goto error;
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(bmap->eq[l][off + k], 
+					    eq->row[i][pos]);
+				++pos;
+			}
+		}
+	}
+	for (i = 0; i < ineq->n_row; ++i) {
+		l = isl_basic_map_alloc_inequality(bmap);
+		if (l < 0)
+			goto error;
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(bmap->ineq[l][off + k], 
+					    ineq->row[i][pos]);
+				++pos;
+			}
+		}
+	}
+
+	isl_space_free(dim);
+	isl_mat_free(eq);
+	isl_mat_free(ineq);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_space_free(dim);
+	isl_mat_free(eq);
+	isl_mat_free(ineq);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_basic_set_equalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	return isl_basic_map_equalities_matrix((isl_basic_map *)bset,
+						c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_mat *isl_basic_set_inequalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	return isl_basic_map_inequalities_matrix((isl_basic_map *)bset,
+						 c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	return (isl_basic_set*)
+	    isl_basic_map_from_constraint_matrices(dim, eq, ineq,
+						   c1, c2, c3, c4, isl_dim_in);
+}
+
+int isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	
+	return isl_space_can_zip(bmap->dim);
+}
+
+int isl_map_can_zip(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	
+	return isl_space_can_zip(map->dim);
+}
+
+/* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap)
+{
+	unsigned pos;
+	unsigned n1;
+	unsigned n2;
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_zip(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be zipped", goto error);
+	pos = isl_basic_map_offset(bmap, isl_dim_in) +
+		isl_space_dim(bmap->dim->nested[0], isl_dim_in);
+	n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out);
+	n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_zip(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Given a map (A -> B) -> (C -> D), return the corresponding map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_map *isl_map_zip(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_zip(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be zipped",
+			goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_zip(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	map->dim = isl_space_zip(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Can we apply isl_basic_map_curry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+
+	return isl_space_can_curry(bmap->dim);
+}
+
+/* Can we apply isl_map_curry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_map_can_curry(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+
+	return isl_space_can_curry(map->dim);
+}
+
+/* Given a basic map (A -> B) -> C, return the corresponding basic map
+ * A -> (B -> C).
+ */
+__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap)
+{
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_curry(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be curried", goto error);
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_curry(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Given a map (A -> B) -> C, return the corresponding map
+ * A -> (B -> C).
+ */
+__isl_give isl_map *isl_map_curry(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_curry(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be curried",
+			goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_curry(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	map->dim = isl_space_curry(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Can we apply isl_basic_map_uncurry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+
+	return isl_space_can_uncurry(bmap->dim);
+}
+
+/* Can we apply isl_map_uncurry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_map_can_uncurry(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+
+	return isl_space_can_uncurry(map->dim);
+}
+
+/* Given a basic map A -> (B -> C), return the corresponding basic map
+ * (A -> B) -> C.
+ */
+__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap)
+{
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_uncurry(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be uncurried",
+			return isl_basic_map_free(bmap));
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_uncurry(bmap->dim);
+	if (!bmap->dim)
+		return isl_basic_map_free(bmap);
+	return bmap;
+}
+
+/* Given a map A -> (B -> C), return the corresponding map
+ * (A -> B) -> C.
+ */
+__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_uncurry(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be uncurried",
+			return isl_map_free(map));
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_uncurry(map->p[i]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	map->dim = isl_space_uncurry(map->dim);
+	if (!map->dim)
+		return isl_map_free(map);
+
+	return map;
+}
+
+/* Construct a basic map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff)
+{
+	int k;
+	int pos;
+	isl_local_space *ls;
+	isl_basic_map *bmap;
+
+	if (!aff)
+		return NULL;
+
+	ls = isl_aff_get_local_space(aff);
+	bmap = isl_basic_map_from_local_space(ls);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+
+	pos = isl_basic_map_offset(bmap, isl_dim_out);
+	isl_seq_cpy(bmap->eq[k], aff->v->el + 1, pos);
+	isl_int_neg(bmap->eq[k][pos], aff->v->el[0]);
+	isl_seq_cpy(bmap->eq[k] + pos + 1, aff->v->el + 1 + pos,
+		    aff->v->size - (pos + 1));
+
+	isl_aff_free(aff);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_aff_free(aff);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Construct a map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_aff(aff);
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+	__isl_take isl_multi_aff *maff)
+{
+	int i;
+	isl_space *space;
+	isl_basic_map *bmap;
+
+	if (!maff)
+		return NULL;
+
+	if (isl_space_dim(maff->space, isl_dim_out) != maff->n)
+		isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal,
+			"invalid space", goto error);
+
+	space = isl_space_domain(isl_multi_aff_get_space(maff));
+	bmap = isl_basic_map_universe(isl_space_from_domain(space));
+
+	for (i = 0; i < maff->n; ++i) {
+		isl_aff *aff;
+		isl_basic_map *bmap_i;
+
+		aff = isl_aff_copy(maff->p[i]);
+		bmap_i = isl_basic_map_from_aff(aff);
+
+		bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+	}
+
+	bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff));
+
+	isl_multi_aff_free(maff);
+	return bmap;
+error:
+	isl_multi_aff_free(maff);
+	return NULL;
+}
+
+/* Construct a map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_multi_aff(maff);
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping a domain in the given space to
+ * to an n-dimensional range, with n the number of elements in the list,
+ * where each coordinate in the range is prescribed by the
+ * corresponding affine expression.
+ * The domains of all affine expressions in the list are assumed to match
+ * domain_dim.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff_list(
+	__isl_take isl_space *domain_dim, __isl_take isl_aff_list *list)
+{
+	int i;
+	isl_space *dim;
+	isl_basic_map *bmap;
+
+	if (!list)
+		return NULL;
+
+	dim = isl_space_from_domain(domain_dim);
+	bmap = isl_basic_map_universe(dim);
+
+	for (i = 0; i < list->n; ++i) {
+		isl_aff *aff;
+		isl_basic_map *bmap_i;
+
+		aff = isl_aff_copy(list->p[i]);
+		bmap_i = isl_basic_map_from_aff(aff);
+
+		bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+	}
+
+	isl_aff_list_free(list);
+	return bmap;
+}
+
+__isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_equate(set, type1, pos1, type2, pos2);
+}
+
+/* Construct a basic map where the given dimensions are equal to each other.
+ */
+static __isl_give isl_basic_map *equator(__isl_take isl_space *space,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (pos1 >= isl_space_dim(space, type1))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_space_dim(space, type2))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (type1 == type2 && pos1 == pos2)
+		return isl_basic_map_universe(space);
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0);
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->eq[i][pos1], -1);
+	isl_int_set_si(bmap->eq[i][pos2], 1);
+	bmap = isl_basic_map_finalize(bmap);
+	isl_space_free(space);
+	return bmap;
+error:
+	isl_space_free(space);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *eq;
+
+	eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+	bmap = isl_basic_map_intersect(bmap, eq);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap;
+
+	bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+/* Add a constraint imposing that the given two dimensions have opposite values.
+ */
+__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (pos1 >= isl_map_dim(map, type1))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_map_dim(map, type2))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0);
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->eq[i][pos1], 1);
+	isl_int_set_si(bmap->eq[i][pos2], 1);
+	bmap = isl_basic_map_finalize(bmap);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Construct a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+static __isl_give isl_constraint *constraint_order_ge(
+	__isl_take isl_space *space, enum isl_dim_type type1, int pos1,
+	enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+
+	if (!space)
+		return NULL;
+
+	c = isl_inequality_alloc(isl_local_space_from_space(space));
+
+	if (pos1 >= isl_constraint_dim(c, type1))
+		isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+			"index out of bounds", return isl_constraint_free(c));
+	if (pos2 >= isl_constraint_dim(c, type2))
+		isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+			"index out of bounds", return isl_constraint_free(c));
+
+	if (type1 == type2 && pos1 == pos2)
+		return c;
+
+	c = isl_constraint_set_coefficient_si(c, type1, pos1, 1);
+	c = isl_constraint_set_coefficient_si(c, type2, pos2, -1);
+
+	return c;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+	isl_space *space;
+
+	if (type1 == type2 && pos1 == pos2)
+		return bmap;
+	space = isl_basic_map_get_space(bmap);
+	c = constraint_order_ge(space, type1, pos1, type2, pos2);
+	bmap = isl_basic_map_add_constraint(bmap, c);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+	isl_space *space;
+
+	if (type1 == type2 && pos1 == pos2)
+		return map;
+	space = isl_map_get_space(map);
+	c = constraint_order_ge(space, type1, pos1, type2, pos2);
+	map = isl_map_add_constraint(map, c);
+
+	return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * less than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_order_ge(map, type2, pos2, type1, pos1);
+}
+
+/* Construct a basic map where the value of the first dimension is
+ * greater than that of the second.
+ */
+static __isl_give isl_basic_map *greator(__isl_take isl_space *space,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (pos1 >= isl_space_dim(space, type1))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_space_dim(space, type2))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (type1 == type2 && pos1 == pos2)
+		return isl_basic_map_empty(space);
+
+	bmap = isl_basic_map_alloc_space(space, 0, 0, 1);
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return isl_basic_map_free(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->ineq[i][pos1], 1);
+	isl_int_set_si(bmap->ineq[i][pos2], -1);
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_space_free(space);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *gt;
+
+	gt = greator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+	bmap = isl_basic_map_intersect(bmap, gt);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap;
+
+	bmap = greator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * smaller than that of the second.
+ */
+__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_order_gt(map, type2, pos2, type1, pos1);
+}
+
+__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap,
+	int pos)
+{
+	isl_aff *div;
+	isl_local_space *ls;
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_divs_known(bmap))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"some divs are unknown", return NULL);
+
+	ls = isl_basic_map_get_local_space(bmap);
+	div = isl_local_space_get_div(ls, pos);
+	isl_local_space_free(ls);
+
+	return div;
+}
+
+__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
+	int pos)
+{
+	return isl_basic_map_get_div(bset, pos);
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "bset".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ *
+ * Constraints of the form
+ *
+ *	a i + g
+ *
+ * are replaced by
+ *
+ *	a f + d g
+ *
+ * We currently require that "subs" is an integral expression.
+ * Handling rational expressions may require us to add stride constraints
+ * as we do in isl_basic_set_preimage_multi_aff.
+ */
+__isl_give isl_basic_set *isl_basic_set_substitute(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	int i;
+	isl_int v;
+	isl_ctx *ctx;
+
+	if (bset && isl_basic_set_plain_is_empty(bset))
+		return bset;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !subs)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (!isl_space_is_equal(bset->dim, subs->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+	if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+		isl_die(ctx, isl_error_unsupported,
+			"cannot handle divs yet", goto error);
+	if (!isl_int_is_one(subs->v->el[0]))
+		isl_die(ctx, isl_error_invalid,
+			"can only substitute integer expressions", goto error);
+
+	pos += isl_basic_set_offset(bset, type);
+
+	isl_int_init(v);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][pos]))
+			continue;
+		isl_int_set(v, bset->eq[i][pos]);
+		isl_int_set_si(bset->eq[i][pos], 0);
+		isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i],
+				v, subs->v->el + 1, subs->v->size - 1);
+	}
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][pos]))
+			continue;
+		isl_int_set(v, bset->ineq[i][pos]);
+		isl_int_set_si(bset->ineq[i][pos], 0);
+		isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i],
+				v, subs->v->el + 1, subs->v->size - 1);
+	}
+
+	for (i = 0; i < bset->n_div; ++i) {
+		if (isl_int_is_zero(bset->div[i][1 + pos]))
+			continue;
+		isl_int_set(v, bset->div[i][1 + pos]);
+		isl_int_set_si(bset->div[i][1 + pos], 0);
+		isl_seq_combine(bset->div[i] + 1,
+				subs->v->el[0], bset->div[i] + 1,
+				v, subs->v->el + 1, subs->v->size - 1);
+		isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]);
+	}
+
+	isl_int_clear(v);
+
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "set".
+ */
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	int i;
+
+	if (set && isl_set_plain_is_empty(set))
+		return set;
+
+	set = isl_set_cow(set);
+	if (!set || !subs)
+		goto error;
+
+	for (i = set->n - 1; i >= 0; --i) {
+		set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs);
+		if (remove_if_empty(set, i) < 0)
+			goto error;
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "bmap".
+ * Return -1 if anything is wrong.
+ */
+static int check_basic_map_compatible_range_multi_aff(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	int m;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+
+	m = isl_space_match(bmap->dim, isl_dim_param, ma_space, isl_dim_param);
+	if (m < 0)
+		goto error;
+	if (!m)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"parameters don't match", goto error);
+	m = isl_space_tuple_is_equal(bmap->dim, type, ma_space, isl_dim_out);
+	if (m < 0)
+		goto error;
+	if (!m)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	isl_space_free(ma_space);
+	return m;
+error:
+	isl_space_free(ma_space);
+	return -1;
+}
+
+/* Copy the divs from "ma" to "bmap", adding zeros for the "n_before"
+ * coefficients before the transformed range of dimensions,
+ * the "n_after" coefficients after the transformed range of dimensions
+ * and the coefficients of the other divs in "bmap".
+ */
+static int set_ma_divs(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div)
+{
+	int i;
+	int n_param;
+	int n_set;
+	isl_local_space *ls;
+
+	if (n_div == 0)
+		return 0;
+
+	ls = isl_aff_get_domain_local_space(ma->p[0]);
+	if (!ls)
+		return -1;
+
+	n_param = isl_local_space_dim(ls, isl_dim_param);
+	n_set = isl_local_space_dim(ls, isl_dim_set);
+	for (i = 0; i < n_div; ++i) {
+		int o_bmap = 0, o_ls = 0;
+
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], 1 + 1 + n_param);
+		o_bmap += 1 + 1 + n_param;
+		o_ls += 1 + 1 + n_param;
+		isl_seq_clr(bmap->div[i] + o_bmap, n_before);
+		o_bmap += n_before;
+		isl_seq_cpy(bmap->div[i] + o_bmap,
+			    ls->div->row[i] + o_ls, n_set);
+		o_bmap += n_set;
+		o_ls += n_set;
+		isl_seq_clr(bmap->div[i] + o_bmap, n_after);
+		o_bmap += n_after;
+		isl_seq_cpy(bmap->div[i] + o_bmap,
+			    ls->div->row[i] + o_ls, n_div);
+		o_bmap += n_div;
+		o_ls += n_div;
+		isl_seq_clr(bmap->div[i] + o_bmap, bmap->n_div - n_div);
+		if (isl_basic_set_add_div_constraints(bmap, i) < 0)
+			goto error;
+	}
+
+	isl_local_space_free(ls);
+	return 0;
+error:
+	isl_local_space_free(ls);
+	return -1;
+}
+
+/* How many stride constraints does "ma" enforce?
+ * That is, how many of the affine expressions have a denominator
+ * different from one?
+ */
+static int multi_aff_strides(__isl_keep isl_multi_aff *ma)
+{
+	int i;
+	int strides = 0;
+
+	for (i = 0; i < ma->n; ++i)
+		if (!isl_int_is_one(ma->p[i]->v->el[0]))
+			strides++;
+
+	return strides;
+}
+
+/* For each affine expression in ma of the form
+ *
+ *	x_i = (f_i y + h_i)/m_i
+ *
+ * with m_i different from one, add a constraint to "bmap"
+ * of the form
+ *
+ *	f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ */
+static __isl_give isl_basic_map *add_ma_strides(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma,
+	int n_before, int n_after)
+{
+	int i, k;
+	int div;
+	int total;
+	int n_param;
+	int n_in;
+	int n_div;
+
+	total = isl_basic_map_total_dim(bmap);
+	n_param = isl_multi_aff_dim(ma, isl_dim_param);
+	n_in = isl_multi_aff_dim(ma, isl_dim_in);
+	n_div = isl_multi_aff_dim(ma, isl_dim_div);
+	for (i = 0; i < ma->n; ++i) {
+		int o_bmap = 0, o_ma = 1;
+
+		if (isl_int_is_one(ma->p[i]->v->el[0]))
+			continue;
+		div = isl_basic_map_alloc_div(bmap);
+		k = isl_basic_map_alloc_equality(bmap);
+		if (div < 0 || k < 0)
+			goto error;
+		isl_int_set_si(bmap->div[div][0], 0);
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, 1 + n_param);
+		o_bmap += 1 + n_param;
+		o_ma += 1 + n_param;
+		isl_seq_clr(bmap->eq[k] + o_bmap, n_before);
+		o_bmap += n_before;
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, n_in);
+		o_bmap += n_in;
+		o_ma += n_in;
+		isl_seq_clr(bmap->eq[k] + o_bmap, n_after);
+		o_bmap += n_after;
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, n_div);
+		o_bmap += n_div;
+		o_ma += n_div;
+		isl_seq_clr(bmap->eq[k] + o_bmap, 1 + total - o_bmap);
+		isl_int_neg(bmap->eq[k][1 + total], ma->p[i]->v->el[0]);
+		total++;
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Replace the domain or range space (depending on "type) of "space" by "set".
+ */
+static __isl_give isl_space *isl_space_set(__isl_take isl_space *space,
+	enum isl_dim_type type, __isl_take isl_space *set)
+{
+	if (type == isl_dim_in) {
+		space = isl_space_range(space);
+		space = isl_space_map_from_domain_and_range(set, space);
+	} else {
+		space = isl_space_domain(space);
+		space = isl_space_map_from_domain_and_range(space, set);
+	}
+
+	return space;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "bmap" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * If bmap is represented by
+ *
+ *	A(p) + S u + B x + T v + C(divs) >= 0,
+ *
+ * where u and x are input and output dimensions if type == isl_dim_out
+ * while x and v are input and output dimensions if type == isl_dim_in,
+ * and ma is represented by
+ *
+ *	x = D(p) + F(y) + G(divs')
+ *
+ * then the result is
+ *
+ *	A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0
+ *
+ * The divs in the input set are similarly adjusted.
+ * In particular
+ *
+ *	floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i)
+ *
+ * becomes
+ *
+ *	floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v +
+ *		B_i G(divs') + c_i(divs))/n_i)
+ *
+ * If bmap is not a rational map and if F(y) involves any denominators
+ *
+ *	x_i = (f_i y + h_i)/m_i
+ *
+ * then additional constraints are added to ensure that we only
+ * map back integer points.  That is we enforce
+ *
+ *	f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ *
+ * We first copy over the divs from "ma".
+ * Then we add the modified constraints and divs from "bmap".
+ * Finally, we add the stride constraints, if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_multi_aff(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	__isl_take isl_multi_aff *ma)
+{
+	int i, k;
+	isl_space *space;
+	isl_basic_map *res = NULL;
+	int n_before, n_after, n_div_bmap, n_div_ma;
+	isl_int f, c1, c2, g;
+	int rational, strides;
+
+	isl_int_init(f);
+	isl_int_init(c1);
+	isl_int_init(c2);
+	isl_int_init(g);
+
+	ma = isl_multi_aff_align_divs(ma);
+	if (!bmap || !ma)
+		goto error;
+	if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0)
+		goto error;
+
+	if (type == isl_dim_in) {
+		n_before = 0;
+		n_after = isl_basic_map_dim(bmap, isl_dim_out);
+	} else {
+		n_before = isl_basic_map_dim(bmap, isl_dim_in);
+		n_after = 0;
+	}
+	n_div_bmap = isl_basic_map_dim(bmap, isl_dim_div);
+	n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+	space = isl_multi_aff_get_domain_space(ma);
+	space = isl_space_set(isl_basic_map_get_space(bmap), type, space);
+	rational = isl_basic_map_is_rational(bmap);
+	strides = rational ? 0 : multi_aff_strides(ma);
+	res = isl_basic_map_alloc_space(space, n_div_ma + n_div_bmap + strides,
+			    bmap->n_eq + strides, bmap->n_ineq + 2 * n_div_ma);
+	if (rational)
+		res = isl_basic_map_set_rational(res);
+
+	for (i = 0; i < n_div_ma + n_div_bmap; ++i)
+		if (isl_basic_map_alloc_div(res) < 0)
+			goto error;
+
+	if (set_ma_divs(res, ma, n_before, n_after, n_div_ma) < 0)
+		goto error;
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		k = isl_basic_map_alloc_equality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_preimage(res->eq[k], bmap->eq[i], ma, n_before,
+				n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		k = isl_basic_map_alloc_inequality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_preimage(res->ineq[k], bmap->ineq[i], ma, n_before,
+				n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+	}
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0])) {
+			isl_int_set_si(res->div[n_div_ma + i][0], 0);
+			continue;
+		}
+		isl_seq_preimage(res->div[n_div_ma + i], bmap->div[i], ma,
+				    n_before, n_after, n_div_ma, n_div_bmap,
+				    f, c1, c2, g, 1);
+	}
+
+	if (strides)
+		res = add_ma_strides(res, ma, n_before, n_after);
+
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+	isl_basic_map_free(bmap);
+	isl_multi_aff_free(ma);
+	res = isl_basic_set_simplify(res);
+	return isl_basic_map_finalize(res);
+error:
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+	isl_basic_map_free(bmap);
+	isl_multi_aff_free(ma);
+	isl_basic_map_free(res);
+	return NULL;
+}
+
+/* Compute the preimage of "bset" under the function represented by "ma".
+ * In other words, plug in "ma" in "bset".  The result is a basic set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bset, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bmap, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bmap, isl_dim_out, ma);
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "map".
+ * Return -1 if anything is wrong.
+ */
+static int check_map_compatible_range_multi_aff(
+	__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	int m;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+	m = isl_space_tuple_is_equal(map->dim, type, ma_space, isl_dim_out);
+	isl_space_free(ma_space);
+	if (m >= 0 && !m)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"spaces don't match", return -1);
+	return m;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space;
+
+	map = isl_map_cow(map);
+	ma = isl_multi_aff_align_divs(ma);
+	if (!map || !ma)
+		goto error;
+	if (check_map_compatible_range_multi_aff(map, type, ma) < 0)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_preimage_multi_aff(map->p[i], type,
+							isl_multi_aff_copy(ma));
+		if (!map->p[i])
+			goto error;
+	}
+
+	space = isl_multi_aff_get_domain_space(ma);
+	space = isl_space_set(isl_map_get_space(map), type, space);
+
+	isl_space_free(map->dim);
+	map->dim = space;
+	if (!map->dim)
+		goto error;
+
+	isl_multi_aff_free(ma);
+	if (map->n > 1)
+		ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_SET_NORMALIZED);
+	return map;
+error:
+	isl_multi_aff_free(ma);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+	if (!map || !ma)
+		goto error;
+
+	if (isl_space_match(map->dim, isl_dim_param, ma->space, isl_dim_param))
+		return map_preimage_multi_aff(map, type, ma);
+
+	if (!isl_space_has_named_params(map->dim) ||
+	    !isl_space_has_named_params(ma->space))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_multi_aff_get_space(ma));
+	ma = isl_multi_aff_align_params(ma, isl_map_get_space(map));
+
+	return map_preimage_multi_aff(map, type, ma);
+error:
+	isl_multi_aff_free(ma);
+	return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "ma".
+ * In other words, plug in "ma" in "set".  The result is a set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(set, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(map, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(map, isl_dim_out, ma);
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ *
+ * The parameters of "map" and "pma" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_map_preimage_pw_multi_aff_aligned(
+	__isl_take isl_map *map, enum isl_dim_type type,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	isl_map *res;
+
+	if (!pma)
+		goto error;
+
+	if (pma->n == 0) {
+		isl_pw_multi_aff_free(pma);
+		res = isl_map_empty(isl_map_get_space(map));
+		isl_map_free(map);
+		return res;
+	}
+
+	res = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+					isl_multi_aff_copy(pma->p[0].maff));
+	if (type == isl_dim_in)
+		res = isl_map_intersect_domain(res,
+						isl_map_copy(pma->p[0].set));
+	else
+		res = isl_map_intersect_range(res,
+						isl_map_copy(pma->p[0].set));
+
+	for (i = 1; i < pma->n; ++i) {
+		isl_map *res_i;
+
+		res_i = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+					isl_multi_aff_copy(pma->p[i].maff));
+		if (type == isl_dim_in)
+			res_i = isl_map_intersect_domain(res_i,
+						isl_map_copy(pma->p[i].set));
+		else
+			res_i = isl_map_intersect_range(res_i,
+						isl_map_copy(pma->p[i].set));
+		res = isl_map_union(res, res_i);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_map_free(map);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_pw_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_pw_multi_aff *pma)
+{
+	if (!map || !pma)
+		goto error;
+
+	if (isl_space_match(map->dim, isl_dim_param, pma->dim, isl_dim_param))
+		return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+
+	if (!isl_space_has_named_params(map->dim) ||
+	    !isl_space_has_named_params(pma->dim))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_pw_multi_aff_get_space(pma));
+	pma = isl_pw_multi_aff_align_params(pma, isl_map_get_space(map));
+
+	return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+error:
+	isl_pw_multi_aff_free(pma);
+	return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "pma".
+ * In other words, plug in "pma" in "set".  The result is a set
+ * that lives in the domain space of "pma".
+ */
+__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(set, isl_dim_set, pma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the domain of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(map, isl_dim_in, pma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that range space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_range_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(map, isl_dim_out, pma);
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "mpa".
+ *
+ * If the map does not involve any constraints that refer to the
+ * dimensions of the substituted space, then the only possible
+ * effect of "mpa" on the map is to map the space to a different space.
+ * We create a separate isl_multi_aff to effectuate this change
+ * in order to avoid spurious splitting of the map along the pieces
+ * of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_multi_pw_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_pw_aff *mpa)
+{
+	int n;
+	isl_pw_multi_aff *pma;
+
+	if (!map || !mpa)
+		goto error;
+
+	n = isl_map_dim(map, type);
+	if (!isl_map_involves_dims(map, type, 0, n)) {
+		isl_space *space;
+		isl_multi_aff *ma;
+
+		space = isl_multi_pw_aff_get_space(mpa);
+		isl_multi_pw_aff_free(mpa);
+		ma = isl_multi_aff_zero(space);
+		return isl_map_preimage_multi_aff(map, type, ma);
+	}
+
+	pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
+	return isl_map_preimage_pw_multi_aff(map, type, pma);
+error:
+	isl_map_free(map);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff(
+	__isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_map_preimage_multi_pw_aff(map, isl_dim_in, mpa);
+}
+
+/* Compute the preimage of "set" by the function represented by "mpa".
+ * In other words, plug in "mpa" in "set".
+ */
+__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_map_preimage_multi_pw_aff(set, isl_dim_set, mpa);
+}

Added: polly/trunk/lib/External/isl/isl_map_lexopt_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_lexopt_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_lexopt_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_map_lexopt_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+/* Function for computing the lexicographic optimum of a map
+ * in the form of either an isl_map or an isl_pw_multi_aff.
+ */
+
+#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX
+#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX)
+
+/* Given a basic map "bmap", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first make sure the basic sets in dom are disjoint and then
+ * simply collect the results over each of the basic sets separately.
+ * We could probably improve the efficiency a bit by moving the union
+ * domain down into the parametric integer programming.
+ */
+static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	int i;
+	TYPE *res;
+
+	dom = isl_set_make_disjoint(dom);
+	if (!dom)
+		goto error;
+
+	if (isl_set_plain_is_empty(dom)) {
+		isl_space *space = isl_basic_map_get_space(bmap);
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		isl_basic_map_free(bmap);
+		return EMPTY(space);
+	}
+
+	res = SF(isl_basic_map_partial_lexopt,SUFFIX)(isl_basic_map_copy(bmap),
+			isl_basic_set_copy(dom->p[0]), empty, max);
+		
+	for (i = 1; i < dom->n; ++i) {
+		TYPE *res_i;
+		isl_set *empty_i;
+
+		res_i = SF(isl_basic_map_partial_lexopt,SUFFIX)(
+				isl_basic_map_copy(bmap),
+				isl_basic_set_copy(dom->p[i]), &empty_i, max);
+
+		res = ADD(res, res_i);
+		*empty = isl_set_union_disjoint(*empty, empty_i);
+	}
+
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return res;
+error:
+	*empty = NULL;
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give TYPE *SF(isl_map_partial_lexopt_aligned,SUFFIX)(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, int max);
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * Align parameters if needed and then call isl_map_partial_lexopt_aligned.
+ */
+static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	if (!map || !dom)
+		goto error;
+	if (isl_space_match(map->dim, isl_dim_param, dom->dim, isl_dim_param))
+		return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom,
+								empty, max);
+	if (!isl_space_has_named_params(map->dim) ||
+	    !isl_space_has_named_params(dom->dim))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_map_get_space(dom));
+	dom = isl_map_align_params(dom, isl_map_get_space(map));
+	return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom, empty, max);
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give TYPE *SF(isl_map_lexopt,SUFFIX)(__isl_take isl_map *map, int max)
+{
+	isl_set *dom = NULL;
+	isl_space *dom_space;
+
+	if (!map)
+		goto error;
+	dom_space = isl_space_domain(isl_space_copy(map->dim));
+	dom = isl_set_universe(dom_space);
+	return SF(isl_map_partial_lexopt,SUFFIX)(map, dom, NULL, max);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give TYPE *SF(isl_map_lexmin,SUFFIX)(__isl_take isl_map *map)
+{
+	return SF(isl_map_lexopt,SUFFIX)(map, 0);
+}
+
+__isl_give TYPE *SF(isl_map_lexmax,SUFFIX)(__isl_take isl_map *map)
+{
+	return SF(isl_map_lexopt,SUFFIX)(map, 1);
+}
+
+__isl_give TYPE *SF(isl_set_lexmin,SUFFIX)(__isl_take isl_set *set)
+{
+	return SF(isl_map_lexmin,SUFFIX)(set);
+}
+
+__isl_give TYPE *SF(isl_set_lexmax,SUFFIX)(__isl_take isl_set *set)
+{
+	return SF(isl_map_lexmax,SUFFIX)(set);
+}

Added: polly/trunk/lib/External/isl/isl_map_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_private.h (added)
+++ polly/trunk/lib/External/isl/isl_map_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_MAP_PRIVATE_H
+#define ISL_MAP_PRIVATE_H
+
+#define isl_basic_set	isl_basic_map
+#define isl_set		isl_map
+#define isl_basic_set_list	isl_basic_map_list
+#define isl_set_list	isl_map_list
+#include <isl/list.h>
+ISL_DECLARE_LIST(basic_map)
+ISL_DECLARE_LIST(map)
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include <isl/vec.h>
+#include <isl_blk.h>
+
+/* A "basic map" is a relation between two sets of variables,
+ * called the "in" and "out" variables.
+ * A "basic set" is a basic map with a zero-dimensional
+ * domain.
+ *
+ * It is implemented as a set with two extra fields:
+ * n_in is the number of in variables
+ * n_out is the number of out variables
+ * n_in + n_out should be equal to set.dim
+ */
+struct isl_basic_map {
+	int ref;
+#define ISL_BASIC_MAP_FINAL		(1 << 0)
+#define ISL_BASIC_MAP_EMPTY		(1 << 1)
+#define ISL_BASIC_MAP_NO_IMPLICIT	(1 << 2)
+#define ISL_BASIC_MAP_NO_REDUNDANT	(1 << 3)
+#define ISL_BASIC_MAP_RATIONAL		(1 << 4)
+#define ISL_BASIC_MAP_NORMALIZED	(1 << 5)
+#define ISL_BASIC_MAP_NORMALIZED_DIVS	(1 << 6)
+#define ISL_BASIC_MAP_ALL_EQUALITIES	(1 << 7)
+#define ISL_BASIC_SET_FINAL		(1 << 0)
+#define ISL_BASIC_SET_EMPTY		(1 << 1)
+#define ISL_BASIC_SET_NO_IMPLICIT	(1 << 2)
+#define ISL_BASIC_SET_NO_REDUNDANT	(1 << 3)
+#define ISL_BASIC_SET_RATIONAL		(1 << 4)
+#define ISL_BASIC_SET_NORMALIZED	(1 << 5)
+#define ISL_BASIC_SET_NORMALIZED_DIVS	(1 << 6)
+#define ISL_BASIC_SET_ALL_EQUALITIES	(1 << 7)
+	unsigned flags;
+
+	struct isl_ctx *ctx;
+
+	isl_space *dim;
+	unsigned extra;
+
+	unsigned n_eq;
+	unsigned n_ineq;
+
+	size_t c_size;
+	isl_int **eq;
+	isl_int **ineq;
+
+	unsigned n_div;
+
+	isl_int **div;
+
+	struct isl_vec *sample;
+
+	struct isl_blk block;
+	struct isl_blk block2;
+};
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+/* A "map" is a (possibly disjoint) union of basic maps.
+ * A "set" is a (possibly disjoint) union of basic sets.
+ *
+ * Currently, the isl_set structure is identical to the isl_map structure
+ * and the library depends on this correspondence internally.
+ * However, users should not depend on this correspondence.
+ */
+struct isl_map {
+	int ref;
+#define ISL_MAP_DISJOINT		(1 << 0)
+#define ISL_MAP_NORMALIZED		(1 << 1)
+#define ISL_SET_DISJOINT		(1 << 0)
+#define ISL_SET_NORMALIZED		(1 << 1)
+	unsigned flags;
+
+	struct isl_ctx *ctx;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_basic_map *p[1];
+};
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+	__isl_take isl_reordering *r);
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+	__isl_take isl_reordering *r);
+
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+	enum isl_dim_type type);
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *dim);
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+	__isl_take isl_space *dim);
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+					enum isl_dim_type type);
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+					enum isl_dim_type type);
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap);
+int isl_map_may_be_set(__isl_keep isl_map *map);
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set);
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset);
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset);
+
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+		struct isl_basic_set *bset2, unsigned pos);
+
+struct isl_map *isl_map_grow(struct isl_map *map, int n);
+struct isl_set *isl_set_grow(struct isl_set *set, int n);
+
+int isl_basic_set_contains(struct isl_basic_set *bset, struct isl_vec *vec);
+int isl_basic_map_contains(struct isl_basic_map *bmap, struct isl_vec *vec);
+
+__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags);
+__isl_give isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags);
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap);
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap);
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset);
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_set_alloc_inequality(struct isl_basic_set *bset);
+int isl_basic_map_alloc_inequality(struct isl_basic_map *bmap);
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap);
+int isl_basic_set_alloc_div(struct isl_basic_set *bset);
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n);
+void isl_basic_map_inequality_to_equality(
+		struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_set_drop_equality(struct isl_basic_set *bset, unsigned pos);
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos);
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos);
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+	isl_int *eq);
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+	isl_int *eq);
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+	isl_int *ineq);
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+	isl_int *ineq);
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos);
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap);
+struct isl_set *isl_set_cow(struct isl_set *set);
+struct isl_map *isl_map_cow(struct isl_map *map);
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset);
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b);
+struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap);
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map);
+struct isl_basic_map *isl_basic_map_align_divs(
+		struct isl_basic_map *dst, struct isl_basic_map *src);
+struct isl_basic_set *isl_basic_set_align_divs(
+		struct isl_basic_set *dst, struct isl_basic_set *src);
+__isl_give isl_set *isl_set_align_divs_to_basic_set_list(
+	__isl_take isl_set *set, __isl_keep isl_basic_set_list *list);
+__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set(
+	__isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map);
+struct isl_basic_map *isl_basic_map_gauss(
+	struct isl_basic_map *bmap, int *progress);
+struct isl_basic_set *isl_basic_set_gauss(
+	struct isl_basic_set *bset, int *progress);
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+	__isl_take isl_basic_set *bset);
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+	const __isl_keep isl_basic_map *bmap2);
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2);
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+	struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+	struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_implicit_equalities(
+						struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_map_underlying_set(struct isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+		__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set(
+	__isl_take isl_basic_set_list *list);
+struct isl_set *isl_map_underlying_set(struct isl_map *map);
+struct isl_basic_map *isl_basic_map_overlying_set(struct isl_basic_set *bset,
+	struct isl_basic_map *like);
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving(
+	__isl_take isl_basic_set *bset, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_set *isl_set_drop(struct isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_basic_set *isl_basic_set_drop_dims(
+		struct isl_basic_set *bset, unsigned first, unsigned n);
+struct isl_set *isl_set_drop_dims(
+		struct isl_set *set, unsigned first, unsigned n);
+struct isl_map *isl_map_drop_inputs(
+		struct isl_map *map, unsigned first, unsigned n);
+struct isl_map *isl_map_drop(struct isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+	__isl_take isl_basic_map *bmap, int *progress, int detect_divs);
+
+struct isl_map *isl_map_remove_empty_parts(struct isl_map *map);
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set);
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map);
+
+struct isl_set *isl_set_normalize(struct isl_set *set);
+
+struct isl_set *isl_set_drop_vars(
+		struct isl_set *set, unsigned first, unsigned n);
+
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+	struct isl_basic_map *bmap, unsigned pos, unsigned n);
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+	struct isl_basic_set *bset, unsigned pos, unsigned n);
+
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d);
+
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned div, int sign);
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div);
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+	__isl_take isl_basic_map *bmap);
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+	struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+	struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_recession_cone(struct isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_set_rational(struct isl_basic_set *bset);
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set);
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map);
+
+int isl_map_has_rational(__isl_keep isl_map *map);
+int isl_set_has_rational(__isl_keep isl_set *set);
+
+struct isl_mat;
+
+struct isl_basic_set *isl_basic_set_preimage(struct isl_basic_set *bset,
+	struct isl_mat *mat);
+struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat);
+
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+	__isl_take isl_mat *trans);
+
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+	isl_int *facet, isl_int *ridge);
+
+int isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_point *point);
+int isl_set_contains_point(__isl_keep isl_set *set, __isl_keep isl_point *point);
+
+int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n, int *signs);
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user);
+
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div);
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+	unsigned pos, isl_int *div);
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div);
+int isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+	isl_int *constraint, unsigned div);
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+	__isl_take isl_local_space *ls);
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+	__isl_take isl_local_space *ls);
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp);
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap);
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset);
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+	__isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap));
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+	__isl_take isl_map *map1, __isl_take isl_map *map2,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+				    __isl_take isl_map *map2));
+int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2,
+	int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2));
+
+int isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+	int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+		  void *user),
+	void *user);
+int isl_basic_set_foreach_lexopt(__isl_keep isl_basic_set *bset, int max,
+	int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+		  void *user),
+	void *user);
+
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context);
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set);
+
+int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap);
+
+int isl_map_is_set(__isl_keep isl_map *map);
+
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+	unsigned dim, isl_int *val);
+
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue);
+int isl_set_dim_residue_class(struct isl_set *set,
+	int pos, isl_int *modulo, isl_int *residue);
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+int isl_map_plain_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val);
+
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+	int pos);
+
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+	__isl_keep isl_set *set);
+
+__isl_give isl_map *isl_map_fixed_power(__isl_take isl_map *map, isl_int exp);
+
+int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
+	isl_int max, isl_int *count);
+int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_map_simplify.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_simplify.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_simplify.c (added)
+++ polly/trunk/lib/External/isl/isl_map_simplify.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,3257 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <strings.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include "isl_equalities.h"
+#include <isl/map.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+static void swap_equality(struct isl_basic_map *bmap, int a, int b)
+{
+	isl_int *t = bmap->eq[a];
+	bmap->eq[a] = bmap->eq[b];
+	bmap->eq[b] = t;
+}
+
+static void swap_inequality(struct isl_basic_map *bmap, int a, int b)
+{
+	if (a != b) {
+		isl_int *t = bmap->ineq[a];
+		bmap->ineq[a] = bmap->ineq[b];
+		bmap->ineq[b] = t;
+	}
+}
+
+static void constraint_drop_vars(isl_int *c, unsigned n, unsigned rem)
+{
+	isl_seq_cpy(c, c + n, rem);
+	isl_seq_clr(c + rem, n);
+}
+
+/* Drop n dimensions starting at first.
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+struct isl_basic_set *isl_basic_set_drop_dims(
+		struct isl_basic_set *bset, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!bset)
+		goto error;
+
+	isl_assert(bset->ctx, first + n <= bset->dim->n_out, goto error);
+
+	if (n == 0 && !isl_space_get_tuple_name(bset->dim, isl_dim_set))
+		return bset;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	for (i = 0; i < bset->n_eq; ++i)
+		constraint_drop_vars(bset->eq[i]+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	for (i = 0; i < bset->n_ineq; ++i)
+		constraint_drop_vars(bset->ineq[i]+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	for (i = 0; i < bset->n_div; ++i)
+		constraint_drop_vars(bset->div[i]+1+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	bset->dim = isl_space_drop_outputs(bset->dim, first, n);
+	if (!bset->dim)
+		goto error;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop_dims(
+		struct isl_set *set, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!set)
+		goto error;
+
+	isl_assert(set->ctx, first + n <= set->dim->n_out, goto error);
+
+	if (n == 0 && !isl_space_get_tuple_name(set->dim, isl_dim_set))
+		return set;
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+	set->dim = isl_space_drop_outputs(set->dim, first, n);
+	if (!set->dim)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_drop_dims(set->p[i], first, n);
+		if (!set->p[i])
+			goto error;
+	}
+
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Move "n" divs starting at "first" to the end of the list of divs.
+ */
+static struct isl_basic_map *move_divs_last(struct isl_basic_map *bmap,
+	unsigned first, unsigned n)
+{
+	isl_int **div;
+	int i;
+
+	if (first + n == bmap->n_div)
+		return bmap;
+
+	div = isl_alloc_array(bmap->ctx, isl_int *, n);
+	if (!div)
+		goto error;
+	for (i = 0; i < n; ++i)
+		div[i] = bmap->div[first + i];
+	for (i = 0; i < bmap->n_div - first - n; ++i)
+		bmap->div[first + i] = bmap->div[first + n + i];
+	for (i = 0; i < n; ++i)
+		bmap->div[bmap->n_div - n + i] = div[i];
+	free(div);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Drop "n" dimensions of type "type" starting at "first".
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	unsigned dim;
+	unsigned offset;
+	unsigned left;
+
+	if (!bmap)
+		goto error;
+
+	dim = isl_basic_map_dim(bmap, type);
+	isl_assert(bmap->ctx, first + n <= dim, goto error);
+
+	if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	offset = isl_basic_map_offset(bmap, type) + first;
+	left = isl_basic_map_total_dim(bmap) - (offset - 1) - n;
+	for (i = 0; i < bmap->n_eq; ++i)
+		constraint_drop_vars(bmap->eq[i]+offset, n, left);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		constraint_drop_vars(bmap->ineq[i]+offset, n, left);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		constraint_drop_vars(bmap->div[i]+1+offset, n, left);
+
+	if (type == isl_dim_div) {
+		bmap = move_divs_last(bmap, first, n);
+		if (!bmap)
+			goto error;
+		isl_basic_map_free_div(bmap, n);
+	} else
+		bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+	if (!bmap->dim)
+		goto error;
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_basic_set *)isl_basic_map_drop((isl_basic_map *)bset,
+							type, first, n);
+}
+
+struct isl_basic_map *isl_basic_map_drop_inputs(
+		struct isl_basic_map *bmap, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop(bmap, isl_dim_in, first, n);
+}
+
+struct isl_map *isl_map_drop(struct isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		goto error;
+
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+	if (n == 0 && !isl_space_get_tuple_name(map->dim, type))
+		return map;
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+	map->dim = isl_space_drop_dims(map->dim, type, first, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_drop(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop(struct isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_drop((isl_map *)set, type, first, n);
+}
+
+struct isl_map *isl_map_drop_inputs(
+		struct isl_map *map, unsigned first, unsigned n)
+{
+	return isl_map_drop(map, isl_dim_in, first, n);
+}
+
+/*
+ * We don't cow, as the div is assumed to be redundant.
+ */
+static struct isl_basic_map *isl_basic_map_drop_div(
+		struct isl_basic_map *bmap, unsigned div)
+{
+	int i;
+	unsigned pos;
+
+	if (!bmap)
+		goto error;
+
+	pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	isl_assert(bmap->ctx, div < bmap->n_div, goto error);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		constraint_drop_vars(bmap->eq[i]+pos, 1, bmap->extra-div-1);
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (!isl_int_is_zero(bmap->ineq[i][pos])) {
+			isl_basic_map_drop_inequality(bmap, i);
+			--i;
+			continue;
+		}
+		constraint_drop_vars(bmap->ineq[i]+pos, 1, bmap->extra-div-1);
+	}
+
+	for (i = 0; i < bmap->n_div; ++i)
+		constraint_drop_vars(bmap->div[i]+1+pos, 1, bmap->extra-div-1);
+
+	if (div != bmap->n_div - 1) {
+		int j;
+		isl_int *t = bmap->div[div];
+
+		for (j = div; j < bmap->n_div - 1; ++j)
+			bmap->div[j] = bmap->div[j+1];
+
+		bmap->div[bmap->n_div - 1] = t;
+	}
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	isl_basic_map_free_div(bmap, 1);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+	struct isl_basic_map *bmap)
+{
+	int i;
+	isl_int gcd;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	isl_int_init(gcd);
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		isl_seq_gcd(bmap->eq[i]+1, total, &gcd);
+		if (isl_int_is_zero(gcd)) {
+			if (!isl_int_is_zero(bmap->eq[i][0])) {
+				bmap = isl_basic_map_set_to_empty(bmap);
+				break;
+			}
+			isl_basic_map_drop_equality(bmap, i);
+			continue;
+		}
+		if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+			isl_int_gcd(gcd, gcd, bmap->eq[i][0]);
+		if (isl_int_is_one(gcd))
+			continue;
+		if (!isl_int_is_divisible_by(bmap->eq[i][0], gcd)) {
+			bmap = isl_basic_map_set_to_empty(bmap);
+			break;
+		}
+		isl_seq_scale_down(bmap->eq[i], bmap->eq[i], gcd, 1+total);
+	}
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		isl_seq_gcd(bmap->ineq[i]+1, total, &gcd);
+		if (isl_int_is_zero(gcd)) {
+			if (isl_int_is_neg(bmap->ineq[i][0])) {
+				bmap = isl_basic_map_set_to_empty(bmap);
+				break;
+			}
+			isl_basic_map_drop_inequality(bmap, i);
+			continue;
+		}
+		if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+			isl_int_gcd(gcd, gcd, bmap->ineq[i][0]);
+		if (isl_int_is_one(gcd))
+			continue;
+		isl_int_fdiv_q(bmap->ineq[i][0], bmap->ineq[i][0], gcd);
+		isl_seq_scale_down(bmap->ineq[i]+1, bmap->ineq[i]+1, gcd, total);
+	}
+	isl_int_clear(gcd);
+
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+	struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_normalize_constraints(
+		(struct isl_basic_map *)bset);
+}
+
+/* Remove any common factor in numerator and denominator of the div expression,
+ * not taking into account the constant term.
+ * That is, if the div is of the form
+ *
+ *	floor((a + m f(x))/(m d))
+ *
+ * then replace it by
+ *
+ *	floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static void normalize_div_expression(__isl_keep isl_basic_map *bmap, int div)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	isl_ctx *ctx = bmap->ctx;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return;
+	isl_seq_gcd(bmap->div[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, bmap->div[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+	isl_int_fdiv_q(bmap->div[div][1], bmap->div[div][1],
+			ctx->normalize_gcd);
+	isl_int_divexact(bmap->div[div][0], bmap->div[div][0],
+			ctx->normalize_gcd);
+	isl_seq_scale_down(bmap->div[div] + 2, bmap->div[div] + 2,
+			ctx->normalize_gcd, total);
+}
+
+/* Remove any common factor in numerator and denominator of a div expression,
+ * not taking into account the constant term.
+ * That is, look for any div of the form
+ *
+ *	floor((a + m f(x))/(m d))
+ *
+ * and replace it by
+ *
+ *	floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static __isl_give isl_basic_map *normalize_div_expressions(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_div == 0)
+		return bmap;
+
+	for (i = 0; i < bmap->n_div; ++i)
+		normalize_div_expression(bmap, i);
+
+	return bmap;
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static void eliminate_var_using_equality(struct isl_basic_map *bmap,
+	unsigned pos, isl_int *eq, int keep_divs, int *progress)
+{
+	unsigned total;
+	unsigned space_total;
+	int k;
+	int last_div;
+
+	total = isl_basic_map_total_dim(bmap);
+	space_total = isl_space_dim(bmap->dim, isl_dim_all);
+	last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+	for (k = 0; k < bmap->n_eq; ++k) {
+		if (bmap->eq[k] == eq)
+			continue;
+		if (isl_int_is_zero(bmap->eq[k][1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL);
+		isl_seq_normalize(bmap->ctx, bmap->eq[k], 1 + total);
+	}
+
+	for (k = 0; k < bmap->n_ineq; ++k) {
+		if (isl_int_is_zero(bmap->ineq[k][1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL);
+		isl_seq_normalize(bmap->ctx, bmap->ineq[k], 1 + total);
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+
+	for (k = 0; k < bmap->n_div; ++k) {
+		if (isl_int_is_zero(bmap->div[k][0]))
+			continue;
+		if (isl_int_is_zero(bmap->div[k][1+1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		/* We need to be careful about circular definitions,
+		 * so for now we just remove the definition of div k
+		 * if the equality contains any divs.
+		 * If keep_divs is set, then the divs have been ordered
+		 * and we can keep the definition as long as the result
+		 * is still ordered.
+		 */
+		if (last_div == -1 || (keep_divs && last_div < k)) {
+			isl_seq_elim(bmap->div[k]+1, eq,
+					1+pos, 1+total, &bmap->div[k][0]);
+			normalize_div_expression(bmap, k);
+		} else
+			isl_seq_clr(bmap->div[k], 1 + total);
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static void eliminate_div(struct isl_basic_map *bmap, isl_int *eq,
+	unsigned div, int keep_divs)
+{
+	unsigned pos = isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	eliminate_var_using_equality(bmap, pos, eq, keep_divs, NULL);
+
+	isl_basic_map_drop_div(bmap, div);
+}
+
+/* Check if elimination of div "div" using equality "eq" would not
+ * result in a div depending on a later div.
+ */
+static int ok_to_eliminate_div(struct isl_basic_map *bmap, isl_int *eq,
+	unsigned div)
+{
+	int k;
+	int last_div;
+	unsigned space_total = isl_space_dim(bmap->dim, isl_dim_all);
+	unsigned pos = space_total + div;
+
+	last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+	if (last_div < 0 || last_div <= div)
+		return 1;
+
+	for (k = 0; k <= last_div; ++k) {
+		if (isl_int_is_zero(bmap->div[k][0]))
+			return 1;
+		if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Elimininate divs based on equalities
+ */
+static struct isl_basic_map *eliminate_divs_eq(
+		struct isl_basic_map *bmap, int *progress)
+{
+	int d;
+	int i;
+	int modified = 0;
+	unsigned off;
+
+	bmap = isl_basic_map_order_divs(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (d = bmap->n_div - 1; d >= 0 ; --d) {
+		for (i = 0; i < bmap->n_eq; ++i) {
+			if (!isl_int_is_one(bmap->eq[i][off + d]) &&
+			    !isl_int_is_negone(bmap->eq[i][off + d]))
+				continue;
+			if (!ok_to_eliminate_div(bmap, bmap->eq[i], d))
+				continue;
+			modified = 1;
+			*progress = 1;
+			eliminate_div(bmap, bmap->eq[i], d, 1);
+			isl_basic_map_drop_equality(bmap, i);
+			break;
+		}
+	}
+	if (modified)
+		return eliminate_divs_eq(bmap, progress);
+	return bmap;
+}
+
+/* Elimininate divs based on inequalities
+ */
+static struct isl_basic_map *eliminate_divs_ineq(
+		struct isl_basic_map *bmap, int *progress)
+{
+	int d;
+	int i;
+	unsigned off;
+	struct isl_ctx *ctx;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = bmap->ctx;
+	off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (d = bmap->n_div - 1; d >= 0 ; --d) {
+		for (i = 0; i < bmap->n_eq; ++i)
+			if (!isl_int_is_zero(bmap->eq[i][off + d]))
+				break;
+		if (i < bmap->n_eq)
+			continue;
+		for (i = 0; i < bmap->n_ineq; ++i)
+			if (isl_int_abs_gt(bmap->ineq[i][off + d], ctx->one))
+				break;
+		if (i < bmap->n_ineq)
+			continue;
+		*progress = 1;
+		bmap = isl_basic_map_eliminate_vars(bmap, (off-1)+d, 1);
+		if (!bmap || ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+			break;
+		bmap = isl_basic_map_drop_div(bmap, d);
+		if (!bmap)
+			break;
+	}
+	return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_gauss(
+	struct isl_basic_map *bmap, int *progress)
+{
+	int k;
+	int done;
+	int last_var;
+	unsigned total_var;
+	unsigned total;
+
+	bmap = isl_basic_map_order_divs(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	total = isl_basic_map_total_dim(bmap);
+	total_var = total - bmap->n_div;
+
+	last_var = total - 1;
+	for (done = 0; done < bmap->n_eq; ++done) {
+		for (; last_var >= 0; --last_var) {
+			for (k = done; k < bmap->n_eq; ++k)
+				if (!isl_int_is_zero(bmap->eq[k][1+last_var]))
+					break;
+			if (k < bmap->n_eq)
+				break;
+		}
+		if (last_var < 0)
+			break;
+		if (k != done)
+			swap_equality(bmap, k, done);
+		if (isl_int_is_neg(bmap->eq[done][1+last_var]))
+			isl_seq_neg(bmap->eq[done], bmap->eq[done], 1+total);
+
+		eliminate_var_using_equality(bmap, last_var, bmap->eq[done], 1,
+						progress);
+
+		if (last_var >= total_var &&
+		    isl_int_is_zero(bmap->div[last_var - total_var][0])) {
+			unsigned div = last_var - total_var;
+			isl_seq_neg(bmap->div[div]+1, bmap->eq[done], 1+total);
+			isl_int_set_si(bmap->div[div][1+1+last_var], 0);
+			isl_int_set(bmap->div[div][0],
+				    bmap->eq[done][1+last_var]);
+			if (progress)
+				*progress = 1;
+			ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+		}
+	}
+	if (done == bmap->n_eq)
+		return bmap;
+	for (k = done; k < bmap->n_eq; ++k) {
+		if (isl_int_is_zero(bmap->eq[k][0]))
+			continue;
+		return isl_basic_map_set_to_empty(bmap);
+	}
+	isl_basic_map_free_equality(bmap, bmap->n_eq-done);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_gauss(
+	struct isl_basic_set *bset, int *progress)
+{
+	return (struct isl_basic_set*)isl_basic_map_gauss(
+			(struct isl_basic_map *)bset, progress);
+}
+
+
+static unsigned int round_up(unsigned int v)
+{
+	int old_v = v;
+
+	while (v) {
+		old_v = v;
+		v ^= v & -v;
+	}
+	return old_v << 1;
+}
+
+static int hash_index(isl_int ***index, unsigned int size, int bits,
+			struct isl_basic_map *bmap, int k)
+{
+	int h;
+	unsigned total = isl_basic_map_total_dim(bmap);
+	uint32_t hash = isl_seq_get_hash_bits(bmap->ineq[k]+1, total, bits);
+	for (h = hash; index[h]; h = (h+1) % size)
+		if (&bmap->ineq[k] != index[h] &&
+		    isl_seq_eq(bmap->ineq[k]+1, index[h][0]+1, total))
+			break;
+	return h;
+}
+
+static int set_hash_index(isl_int ***index, unsigned int size, int bits,
+			  struct isl_basic_set *bset, int k)
+{
+	return hash_index(index, size, bits, (struct isl_basic_map *)bset, k);
+}
+
+/* If we can eliminate more than one div, then we need to make
+ * sure we do it from last div to first div, in order not to
+ * change the position of the other divs that still need to
+ * be removed.
+ */
+static struct isl_basic_map *remove_duplicate_divs(
+	struct isl_basic_map *bmap, int *progress)
+{
+	unsigned int size;
+	int *index;
+	int *elim_for;
+	int k, l, h;
+	int bits;
+	struct isl_blk eq;
+	unsigned total_var;
+	unsigned total;
+	struct isl_ctx *ctx;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	if (!bmap || bmap->n_div <= 1)
+		return bmap;
+
+	total_var = isl_space_dim(bmap->dim, isl_dim_all);
+	total = total_var + bmap->n_div;
+
+	ctx = bmap->ctx;
+	for (k = bmap->n_div - 1; k >= 0; --k)
+		if (!isl_int_is_zero(bmap->div[k][0]))
+			break;
+	if (k <= 0)
+		return bmap;
+
+	elim_for = isl_calloc_array(ctx, int, bmap->n_div);
+	size = round_up(4 * bmap->n_div / 3 - 1);
+	bits = ffs(size) - 1;
+	index = isl_calloc_array(ctx, int, size);
+	if (!index)
+		return bmap;
+	eq = isl_blk_alloc(ctx, 1+total);
+	if (isl_blk_is_error(eq))
+		goto out;
+
+	isl_seq_clr(eq.data, 1+total);
+	index[isl_seq_get_hash_bits(bmap->div[k], 2+total, bits)] = k + 1;
+	for (--k; k >= 0; --k) {
+		uint32_t hash;
+
+		if (isl_int_is_zero(bmap->div[k][0]))
+			continue;
+
+		hash = isl_seq_get_hash_bits(bmap->div[k], 2+total, bits);
+		for (h = hash; index[h]; h = (h+1) % size)
+			if (isl_seq_eq(bmap->div[k],
+				       bmap->div[index[h]-1], 2+total))
+				break;
+		if (index[h]) {
+			*progress = 1;
+			l = index[h] - 1;
+			elim_for[l] = k + 1;
+		}
+		index[h] = k+1;
+	}
+	for (l = bmap->n_div - 1; l >= 0; --l) {
+		if (!elim_for[l])
+			continue;
+		k = elim_for[l] - 1;
+		isl_int_set_si(eq.data[1+total_var+k], -1);
+		isl_int_set_si(eq.data[1+total_var+l], 1);
+		eliminate_div(bmap, eq.data, l, 1);
+		isl_int_set_si(eq.data[1+total_var+k], 0);
+		isl_int_set_si(eq.data[1+total_var+l], 0);
+	}
+
+	isl_blk_free(ctx, eq);
+out:
+	free(index);
+	free(elim_for);
+	return bmap;
+}
+
+static int n_pure_div_eq(struct isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) {
+		while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+			--j;
+		if (j < 0)
+			break;
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1)
+			return 0;
+	}
+	return i;
+}
+
+/* Normalize divs that appear in equalities.
+ *
+ * In particular, we assume that bmap contains some equalities
+ * of the form
+ *
+ *	a x = m * e_i
+ *
+ * and we want to replace the set of e_i by a minimal set and
+ * such that the new e_i have a canonical representation in terms
+ * of the vector x.
+ * If any of the equalities involves more than one divs, then
+ * we currently simply bail out.
+ *
+ * Let us first additionally assume that all equalities involve
+ * a div.  The equalities then express modulo constraints on the
+ * remaining variables and we can use "parameter compression"
+ * to find a minimal set of constraints.  The result is a transformation
+ *
+ *	x = T(x') = x_0 + G x'
+ *
+ * with G a lower-triangular matrix with all elements below the diagonal
+ * non-negative and smaller than the diagonal element on the same row.
+ * We first normalize x_0 by making the same property hold in the affine
+ * T matrix.
+ * The rows i of G with a 1 on the diagonal do not impose any modulo
+ * constraint and simply express x_i = x'_i.
+ * For each of the remaining rows i, we introduce a div and a corresponding
+ * equality.  In particular
+ *
+ *	g_ii e_j = x_i - g_i(x')
+ *
+ * where each x'_k is replaced either by x_k (if g_kk = 1) or the
+ * corresponding div (if g_kk != 1).
+ *
+ * If there are any equalities not involving any div, then we
+ * first apply a variable compression on the variables x:
+ *
+ *	x = C x''	x'' = C_2 x
+ *
+ * and perform the above parameter compression on A C instead of on A.
+ * The resulting compression is then of the form
+ *
+ *	x'' = T(x') = x_0 + G x'
+ *
+ * and in constructing the new divs and the corresponding equalities,
+ * we have to replace each x'', i.e., the x'_k with (g_kk = 1),
+ * by the corresponding row from C_2.
+ */
+static struct isl_basic_map *normalize_divs(
+	struct isl_basic_map *bmap, int *progress)
+{
+	int i, j, k;
+	int total;
+	int div_eq;
+	struct isl_mat *B;
+	struct isl_vec *d;
+	struct isl_mat *T = NULL;
+	struct isl_mat *C = NULL;
+	struct isl_mat *C2 = NULL;
+	isl_int v;
+	int *pos;
+	int dropped, needed;
+
+	if (!bmap)
+		return NULL;
+
+	if (bmap->n_div == 0)
+		return bmap;
+
+	if (bmap->n_eq == 0)
+		return bmap;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS))
+		return bmap;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	div_eq = n_pure_div_eq(bmap);
+	if (div_eq == 0)
+		return bmap;
+
+	if (div_eq < bmap->n_eq) {
+		B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, div_eq,
+					bmap->n_eq - div_eq, 0, 1 + total);
+		C = isl_mat_variable_compression(B, &C2);
+		if (!C || !C2)
+			goto error;
+		if (C->n_col == 0) {
+			bmap = isl_basic_map_set_to_empty(bmap);
+			isl_mat_free(C);
+			isl_mat_free(C2);
+			goto done;
+		}
+	}
+
+	d = isl_vec_alloc(bmap->ctx, div_eq);
+	if (!d)
+		goto error;
+	for (i = 0, j = bmap->n_div-1; i < div_eq; ++i) {
+		while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+			--j;
+		isl_int_set(d->block.data[i], bmap->eq[i][1 + total + j]);
+	}
+	B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total);
+
+	if (C) {
+		B = isl_mat_product(B, C);
+		C = NULL;
+	}
+
+	T = isl_mat_parameter_compression(B, d);
+	if (!T)
+		goto error;
+	if (T->n_col == 0) {
+		bmap = isl_basic_map_set_to_empty(bmap);
+		isl_mat_free(C2);
+		isl_mat_free(T);
+		goto done;
+	}
+	isl_int_init(v);
+	for (i = 0; i < T->n_row - 1; ++i) {
+		isl_int_fdiv_q(v, T->row[1 + i][0], T->row[1 + i][1 + i]);
+		if (isl_int_is_zero(v))
+			continue;
+		isl_mat_col_submul(T, 0, v, 1 + i);
+	}
+	isl_int_clear(v);
+	pos = isl_alloc_array(bmap->ctx, int, T->n_row);
+	if (!pos)
+		goto error;
+	/* We have to be careful because dropping equalities may reorder them */
+	dropped = 0;
+	for (j = bmap->n_div - 1; j >= 0; --j) {
+		for (i = 0; i < bmap->n_eq; ++i)
+			if (!isl_int_is_zero(bmap->eq[i][1 + total + j]))
+				break;
+		if (i < bmap->n_eq) {
+			bmap = isl_basic_map_drop_div(bmap, j);
+			isl_basic_map_drop_equality(bmap, i);
+			++dropped;
+		}
+	}
+	pos[0] = 0;
+	needed = 0;
+	for (i = 1; i < T->n_row; ++i) {
+		if (isl_int_is_one(T->row[i][i]))
+			pos[i] = i;
+		else
+			needed++;
+	}
+	if (needed > dropped) {
+		bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+				needed, needed, 0);
+		if (!bmap)
+			goto error;
+	}
+	for (i = 1; i < T->n_row; ++i) {
+		if (isl_int_is_one(T->row[i][i]))
+			continue;
+		k = isl_basic_map_alloc_div(bmap);
+		pos[i] = 1 + total + k;
+		isl_seq_clr(bmap->div[k] + 1, 1 + total + bmap->n_div);
+		isl_int_set(bmap->div[k][0], T->row[i][i]);
+		if (C2)
+			isl_seq_cpy(bmap->div[k] + 1, C2->row[i], 1 + total);
+		else
+			isl_int_set_si(bmap->div[k][1 + i], 1);
+		for (j = 0; j < i; ++j) {
+			if (isl_int_is_zero(T->row[i][j]))
+				continue;
+			if (pos[j] < T->n_row && C2)
+				isl_seq_submul(bmap->div[k] + 1, T->row[i][j],
+						C2->row[pos[j]], 1 + total);
+			else
+				isl_int_neg(bmap->div[k][1 + pos[j]],
+								T->row[i][j]);
+		}
+		j = isl_basic_map_alloc_equality(bmap);
+		isl_seq_neg(bmap->eq[j], bmap->div[k]+1, 1+total+bmap->n_div);
+		isl_int_set(bmap->eq[j][pos[i]], bmap->div[k][0]);
+	}
+	free(pos);
+	isl_mat_free(C2);
+	isl_mat_free(T);
+
+	if (progress)
+		*progress = 1;
+done:
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+
+	return bmap;
+error:
+	isl_mat_free(C);
+	isl_mat_free(C2);
+	isl_mat_free(T);
+	return bmap;
+}
+
+static struct isl_basic_map *set_div_from_lower_bound(
+	struct isl_basic_map *bmap, int div, int ineq)
+{
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div);
+	isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]);
+	isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]);
+	isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+	isl_int_set_si(bmap->div[div][1 + total + div], 0);
+
+	return bmap;
+}
+
+/* Check whether it is ok to define a div based on an inequality.
+ * To avoid the introduction of circular definitions of divs, we
+ * do not allow such a definition if the resulting expression would refer to
+ * any other undefined divs or if any known div is defined in
+ * terms of the unknown div.
+ */
+static int ok_to_set_div_from_bound(struct isl_basic_map *bmap,
+	int div, int ineq)
+{
+	int j;
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	/* Not defined in terms of unknown divs */
+	for (j = 0; j < bmap->n_div; ++j) {
+		if (div == j)
+			continue;
+		if (isl_int_is_zero(bmap->ineq[ineq][total + j]))
+			continue;
+		if (isl_int_is_zero(bmap->div[j][0]))
+			return 0;
+	}
+
+	/* No other div defined in terms of this one => avoid loops */
+	for (j = 0; j < bmap->n_div; ++j) {
+		if (div == j)
+			continue;
+		if (isl_int_is_zero(bmap->div[j][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[j][1 + total + div]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Would an expression for div "div" based on inequality "ineq" of "bmap"
+ * be a better expression than the current one?
+ *
+ * If we do not have any expression yet, then any expression would be better.
+ * Otherwise we check if the last variable involved in the inequality
+ * (disregarding the div that it would define) is in an earlier position
+ * than the last variable involved in the current div expression.
+ */
+static int better_div_constraint(__isl_keep isl_basic_map *bmap,
+	int div, int ineq)
+{
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+	int last_div;
+	int last_ineq;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return 1;
+
+	if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1,
+				  bmap->n_div - (div + 1)) >= 0)
+		return 0;
+
+	last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div);
+	last_div = isl_seq_last_non_zero(bmap->div[div] + 1,
+					 total + bmap->n_div);
+
+	return last_ineq < last_div;
+}
+
+/* Given two constraints "k" and "l" that are opposite to each other,
+ * except for the constant term, check if we can use them
+ * to obtain an expression for one of the hitherto unknown divs or
+ * a "better" expression for a div for which we already have an expression.
+ * "sum" is the sum of the constant terms of the constraints.
+ * If this sum is strictly smaller than the coefficient of one
+ * of the divs, then this pair can be used define the div.
+ * 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
+ * terms of the unknown div.
+ */
+static struct isl_basic_map *check_for_div_constraints(
+	struct isl_basic_map *bmap, int k, int l, isl_int sum, int *progress)
+{
+	int i;
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->ineq[k][total + i]))
+			continue;
+		if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
+			continue;
+		if (!better_div_constraint(bmap, i, k))
+			continue;
+		if (!ok_to_set_div_from_bound(bmap, i, k))
+			break;
+		if (isl_int_is_pos(bmap->ineq[k][total + i]))
+			bmap = set_div_from_lower_bound(bmap, i, k);
+		else
+			bmap = set_div_from_lower_bound(bmap, i, l);
+		if (progress)
+			*progress = 1;
+		break;
+	}
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+	__isl_take isl_basic_map *bmap, int *progress, int detect_divs)
+{
+	unsigned int size;
+	isl_int ***index;
+	int k, l, h;
+	int bits;
+	unsigned total = isl_basic_map_total_dim(bmap);
+	isl_int sum;
+	isl_ctx *ctx;
+
+	if (!bmap || bmap->n_ineq <= 1)
+		return bmap;
+
+	size = round_up(4 * (bmap->n_ineq+1) / 3 - 1);
+	bits = ffs(size) - 1;
+	ctx = isl_basic_map_get_ctx(bmap);
+	index = isl_calloc_array(ctx, isl_int **, size);
+	if (!index)
+		return bmap;
+
+	index[isl_seq_get_hash_bits(bmap->ineq[0]+1, total, bits)] = &bmap->ineq[0];
+	for (k = 1; k < bmap->n_ineq; ++k) {
+		h = hash_index(index, size, bits, bmap, k);
+		if (!index[h]) {
+			index[h] = &bmap->ineq[k];
+			continue;
+		}
+		if (progress)
+			*progress = 1;
+		l = index[h] - &bmap->ineq[0];
+		if (isl_int_lt(bmap->ineq[k][0], bmap->ineq[l][0]))
+			swap_inequality(bmap, k, l);
+		isl_basic_map_drop_inequality(bmap, k);
+		--k;
+	}
+	isl_int_init(sum);
+	for (k = 0; k < bmap->n_ineq-1; ++k) {
+		isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+		h = hash_index(index, size, bits, bmap, k);
+		isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+		if (!index[h])
+			continue;
+		l = index[h] - &bmap->ineq[0];
+		isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]);
+		if (isl_int_is_pos(sum)) {
+			if (detect_divs)
+				bmap = check_for_div_constraints(bmap, k, l,
+								 sum, progress);
+			continue;
+		}
+		if (isl_int_is_zero(sum)) {
+			/* We need to break out of the loop after these
+			 * changes since the contents of the hash
+			 * will no longer be valid.
+			 * Plus, we probably we want to regauss first.
+			 */
+			if (progress)
+				*progress = 1;
+			isl_basic_map_drop_inequality(bmap, l);
+			isl_basic_map_inequality_to_equality(bmap, k);
+		} else
+			bmap = isl_basic_map_set_to_empty(bmap);
+		break;
+	}
+	isl_int_clear(sum);
+
+	free(index);
+	return bmap;
+}
+
+
+/* Eliminate knowns divs from constraints where they appear with
+ * a (positive or negative) unit coefficient.
+ *
+ * That is, replace
+ *
+ *	floor(e/m) + f >= 0
+ *
+ * by
+ *
+ *	e + m f >= 0
+ *
+ * and
+ *
+ *	-floor(e/m) + f >= 0
+ *
+ * by
+ *
+ *	-e + m f + m - 1 >= 0
+ *
+ * The first conversion is valid because floor(e/m) >= -f is equivalent
+ * to e/m >= -f because -f is an integral expression.
+ * The second conversion follows from the fact that
+ *
+ *	-floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m)
+ *
+ *
+ * Note that one of the div constraints may have been eliminated
+ * due to being redundant with respect to the constraint that is
+ * being modified by this function.  The modified constraint may
+ * no longer imply this div constraint, so we add it back to make
+ * sure we do not lose any information.
+ *
+ * We skip integral divs, i.e., those with denominator 1, as we would
+ * risk eliminating the div from the div constraints.  We do not need
+ * to handle those divs here anyway since the div constraints will turn
+ * out to form an equality and this equality can then be use to eliminate
+ * the div from all constraints.
+ */
+static __isl_give isl_basic_map *eliminate_unit_divs(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	int i, j;
+	isl_ctx *ctx;
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_int_is_one(bmap->div[i][0]))
+			continue;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			int s;
+
+			if (!isl_int_is_one(bmap->ineq[j][total + i]) &&
+			    !isl_int_is_negone(bmap->ineq[j][total + i]))
+				continue;
+
+			*progress = 1;
+
+			s = isl_int_sgn(bmap->ineq[j][total + i]);
+			isl_int_set_si(bmap->ineq[j][total + i], 0);
+			if (s < 0)
+				isl_seq_combine(bmap->ineq[j],
+					ctx->negone, bmap->div[i] + 1,
+					bmap->div[i][0], bmap->ineq[j],
+					total + bmap->n_div);
+			else
+				isl_seq_combine(bmap->ineq[j],
+					ctx->one, bmap->div[i] + 1,
+					bmap->div[i][0], bmap->ineq[j],
+					total + bmap->n_div);
+			if (s < 0) {
+				isl_int_add(bmap->ineq[j][0],
+					bmap->ineq[j][0], bmap->div[i][0]);
+				isl_int_sub_ui(bmap->ineq[j][0],
+					bmap->ineq[j][0], 1);
+			}
+
+			bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+			if (isl_basic_map_add_div_constraint(bmap, i, s) < 0)
+				return isl_basic_map_free(bmap);
+		}
+	}
+
+	return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap)
+{
+	int progress = 1;
+	if (!bmap)
+		return NULL;
+	while (progress) {
+		progress = 0;
+		if (!bmap)
+			break;
+		if (isl_basic_map_plain_is_empty(bmap))
+			break;
+		bmap = isl_basic_map_normalize_constraints(bmap);
+		bmap = normalize_div_expressions(bmap);
+		bmap = remove_duplicate_divs(bmap, &progress);
+		bmap = eliminate_unit_divs(bmap, &progress);
+		bmap = eliminate_divs_eq(bmap, &progress);
+		bmap = eliminate_divs_ineq(bmap, &progress);
+		bmap = isl_basic_map_gauss(bmap, &progress);
+		/* requires equalities in normal form */
+		bmap = normalize_divs(bmap, &progress);
+		bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+								&progress, 1);
+	}
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_simplify((struct isl_basic_map *)bset);
+}
+
+
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!bmap)
+		return -1;
+
+	pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	if (isl_int_eq(constraint[pos], bmap->div[div][0])) {
+		int neg;
+		isl_int_sub(bmap->div[div][1],
+				bmap->div[div][1], bmap->div[div][0]);
+		isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1);
+		neg = isl_seq_is_neg(constraint, bmap->div[div]+1, pos);
+		isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+		isl_int_add(bmap->div[div][1],
+				bmap->div[div][1], bmap->div[div][0]);
+		if (!neg)
+			return 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return 0;
+	} else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) {
+		if (!isl_seq_eq(constraint, bmap->div[div]+1, pos))
+			return 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return 0;
+	} else
+		return 0;
+
+	return 1;
+}
+
+int isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+	isl_int *constraint, unsigned div)
+{
+	return isl_basic_map_is_div_constraint(bset, constraint, div);
+}
+
+
+/* If the only constraints a div d=floor(f/m)
+ * appears in are its two defining constraints
+ *
+ *	f - m d >=0
+ *	-(f - (m - 1)) + m d >= 0
+ *
+ * then it can safely be removed.
+ */
+static int div_is_redundant(struct isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][pos]))
+			return 0;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_int_is_zero(bmap->ineq[i][pos]))
+			continue;
+		if (!isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div))
+			return 0;
+	}
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1+pos]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Remove divs that don't occur in any of the constraints or other divs.
+ * These can arise when dropping constraints from a basic map or
+ * when the divs of a basic map have been temporarily aligned
+ * with the divs of another basic map.
+ */
+static struct isl_basic_map *remove_redundant_divs(struct isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_div-1; i >= 0; --i) {
+		if (!div_is_redundant(bmap, i))
+			continue;
+		bmap = isl_basic_map_drop_div(bmap, i);
+	}
+	return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_finalize(struct isl_basic_map *bmap)
+{
+	bmap = remove_redundant_divs(bmap);
+	if (!bmap)
+		return NULL;
+	ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_finalize(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_finalize((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_finalize(struct isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_finalize(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_map *isl_map_finalize(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_finalize(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+
+/* Remove definition of any div that is defined in terms of the given variable.
+ * The div itself is not removed.  Functions such as
+ * eliminate_divs_ineq depend on the other divs remaining in place.
+ */
+static struct isl_basic_map *remove_dependent_vars(struct isl_basic_map *bmap,
+									int pos)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_int_is_zero(bmap->div[i][1+1+pos]))
+			continue;
+		isl_int_set_si(bmap->div[i][0], 0);
+	}
+	return bmap;
+}
+
+/* Eliminate the specified variables from the constraints using
+ * Fourier-Motzkin.  The variables themselves are not removed.
+ */
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+	struct isl_basic_map *bmap, unsigned pos, unsigned n)
+{
+	int d;
+	int i, j, k;
+	unsigned total;
+	int need_gauss = 0;
+
+	if (n == 0)
+		return bmap;
+	if (!bmap)
+		return NULL;
+	total = isl_basic_map_total_dim(bmap);
+
+	bmap = isl_basic_map_cow(bmap);
+	for (d = pos + n - 1; d >= 0 && d >= pos; --d)
+		bmap = remove_dependent_vars(bmap, d);
+	if (!bmap)
+		return NULL;
+
+	for (d = pos + n - 1;
+	     d >= 0 && d >= total - bmap->n_div && d >= pos; --d)
+		isl_seq_clr(bmap->div[d-(total-bmap->n_div)], 2+total);
+	for (d = pos + n - 1; d >= 0 && d >= pos; --d) {
+		int n_lower, n_upper;
+		if (!bmap)
+			return NULL;
+		for (i = 0; i < bmap->n_eq; ++i) {
+			if (isl_int_is_zero(bmap->eq[i][1+d]))
+				continue;
+			eliminate_var_using_equality(bmap, d, bmap->eq[i], 0, NULL);
+			isl_basic_map_drop_equality(bmap, i);
+			need_gauss = 1;
+			break;
+		}
+		if (i < bmap->n_eq)
+			continue;
+		n_lower = 0;
+		n_upper = 0;
+		for (i = 0; i < bmap->n_ineq; ++i) {
+			if (isl_int_is_pos(bmap->ineq[i][1+d]))
+				n_lower++;
+			else if (isl_int_is_neg(bmap->ineq[i][1+d]))
+				n_upper++;
+		}
+		bmap = isl_basic_map_extend_constraints(bmap,
+				0, n_lower * n_upper);
+		if (!bmap)
+			goto error;
+		for (i = bmap->n_ineq - 1; i >= 0; --i) {
+			int last;
+			if (isl_int_is_zero(bmap->ineq[i][1+d]))
+				continue;
+			last = -1;
+			for (j = 0; j < i; ++j) {
+				if (isl_int_is_zero(bmap->ineq[j][1+d]))
+					continue;
+				last = j;
+				if (isl_int_sgn(bmap->ineq[i][1+d]) ==
+				    isl_int_sgn(bmap->ineq[j][1+d]))
+					continue;
+				k = isl_basic_map_alloc_inequality(bmap);
+				if (k < 0)
+					goto error;
+				isl_seq_cpy(bmap->ineq[k], bmap->ineq[i],
+						1+total);
+				isl_seq_elim(bmap->ineq[k], bmap->ineq[j],
+						1+d, 1+total, NULL);
+			}
+			isl_basic_map_drop_inequality(bmap, i);
+			i = last + 1;
+		}
+		if (n_lower > 0 && n_upper > 0) {
+			bmap = isl_basic_map_normalize_constraints(bmap);
+			bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+								    NULL, 0);
+			bmap = isl_basic_map_gauss(bmap, NULL);
+			bmap = isl_basic_map_remove_redundancies(bmap);
+			need_gauss = 0;
+			if (!bmap)
+				goto error;
+			if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+				break;
+		}
+	}
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	if (need_gauss)
+		bmap = isl_basic_map_gauss(bmap, NULL);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+	struct isl_basic_set *bset, unsigned pos, unsigned n)
+{
+	return (struct isl_basic_set *)isl_basic_map_eliminate_vars(
+			(struct isl_basic_map *)bset, pos, n);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ * Otherwise, they are projected out and the original space is restored.
+ */
+__isl_give isl_basic_map *isl_basic_map_eliminate(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_space *space;
+
+	if (!bmap)
+		return NULL;
+	if (n == 0)
+		return bmap;
+
+	if (first + n > isl_basic_map_dim(bmap, type) || first + n < first)
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+		first += isl_basic_map_offset(bmap, type) - 1;
+		bmap = isl_basic_map_eliminate_vars(bmap, first, n);
+		return isl_basic_map_finalize(bmap);
+	}
+
+	space = isl_basic_map_get_space(bmap);
+	bmap = isl_basic_map_project_out(bmap, type, first, n);
+	bmap = isl_basic_map_insert_dims(bmap, type, first, n);
+	bmap = isl_basic_map_reset_space(bmap, space);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_eliminate(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_eliminate(bset, type, first, n);
+}
+
+/* Don't assume equalities are in order, because align_divs
+ * may have changed the order of the divs.
+ */
+static void compute_elimination_index(struct isl_basic_map *bmap, int *elim)
+{
+	int d, i;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (d = 0; d < total; ++d)
+		elim[d] = -1;
+	for (i = 0; i < bmap->n_eq; ++i) {
+		for (d = total - 1; d >= 0; --d) {
+			if (isl_int_is_zero(bmap->eq[i][1+d]))
+				continue;
+			elim[d] = i;
+			break;
+		}
+	}
+}
+
+static void set_compute_elimination_index(struct isl_basic_set *bset, int *elim)
+{
+	compute_elimination_index((struct isl_basic_map *)bset, elim);
+}
+
+static int reduced_using_equalities(isl_int *dst, isl_int *src,
+	struct isl_basic_map *bmap, int *elim)
+{
+	int d;
+	int copied = 0;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (d = total - 1; d >= 0; --d) {
+		if (isl_int_is_zero(src[1+d]))
+			continue;
+		if (elim[d] == -1)
+			continue;
+		if (!copied) {
+			isl_seq_cpy(dst, src, 1 + total);
+			copied = 1;
+		}
+		isl_seq_elim(dst, bmap->eq[elim[d]], 1 + d, 1 + total, NULL);
+	}
+	return copied;
+}
+
+static int set_reduced_using_equalities(isl_int *dst, isl_int *src,
+	struct isl_basic_set *bset, int *elim)
+{
+	return reduced_using_equalities(dst, src,
+					(struct isl_basic_map *)bset, elim);
+}
+
+static struct isl_basic_set *isl_basic_set_reduce_using_equalities(
+	struct isl_basic_set *bset, struct isl_basic_set *context)
+{
+	int i;
+	int *elim;
+
+	if (!bset || !context)
+		goto error;
+
+	if (context->n_eq == 0) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+
+	elim = isl_alloc_array(bset->ctx, int, isl_basic_set_n_dim(bset));
+	if (!elim)
+		goto error;
+	set_compute_elimination_index(context, elim);
+	for (i = 0; i < bset->n_eq; ++i)
+		set_reduced_using_equalities(bset->eq[i], bset->eq[i],
+							context, elim);
+	for (i = 0; i < bset->n_ineq; ++i)
+		set_reduced_using_equalities(bset->ineq[i], bset->ineq[i],
+							context, elim);
+	isl_basic_set_free(context);
+	free(elim);
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(context);
+	return NULL;
+}
+
+static struct isl_basic_set *remove_shifted_constraints(
+	struct isl_basic_set *bset, struct isl_basic_set *context)
+{
+	unsigned int size;
+	isl_int ***index;
+	int bits;
+	int k, h, l;
+	isl_ctx *ctx;
+
+	if (!bset)
+		return NULL;
+
+	size = round_up(4 * (context->n_ineq+1) / 3 - 1);
+	bits = ffs(size) - 1;
+	ctx = isl_basic_set_get_ctx(bset);
+	index = isl_calloc_array(ctx, isl_int **, size);
+	if (!index)
+		return bset;
+
+	for (k = 0; k < context->n_ineq; ++k) {
+		h = set_hash_index(index, size, bits, context, k);
+		index[h] = &context->ineq[k];
+	}
+	for (k = 0; k < bset->n_ineq; ++k) {
+		h = set_hash_index(index, size, bits, bset, k);
+		if (!index[h])
+			continue;
+		l = index[h] - &context->ineq[0];
+		if (isl_int_lt(bset->ineq[k][0], context->ineq[l][0]))
+			continue;
+		bset = isl_basic_set_cow(bset);
+		if (!bset)
+			goto error;
+		isl_basic_set_drop_inequality(bset, k);
+		--k;
+	}
+	free(index);
+	return bset;
+error:
+	free(index);
+	return bset;
+}
+
+/* Remove constraints from "bmap" that are identical to constraints
+ * in "context" or that are more relaxed (greater constant term).
+ *
+ * We perform the test for shifted copies on the pure constraints
+ * in remove_shifted_constraints.
+ */
+static __isl_give isl_basic_map *isl_basic_map_remove_shifted_constraints(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context)
+{
+	isl_basic_set *bset, *bset_context;
+
+	if (!bmap || !context)
+		goto error;
+
+	if (bmap->n_ineq == 0 || context->n_ineq == 0) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+
+	context = isl_basic_map_align_divs(context, bmap);
+	bmap = isl_basic_map_align_divs(bmap, context);
+
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	bset_context = isl_basic_map_underlying_set(context);
+	bset = remove_shifted_constraints(bset, bset_context);
+	isl_basic_set_free(bset_context);
+
+	bmap = isl_basic_map_overlying_set(bset, bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Does the (linear part of a) constraint "c" involve any of the "len"
+ * "relevant" dimensions?
+ */
+static int is_related(isl_int *c, int len, int *relevant)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (!relevant[i])
+			continue;
+		if (!isl_int_is_zero(c[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Drop constraints from "bset" that do not involve any of
+ * the dimensions marked "relevant".
+ */
+static __isl_give isl_basic_set *drop_unrelated_constraints(
+	__isl_take isl_basic_set *bset, int *relevant)
+{
+	int i, dim;
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < dim; ++i)
+		if (!relevant[i])
+			break;
+	if (i >= dim)
+		return bset;
+
+	for (i = bset->n_eq - 1; i >= 0; --i)
+		if (!is_related(bset->eq[i] + 1, dim, relevant))
+			isl_basic_set_drop_equality(bset, i);
+
+	for (i = bset->n_ineq - 1; i >= 0; --i)
+		if (!is_related(bset->ineq[i] + 1, dim, relevant))
+			isl_basic_set_drop_inequality(bset, i);
+
+	return bset;
+}
+
+/* Update the groups in "group" based on the (linear part of a) constraint "c".
+ *
+ * In particular, for any variable involved in the constraint,
+ * find the actual group id from before and replace the group
+ * of the corresponding variable by the minimal group of all
+ * the variables involved in the constraint considered so far
+ * (if this minimum is smaller) or replace the minimum by this group
+ * (if the minimum is larger).
+ *
+ * At the end, all the variables in "c" will (indirectly) point
+ * to the minimal of the groups that they referred to originally.
+ */
+static void update_groups(int dim, int *group, isl_int *c)
+{
+	int j;
+	int min = dim;
+
+	for (j = 0; j < dim; ++j) {
+		if (isl_int_is_zero(c[j]))
+			continue;
+		while (group[j] >= 0 && group[group[j]] != group[j])
+			group[j] = group[group[j]];
+		if (group[j] == min)
+			continue;
+		if (group[j] < min) {
+			if (min >= 0 && min < dim)
+				group[min] = group[j];
+			min = group[j];
+		} else
+			group[group[j]] = min;
+	}
+}
+
+/* Drop constraints from "context" that are irrelevant for computing
+ * the gist of "bset".
+ *
+ * In particular, drop constraints in variables that are not related
+ * to any of the variables involved in the constraints of "bset"
+ * in the sense that there is no sequence of constraints that connects them.
+ *
+ * We construct groups of variables that collect variables that
+ * (indirectly) appear in some common constraint of "context".
+ * Each group is identified by the first variable in the group,
+ * except for the special group of variables that appear in "bset"
+ * (or are related to those variables), which is identified by -1.
+ * If group[i] is equal to i (or -1), then the group of i is i (or -1),
+ * otherwise the group of i is the group of group[i].
+ *
+ * We first initialize the -1 group with the variables that appear in "bset".
+ * Then we initialize groups for the remaining variables.
+ * Then we iterate over the constraints of "context" and update the
+ * group of the variables in the constraint by the smallest group.
+ * Finally, we resolve indirect references to groups by running over
+ * the variables.
+ *
+ * After computing the groups, we drop constraints that do not involve
+ * any variables in the -1 group.
+ */
+static __isl_give isl_basic_set *drop_irrelevant_constraints(
+	__isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset)
+{
+	isl_ctx *ctx;
+	int *group;
+	int dim;
+	int i, j;
+	int last;
+
+	if (!context || !bset)
+		return isl_basic_set_free(context);
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	ctx = isl_basic_set_get_ctx(bset);
+	group = isl_calloc_array(ctx, int, dim);
+
+	if (!group)
+		goto error;
+
+	for (i = 0; i < dim; ++i) {
+		for (j = 0; j < bset->n_eq; ++j)
+			if (!isl_int_is_zero(bset->eq[j][1 + i]))
+				break;
+		if (j < bset->n_eq) {
+			group[i] = -1;
+			continue;
+		}
+		for (j = 0; j < bset->n_ineq; ++j)
+			if (!isl_int_is_zero(bset->ineq[j][1 + i]))
+				break;
+		if (j < bset->n_ineq)
+			group[i] = -1;
+	}
+
+	last = -1;
+	for (i = 0; i < dim; ++i)
+		if (group[i] >= 0)
+			last = group[i] = i;
+	if (last < 0) {
+		free(group);
+		return context;
+	}
+
+	for (i = 0; i < context->n_eq; ++i)
+		update_groups(dim, group, context->eq[i] + 1);
+	for (i = 0; i < context->n_ineq; ++i)
+		update_groups(dim, group, context->ineq[i] + 1);
+
+	for (i = 0; i < dim; ++i)
+		if (group[i] >= 0)
+			group[i] = group[group[i]];
+
+	for (i = 0; i < dim; ++i)
+		group[i] = group[i] == -1;
+
+	context = drop_unrelated_constraints(context, group);
+
+	free(group);
+	return context;
+error:
+	free(group);
+	return isl_basic_set_free(context);
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context.  Both bset and context are assumed to be full-dimensional.
+ *
+ * We first remove the inequalities from "bset"
+ * that are obviously redundant with respect to some inequality in "context".
+ * Then we remove those constraints from "context" that have become
+ * irrelevant for computing the gist of "bset".
+ * Note that this removal of constraints cannot be replaced by
+ * a factorization because factors in "bset" may still be connected
+ * to each other through constraints in "context".
+ *
+ * If there are any inequalities left, we construct a tableau for
+ * the context and then add the inequalities of "bset".
+ * Before adding these inequalities, we freeze all constraints such that
+ * they won't be considered redundant in terms of the constraints of "bset".
+ * Then we detect all redundant constraints (among the
+ * constraints that weren't frozen), first by checking for redundancy in the
+ * the tableau and then by checking if replacing a constraint by its negation
+ * would lead to an empty set.  This last step is fairly expensive
+ * and could be optimized by more reuse of the tableau.
+ * Finally, we update bset according to the results.
+ */
+static __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset,
+	__isl_take isl_basic_set *context)
+{
+	int i, k;
+	isl_basic_set *combined = NULL;
+	struct isl_tab *tab = NULL;
+	unsigned context_ineq;
+	unsigned total;
+
+	if (!bset || !context)
+		goto error;
+
+	if (isl_basic_set_is_universe(bset)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	if (isl_basic_set_is_universe(context)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	bset = remove_shifted_constraints(bset, context);
+	if (!bset)
+		goto error;
+	if (bset->n_ineq == 0)
+		goto done;
+
+	context = drop_irrelevant_constraints(context, bset);
+	if (!context)
+		goto error;
+	if (isl_basic_set_is_universe(context)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	context_ineq = context->n_ineq;
+	combined = isl_basic_set_cow(isl_basic_set_copy(context));
+	combined = isl_basic_set_extend_constraints(combined, 0, bset->n_ineq);
+	tab = isl_tab_from_basic_set(combined, 0);
+	for (i = 0; i < context_ineq; ++i)
+		if (isl_tab_freeze_constraint(tab, i) < 0)
+			goto error;
+	if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i)
+		if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0)
+			goto error;
+	bset = isl_basic_set_add_constraints(combined, bset, 0);
+	combined = NULL;
+	if (!bset)
+		goto error;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	total = isl_basic_set_total_dim(bset);
+	for (i = context_ineq; i < bset->n_ineq; ++i) {
+		int is_empty;
+		if (tab->con[i].is_redundant)
+			continue;
+		tab->con[i].is_redundant = 1;
+		combined = isl_basic_set_dup(bset);
+		combined = isl_basic_set_update_from_tab(combined, tab);
+		combined = isl_basic_set_extend_constraints(combined, 0, 1);
+		k = isl_basic_set_alloc_inequality(combined);
+		if (k < 0)
+			goto error;
+		isl_seq_neg(combined->ineq[k], bset->ineq[i], 1 + total);
+		isl_int_sub_ui(combined->ineq[k][0], combined->ineq[k][0], 1);
+		is_empty = isl_basic_set_is_empty(combined);
+		if (is_empty < 0)
+			goto error;
+		isl_basic_set_free(combined);
+		combined = NULL;
+		if (!is_empty)
+			tab->con[i].is_redundant = 0;
+	}
+	for (i = 0; i < context_ineq; ++i)
+		tab->con[i].is_redundant = 1;
+	bset = isl_basic_set_update_from_tab(bset, tab);
+	if (bset) {
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	}
+
+	isl_tab_free(tab);
+done:
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	isl_basic_set_free(context);
+	return bset;
+error:
+	isl_tab_free(tab);
+	isl_basic_set_free(combined);
+	isl_basic_set_free(context);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context.  In particular, equalities that are linear combinations
+ * of those in context are removed.  Then the inequalities that are
+ * redundant in the context of the equalities and inequalities of
+ * context are removed.
+ *
+ * First of all, we drop those constraints from "context"
+ * that are irrelevant for computing the gist of "bset".
+ * Alternatively, we could factorize the intersection of "context" and "bset".
+ *
+ * We first compute the integer affine hull of the intersection,
+ * compute the gist inside this affine hull and then add back
+ * those equalities that are not implied by the context.
+ *
+ * If two constraints are mutually redundant, then uset_gist_full
+ * will remove the second of those constraints.  We therefore first
+ * sort the constraints so that constraints not involving existentially
+ * quantified variables are given precedence over those that do.
+ * We have to perform this sorting before the variable compression,
+ * because that may effect the order of the variables.
+ */
+static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
+	__isl_take isl_basic_set *context)
+{
+	isl_mat *eq;
+	isl_mat *T, *T2;
+	isl_basic_set *aff;
+	isl_basic_set *aff_context;
+	unsigned total;
+
+	if (!bset || !context)
+		goto error;
+
+	context = drop_irrelevant_constraints(context, bset);
+
+	aff = isl_basic_set_copy(bset);
+	aff = isl_basic_set_intersect(aff, isl_basic_set_copy(context));
+	aff = isl_basic_set_affine_hull(aff);
+	if (!aff)
+		goto error;
+	if (isl_basic_set_plain_is_empty(aff)) {
+		isl_basic_set_free(bset);
+		isl_basic_set_free(context);
+		return aff;
+	}
+	bset = isl_basic_set_sort_constraints(bset);
+	if (aff->n_eq == 0) {
+		isl_basic_set_free(aff);
+		return uset_gist_full(bset, context);
+	}
+	total = isl_basic_set_total_dim(bset);
+	eq = isl_mat_sub_alloc6(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total);
+	eq = isl_mat_cow(eq);
+	T = isl_mat_variable_compression(eq, &T2);
+	if (T && T->n_col == 0) {
+		isl_mat_free(T);
+		isl_mat_free(T2);
+		isl_basic_set_free(context);
+		isl_basic_set_free(aff);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context));
+
+	bset = isl_basic_set_preimage(bset, isl_mat_copy(T));
+	context = isl_basic_set_preimage(context, T);
+
+	bset = uset_gist_full(bset, context);
+	bset = isl_basic_set_preimage(bset, T2);
+	bset = isl_basic_set_intersect(bset, aff);
+	bset = isl_basic_set_reduce_using_equalities(bset, aff_context);
+
+	if (bset) {
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	}
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(context);
+	return NULL;
+}
+
+/* Normalize the divs in "bmap" in the context of the equalities in "context".
+ * We simply add the equalities in context to bmap and then do a regular
+ * div normalizations.  Better results can be obtained by normalizing
+ * only the divs in bmap than do not also appear in context.
+ * We need to be careful to reduce the divs using the equalities
+ * so that later calls to isl_basic_map_overlying_set wouldn't introduce
+ * spurious constraints.
+ */
+static struct isl_basic_map *normalize_divs_in_context(
+	struct isl_basic_map *bmap, struct isl_basic_map *context)
+{
+	int i;
+	unsigned total_context;
+	int div_eq;
+
+	div_eq = n_pure_div_eq(bmap);
+	if (div_eq == 0)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (context->n_div > 0)
+		bmap = isl_basic_map_align_divs(bmap, context);
+
+	total_context = isl_basic_map_total_dim(context);
+	bmap = isl_basic_map_extend_constraints(bmap, context->n_eq, 0);
+	for (i = 0; i < context->n_eq; ++i) {
+		int k;
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			return isl_basic_map_free(bmap);
+		isl_seq_cpy(bmap->eq[k], context->eq[i], 1 + total_context);
+		isl_seq_clr(bmap->eq[k] + 1 + total_context,
+				isl_basic_map_total_dim(bmap) - total_context);
+	}
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = normalize_divs(bmap, NULL);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return bmap;
+}
+
+/* Return a basic map that has the same intersection with "context" as "bmap"
+ * and that is as "simple" as possible.
+ *
+ * The core computation is performed on the pure constraints.
+ * When we add back the meaning of the integer divisions, we need
+ * to (re)introduce the div constraints.  If we happen to have
+ * discovered that some of these integer divisions are equal to
+ * some affine combination of other variables, then these div
+ * constraints may end up getting simplified in terms of the equalities,
+ * resulting in extra inequalities on the other variables that
+ * may have been removed already or that may not even have been
+ * part of the input.  We try and remove those constraints of
+ * this form that are most obviously redundant with respect to
+ * the context.  We also remove those div constraints that are
+ * redundant with respect to the other constraints in the result.
+ */
+struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap,
+	struct isl_basic_map *context)
+{
+	isl_basic_set *bset, *eq;
+	isl_basic_map *eq_bmap;
+	unsigned n_div, n_eq, n_ineq;
+
+	if (!bmap || !context)
+		goto error;
+
+	if (isl_basic_map_is_universe(bmap)) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+	if (isl_basic_map_plain_is_empty(context)) {
+		isl_space *space = isl_basic_map_get_space(bmap);
+		isl_basic_map_free(bmap);
+		isl_basic_map_free(context);
+		return isl_basic_map_universe(space);
+	}
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+
+	bmap = isl_basic_map_remove_redundancies(bmap);
+	context = isl_basic_map_remove_redundancies(context);
+	if (!context)
+		goto error;
+
+	if (context->n_eq)
+		bmap = normalize_divs_in_context(bmap, context);
+
+	context = isl_basic_map_align_divs(context, bmap);
+	bmap = isl_basic_map_align_divs(bmap, context);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+
+	bset = uset_gist(isl_basic_map_underlying_set(isl_basic_map_copy(bmap)),
+		    isl_basic_map_underlying_set(isl_basic_map_copy(context)));
+
+	if (!bset || bset->n_eq == 0 || n_div == 0 ||
+	    isl_basic_set_plain_is_empty(bset)) {
+		isl_basic_map_free(context);
+		return isl_basic_map_overlying_set(bset, bmap);
+	}
+
+	n_eq = bset->n_eq;
+	n_ineq = bset->n_ineq;
+	eq = isl_basic_set_copy(bset);
+	eq = isl_basic_set_cow(bset);
+	if (isl_basic_set_free_inequality(eq, n_ineq) < 0)
+		eq = isl_basic_set_free(eq);
+	if (isl_basic_set_free_equality(bset, n_eq) < 0)
+		bset = isl_basic_set_free(bset);
+
+	eq_bmap = isl_basic_map_overlying_set(eq, isl_basic_map_copy(bmap));
+	eq_bmap = isl_basic_map_remove_shifted_constraints(eq_bmap, context);
+	bmap = isl_basic_map_overlying_set(bset, bmap);
+	bmap = isl_basic_map_intersect(bmap, eq_bmap);
+	bmap = isl_basic_map_remove_redundancies(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/*
+ * Assumes context has no implicit divs.
+ */
+__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *context)
+{
+	int i;
+
+	if (!map || !context)
+		goto error;
+
+	if (isl_basic_map_plain_is_empty(context)) {
+		isl_space *space = isl_map_get_space(map);
+		isl_map_free(map);
+		isl_basic_map_free(context);
+		return isl_map_universe(space);
+	}
+
+	context = isl_basic_map_remove_redundancies(context);
+	map = isl_map_cow(map);
+	if (!map || !context)
+		goto error;
+	isl_assert(map->ctx, isl_space_is_equal(map->dim, context->dim), goto error);
+	map = isl_map_compute_divs(map);
+	if (!map)
+		goto error;
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_gist(map->p[i],
+						isl_basic_map_copy(context));
+		if (!map->p[i])
+			goto error;
+		if (isl_basic_map_plain_is_empty(map->p[i])) {
+			isl_basic_map_free(map->p[i]);
+			if (i != map->n - 1)
+				map->p[i] = map->p[map->n - 1];
+			map->n--;
+		}
+	}
+	isl_basic_map_free(context);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Return a map that has the same intersection with "context" as "map"
+ * and that is as "simple" as possible.
+ *
+ * If "map" is already the universe, then we cannot make it any simpler.
+ * Similarly, if "context" is the universe, then we cannot exploit it
+ * to simplify "map"
+ * If "map" and "context" are identical to each other, then we can
+ * return the corresponding universe.
+ *
+ * If none of these cases apply, we have to work a bit harder.
+ */
+static __isl_give isl_map *map_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context)
+{
+	int equal;
+	int is_universe;
+
+	is_universe = isl_map_plain_is_universe(map);
+	if (is_universe >= 0 && !is_universe)
+		is_universe = isl_map_plain_is_universe(context);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(context);
+		return map;
+	}
+
+	equal = isl_map_plain_is_equal(map, context);
+	if (equal < 0)
+		goto error;
+	if (equal) {
+		isl_map *res = isl_map_universe(isl_map_get_space(map));
+		isl_map_free(map);
+		isl_map_free(context);
+		return res;
+	}
+
+	context = isl_map_compute_divs(context);
+	return isl_map_gist_basic_map(map, isl_map_simple_hull(context));
+error:
+	isl_map_free(map);
+	isl_map_free(context);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context)
+{
+	return isl_map_align_params_map_map_and(map, context, &map_gist);
+}
+
+struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset,
+						struct isl_basic_set *context)
+{
+	return (struct isl_basic_set *)isl_basic_map_gist(
+		(struct isl_basic_map *)bset, (struct isl_basic_map *)context);
+}
+
+__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	return (struct isl_set *)isl_map_gist_basic_map((struct isl_map *)set,
+					(struct isl_basic_map *)context);
+}
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	isl_space *space = isl_set_get_space(set);
+	isl_basic_set *dom_context = isl_basic_set_universe(space);
+	dom_context = isl_basic_set_intersect_params(dom_context, context);
+	return isl_set_gist_basic_set(set, dom_context);
+}
+
+__isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
+	__isl_take isl_set *context)
+{
+	return (struct isl_set *)isl_map_gist((struct isl_map *)set,
+					(struct isl_map *)context);
+}
+
+__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_domain(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_range(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_params(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set,
+	__isl_take isl_set *context)
+{
+	return isl_map_gist_params(set, context);
+}
+
+/* Quick check to see if two basic maps are disjoint.
+ * In particular, we reduce the equalities and inequalities of
+ * one basic map in the context of the equalities of the other
+ * basic map and check if we get a contradiction.
+ */
+int isl_basic_map_plain_is_disjoint(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	struct isl_vec *v = NULL;
+	int *elim = NULL;
+	unsigned total;
+	int i;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+			return -1);
+	if (bmap1->n_div || bmap2->n_div)
+		return 0;
+	if (!bmap1->n_eq && !bmap2->n_eq)
+		return 0;
+
+	total = isl_space_dim(bmap1->dim, isl_dim_all);
+	if (total == 0)
+		return 0;
+	v = isl_vec_alloc(bmap1->ctx, 1 + total);
+	if (!v)
+		goto error;
+	elim = isl_alloc_array(bmap1->ctx, int, total);
+	if (!elim)
+		goto error;
+	compute_elimination_index(bmap1, elim);
+	for (i = 0; i < bmap2->n_eq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data, bmap2->eq[i],
+							bmap1, elim);
+		if (reduced && !isl_int_is_zero(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	for (i = 0; i < bmap2->n_ineq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data,
+						bmap2->ineq[i], bmap1, elim);
+		if (reduced && isl_int_is_neg(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	compute_elimination_index(bmap2, elim);
+	for (i = 0; i < bmap1->n_ineq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data,
+						bmap1->ineq[i], bmap2, elim);
+		if (reduced && isl_int_is_neg(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	isl_vec_free(v);
+	free(elim);
+	return 0;
+disjoint:
+	isl_vec_free(v);
+	free(elim);
+	return 1;
+error:
+	isl_vec_free(v);
+	free(elim);
+	return -1;
+}
+
+int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_is_disjoint((struct isl_basic_map *)bset1,
+					      (struct isl_basic_map *)bset2);
+}
+
+/* Are "map1" and "map2" obviously disjoint?
+ *
+ * If one of them is empty or if they live in different spaces (ignoring
+ * parameters), then they are clearly disjoint.
+ *
+ * If they have different parameters, then we skip any further tests.
+ *
+ * If they are obviously equal, but not obviously empty, then we will
+ * not be able to detect if they are disjoint.
+ *
+ * Otherwise we check if each basic map in "map1" is obviously disjoint
+ * from each basic map in "map2".
+ */
+int isl_map_plain_is_disjoint(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	int i, j;
+	int disjoint;
+	int intersect;
+	int match;
+
+	if (!map1 || !map2)
+		return -1;
+
+	disjoint = isl_map_plain_is_empty(map1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_plain_is_empty(map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	match = isl_space_tuple_is_equal(map1->dim, isl_dim_in,
+				map2->dim, isl_dim_in);
+	if (match < 0 || !match)
+		return match < 0 ? -1 : 1;
+
+	match = isl_space_tuple_is_equal(map1->dim, isl_dim_out,
+				map2->dim, isl_dim_out);
+	if (match < 0 || !match)
+		return match < 0 ? -1 : 1;
+
+	match = isl_space_match(map1->dim, isl_dim_param,
+				map2->dim, isl_dim_param);
+	if (match < 0 || !match)
+		return match < 0 ? -1 : 0;
+
+	intersect = isl_map_plain_is_equal(map1, map2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? -1 : 0;
+
+	for (i = 0; i < map1->n; ++i) {
+		for (j = 0; j < map2->n; ++j) {
+			int d = isl_basic_map_plain_is_disjoint(map1->p[i],
+							       map2->p[j]);
+			if (d != 1)
+				return d;
+		}
+	}
+	return 1;
+}
+
+/* Are "map1" and "map2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty.  Otherwise, they are not disjoint if one of them is universal.
+ * If none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+int isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	int disjoint;
+	int intersect;
+	isl_map *test;
+
+	disjoint = isl_map_plain_is_disjoint(map1, map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_is_empty(map1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_is_empty(map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	intersect = isl_map_plain_is_universe(map1);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? -1 : 0;
+
+	intersect = isl_map_plain_is_universe(map2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? -1 : 0;
+
+	test = isl_map_intersect(isl_map_copy(map1), isl_map_copy(map2));
+	disjoint = isl_map_is_empty(test);
+	isl_map_free(test);
+
+	return disjoint;
+}
+
+/* Are "bmap1" and "bmap2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty.  Otherwise, they are not disjoint if one of them is universal.
+ * If none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+int isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int disjoint;
+	int intersect;
+	isl_basic_map *test;
+
+	disjoint = isl_basic_map_plain_is_disjoint(bmap1, bmap2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_basic_map_is_empty(bmap1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_basic_map_is_empty(bmap2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	intersect = isl_basic_map_is_universe(bmap1);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? -1 : 0;
+
+	intersect = isl_basic_map_is_universe(bmap2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? -1 : 0;
+
+	test = isl_basic_map_intersect(isl_basic_map_copy(bmap1),
+		isl_basic_map_copy(bmap2));
+	disjoint = isl_basic_map_is_empty(test);
+	isl_basic_map_free(test);
+
+	return disjoint;
+}
+
+/* Are "bset1" and "bset2" disjoint?
+ */
+int isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_is_disjoint(bset1, bset2);
+}
+
+int isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	return isl_map_plain_is_disjoint((struct isl_map *)set1,
+					(struct isl_map *)set2);
+}
+
+/* Are "set1" and "set2" disjoint?
+ */
+int isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_is_disjoint(set1, set2);
+}
+
+int isl_set_fast_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_set_plain_is_disjoint(set1, set2);
+}
+
+/* Check if we can combine a given div with lower bound l and upper
+ * bound u with some other div and if so return that other div.
+ * Otherwise return -1.
+ *
+ * We first check that
+ *	- the bounds are opposites of each other (except for the constant
+ *	  term)
+ *	- the bounds do not reference any other div
+ *	- no div is defined in terms of this div
+ *
+ * Let m be the size of the range allowed on the div by the bounds.
+ * That is, the bounds are of the form
+ *
+ *	e <= a <= e + m - 1
+ *
+ * with e some expression in the other variables.
+ * We look for another div b such that no third div is defined in terms
+ * of this second div b and such that in any constraint that contains
+ * a (except for the given lower and upper bound), also contains b
+ * with a coefficient that is m times that of b.
+ * That is, all constraints (execpt for the lower and upper bound)
+ * are of the form
+ *
+ *	e + f (a + m b) >= 0
+ *
+ * If so, we return b so that "a + m b" can be replaced by
+ * a single div "c = a + m b".
+ */
+static int div_find_coalesce(struct isl_basic_map *bmap, int *pairs,
+	unsigned div, unsigned l, unsigned u)
+{
+	int i, j;
+	unsigned dim;
+	int coalesce = -1;
+
+	if (bmap->n_div <= 1)
+		return -1;
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim, div) != -1)
+		return -1;
+	if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim + div + 1,
+				   bmap->n_div - div - 1) != -1)
+		return -1;
+	if (!isl_seq_is_neg(bmap->ineq[l] + 1, bmap->ineq[u] + 1,
+			    dim + bmap->n_div))
+		return -1;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1 + 1 + dim + div]))
+			return -1;
+	}
+
+	isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+	if (isl_int_is_neg(bmap->ineq[l][0])) {
+		isl_int_sub(bmap->ineq[l][0],
+			    bmap->ineq[l][0], bmap->ineq[u][0]);
+		bmap = isl_basic_map_copy(bmap);
+		bmap = isl_basic_map_set_to_empty(bmap);
+		isl_basic_map_free(bmap);
+		return -1;
+	}
+	isl_int_add_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (i == div)
+			continue;
+		if (!pairs[i])
+			continue;
+		for (j = 0; j < bmap->n_div; ++j) {
+			if (isl_int_is_zero(bmap->div[j][0]))
+				continue;
+			if (!isl_int_is_zero(bmap->div[j][1 + 1 + dim + i]))
+				break;
+		}
+		if (j < bmap->n_div)
+			continue;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			int valid;
+			if (j == l || j == u)
+				continue;
+			if (isl_int_is_zero(bmap->ineq[j][1 + dim + div]))
+				continue;
+			if (isl_int_is_zero(bmap->ineq[j][1 + dim + i]))
+				break;
+			isl_int_mul(bmap->ineq[j][1 + dim + div],
+				    bmap->ineq[j][1 + dim + div],
+				    bmap->ineq[l][0]);
+			valid = isl_int_eq(bmap->ineq[j][1 + dim + div],
+					   bmap->ineq[j][1 + dim + i]);
+			isl_int_divexact(bmap->ineq[j][1 + dim + div],
+					 bmap->ineq[j][1 + dim + div],
+					 bmap->ineq[l][0]);
+			if (!valid)
+				break;
+		}
+		if (j < bmap->n_ineq)
+			continue;
+		coalesce = i;
+		break;
+	}
+	isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	isl_int_sub(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+	return coalesce;
+}
+
+/* Given a lower and an upper bound on div i, construct an inequality
+ * that when nonnegative ensures that this pair of bounds always allows
+ * for an integer value of the given div.
+ * The lower bound is inequality l, while the upper bound is inequality u.
+ * The constructed inequality is stored in ineq.
+ * g, fl, fu are temporary scalars.
+ *
+ * Let the upper bound be
+ *
+ *	-n_u a + e_u >= 0
+ *
+ * and the lower bound
+ *
+ *	n_l a + e_l >= 0
+ *
+ * Let n_u = f_u g and n_l = f_l g, with g = gcd(n_u, n_l).
+ * We have
+ *
+ *	- f_u e_l <= f_u f_l g a <= f_l e_u
+ *
+ * Since all variables are integer valued, this is equivalent to
+ *
+ *	- f_u e_l - (f_u - 1) <= f_u f_l g a <= f_l e_u + (f_l - 1)
+ *
+ * If this interval is at least f_u f_l g, then it contains at least
+ * one integer value for a.
+ * That is, the test constraint is
+ *
+ *	f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 >= f_u f_l g
+ */
+static void construct_test_ineq(struct isl_basic_map *bmap, int i,
+	int l, int u, isl_int *ineq, isl_int g, isl_int fl, isl_int fu)
+{
+	unsigned dim;
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+	isl_int_gcd(g, bmap->ineq[l][1 + dim + i], bmap->ineq[u][1 + dim + i]);
+	isl_int_divexact(fl, bmap->ineq[l][1 + dim + i], g);
+	isl_int_divexact(fu, bmap->ineq[u][1 + dim + i], g);
+	isl_int_neg(fu, fu);
+	isl_seq_combine(ineq, fl, bmap->ineq[u], fu, bmap->ineq[l],
+			1 + dim + bmap->n_div);
+	isl_int_add(ineq[0], ineq[0], fl);
+	isl_int_add(ineq[0], ineq[0], fu);
+	isl_int_sub_ui(ineq[0], ineq[0], 1);
+	isl_int_mul(g, g, fl);
+	isl_int_mul(g, g, fu);
+	isl_int_sub(ineq[0], ineq[0], g);
+}
+
+/* Remove more kinds of divs that are not strictly needed.
+ * In particular, if all pairs of lower and upper bounds on a div
+ * are such that they allow at least one integer value of the div,
+ * the we can eliminate the div using Fourier-Motzkin without
+ * introducing any spurious solutions.
+ */
+static struct isl_basic_map *drop_more_redundant_divs(
+	struct isl_basic_map *bmap, int *pairs, int n)
+{
+	struct isl_tab *tab = NULL;
+	struct isl_vec *vec = NULL;
+	unsigned dim;
+	int remove = -1;
+	isl_int g, fl, fu;
+
+	isl_int_init(g);
+	isl_int_init(fl);
+	isl_int_init(fu);
+
+	if (!bmap)
+		goto error;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div);
+	if (!vec)
+		goto error;
+
+	tab = isl_tab_from_basic_map(bmap, 0);
+
+	while (n > 0) {
+		int i, l, u;
+		int best = -1;
+		enum isl_lp_result res;
+
+		for (i = 0; i < bmap->n_div; ++i) {
+			if (!pairs[i])
+				continue;
+			if (best >= 0 && pairs[best] <= pairs[i])
+				continue;
+			best = i;
+		}
+
+		i = best;
+		for (l = 0; l < bmap->n_ineq; ++l) {
+			if (!isl_int_is_pos(bmap->ineq[l][1 + dim + i]))
+				continue;
+			for (u = 0; u < bmap->n_ineq; ++u) {
+				if (!isl_int_is_neg(bmap->ineq[u][1 + dim + i]))
+					continue;
+				construct_test_ineq(bmap, i, l, u,
+						    vec->el, g, fl, fu);
+				res = isl_tab_min(tab, vec->el,
+						  bmap->ctx->one, &g, NULL, 0);
+				if (res == isl_lp_error)
+					goto error;
+				if (res == isl_lp_empty) {
+					bmap = isl_basic_map_set_to_empty(bmap);
+					break;
+				}
+				if (res != isl_lp_ok || isl_int_is_neg(g))
+					break;
+			}
+			if (u < bmap->n_ineq)
+				break;
+		}
+		if (l == bmap->n_ineq) {
+			remove = i;
+			break;
+		}
+		pairs[i] = 0;
+		--n;
+	}
+
+	isl_tab_free(tab);
+	isl_vec_free(vec);
+
+	isl_int_clear(g);
+	isl_int_clear(fl);
+	isl_int_clear(fu);
+
+	free(pairs);
+
+	if (remove < 0)
+		return bmap;
+
+	bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, remove, 1);
+	return isl_basic_map_drop_redundant_divs(bmap);
+error:
+	free(pairs);
+	isl_basic_map_free(bmap);
+	isl_tab_free(tab);
+	isl_vec_free(vec);
+	isl_int_clear(g);
+	isl_int_clear(fl);
+	isl_int_clear(fu);
+	return NULL;
+}
+
+/* Given a pair of divs div1 and div2 such that, expect for the lower bound l
+ * and the upper bound u, div1 always occurs together with div2 in the form 
+ * (div1 + m div2), where m is the constant range on the variable div1
+ * allowed by l and u, replace the pair div1 and div2 by a single
+ * div that is equal to div1 + m div2.
+ *
+ * The new div will appear in the location that contains div2.
+ * We need to modify all constraints that contain
+ * div2 = (div - div1) / m
+ * (If a constraint does not contain div2, it will also not contain div1.)
+ * If the constraint also contains div1, then we know they appear
+ * as f (div1 + m div2) and we can simply replace (div1 + m div2) by div,
+ * i.e., the coefficient of div is f.
+ *
+ * Otherwise, we first need to introduce div1 into the constraint.
+ * Let the l be
+ *
+ *	div1 + f >=0
+ *
+ * and u
+ *
+ *	-div1 + f' >= 0
+ *
+ * A lower bound on div2
+ *
+ *	n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	(n * (m div 2 + div1) + m t + n f)/g >= 0
+ *
+ * with g = gcd(m,n).
+ * An upper bound
+ *
+ *	-n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	(-n * (m div2 + div1) + m t + n f')/g >= 0
+ *
+ * These constraint are those that we would obtain from eliminating
+ * div1 using Fourier-Motzkin.
+ *
+ * After all constraints have been modified, we drop the lower and upper
+ * bound and then drop div1.
+ */
+static struct isl_basic_map *coalesce_divs(struct isl_basic_map *bmap,
+	unsigned div1, unsigned div2, unsigned l, unsigned u)
+{
+	isl_int a;
+	isl_int b;
+	isl_int m;
+	unsigned dim, total;
+	int i;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	total = 1 + dim + bmap->n_div;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	isl_int_init(m);
+	isl_int_add(m, bmap->ineq[l][0], bmap->ineq[u][0]);
+	isl_int_add_ui(m, m, 1);
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (i == l || i == u)
+			continue;
+		if (isl_int_is_zero(bmap->ineq[i][1 + dim + div2]))
+			continue;
+		if (isl_int_is_zero(bmap->ineq[i][1 + dim + div1])) {
+			isl_int_gcd(b, m, bmap->ineq[i][1 + dim + div2]);
+			isl_int_divexact(a, m, b);
+			isl_int_divexact(b, bmap->ineq[i][1 + dim + div2], b);
+			if (isl_int_is_pos(b)) {
+				isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+						b, bmap->ineq[l], total);
+			} else {
+				isl_int_neg(b, b);
+				isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+						b, bmap->ineq[u], total);
+			}
+		}
+		isl_int_set(bmap->ineq[i][1 + dim + div2],
+			    bmap->ineq[i][1 + dim + div1]);
+		isl_int_set_si(bmap->ineq[i][1 + dim + div1], 0);
+	}
+
+	isl_int_clear(a);
+	isl_int_clear(b);
+	isl_int_clear(m);
+	if (l > u) {
+		isl_basic_map_drop_inequality(bmap, l);
+		isl_basic_map_drop_inequality(bmap, u);
+	} else {
+		isl_basic_map_drop_inequality(bmap, u);
+		isl_basic_map_drop_inequality(bmap, l);
+	}
+	bmap = isl_basic_map_drop_div(bmap, div1);
+	return bmap;
+}
+
+/* First check if we can coalesce any pair of divs and
+ * then continue with dropping more redundant divs.
+ *
+ * We loop over all pairs of lower and upper bounds on a div
+ * with coefficient 1 and -1, respectively, check if there
+ * is any other div "c" with which we can coalesce the div
+ * and if so, perform the coalescing.
+ */
+static struct isl_basic_map *coalesce_or_drop_more_redundant_divs(
+	struct isl_basic_map *bmap, int *pairs, int n)
+{
+	int i, l, u;
+	unsigned dim;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (!pairs[i])
+			continue;
+		for (l = 0; l < bmap->n_ineq; ++l) {
+			if (!isl_int_is_one(bmap->ineq[l][1 + dim + i]))
+				continue;
+			for (u = 0; u < bmap->n_ineq; ++u) {
+				int c;
+
+				if (!isl_int_is_negone(bmap->ineq[u][1+dim+i]))
+					continue;
+				c = div_find_coalesce(bmap, pairs, i, l, u);
+				if (c < 0)
+					continue;
+				free(pairs);
+				bmap = coalesce_divs(bmap, i, c, l, u);
+				return isl_basic_map_drop_redundant_divs(bmap);
+			}
+		}
+	}
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return bmap;
+
+	return drop_more_redundant_divs(bmap, pairs, n);
+}
+
+/* Remove divs that are not strictly needed.
+ * In particular, if a div only occurs positively (or negatively)
+ * in constraints, then it can simply be dropped.
+ * Also, if a div occurs in only two constraints and if moreover
+ * those two constraints are opposite to each other, except for the constant
+ * term and if the sum of the constant terms is such that for any value
+ * of the other values, there is always at least one integer value of the
+ * div, i.e., if one plus this sum is greater than or equal to
+ * the (absolute value) of the coefficent of the div in the constraints,
+ * then we can also simply drop the div.
+ *
+ * We skip divs that appear in equalities or in the definition of other divs.
+ * Divs that appear in the definition of other divs usually occur in at least
+ * 4 constraints, but the constraints may have been simplified.
+ *
+ * If any divs are left after these simple checks then we move on
+ * to more complicated cases in drop_more_redundant_divs.
+ */
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+	struct isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned off;
+	int *pairs = NULL;
+	int n = 0;
+
+	if (!bmap)
+		goto error;
+	if (bmap->n_div == 0)
+		return bmap;
+
+	off = isl_space_dim(bmap->dim, isl_dim_all);
+	pairs = isl_calloc_array(bmap->ctx, int, bmap->n_div);
+	if (!pairs)
+		goto error;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		int pos, neg;
+		int last_pos, last_neg;
+		int redundant;
+		int defined;
+
+		defined = !isl_int_is_zero(bmap->div[i][0]);
+		for (j = i; j < bmap->n_div; ++j)
+			if (!isl_int_is_zero(bmap->div[j][1 + 1 + off + i]))
+				break;
+		if (j < bmap->n_div)
+			continue;
+		for (j = 0; j < bmap->n_eq; ++j)
+			if (!isl_int_is_zero(bmap->eq[j][1 + off + i]))
+				break;
+		if (j < bmap->n_eq)
+			continue;
+		++n;
+		pos = neg = 0;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			if (isl_int_is_pos(bmap->ineq[j][1 + off + i])) {
+				last_pos = j;
+				++pos;
+			}
+			if (isl_int_is_neg(bmap->ineq[j][1 + off + i])) {
+				last_neg = j;
+				++neg;
+			}
+		}
+		pairs[i] = pos * neg;
+		if (pairs[i] == 0) {
+			for (j = bmap->n_ineq - 1; j >= 0; --j)
+				if (!isl_int_is_zero(bmap->ineq[j][1+off+i]))
+					isl_basic_map_drop_inequality(bmap, j);
+			bmap = isl_basic_map_drop_div(bmap, i);
+			free(pairs);
+			return isl_basic_map_drop_redundant_divs(bmap);
+		}
+		if (pairs[i] != 1)
+			continue;
+		if (!isl_seq_is_neg(bmap->ineq[last_pos] + 1,
+				    bmap->ineq[last_neg] + 1,
+				    off + bmap->n_div))
+			continue;
+
+		isl_int_add(bmap->ineq[last_pos][0],
+			    bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+		isl_int_add_ui(bmap->ineq[last_pos][0],
+			       bmap->ineq[last_pos][0], 1);
+		redundant = isl_int_ge(bmap->ineq[last_pos][0],
+				bmap->ineq[last_pos][1+off+i]);
+		isl_int_sub_ui(bmap->ineq[last_pos][0],
+			       bmap->ineq[last_pos][0], 1);
+		isl_int_sub(bmap->ineq[last_pos][0],
+			    bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+		if (!redundant) {
+			if (defined ||
+			    !ok_to_set_div_from_bound(bmap, i, last_pos)) {
+				pairs[i] = 0;
+				--n;
+				continue;
+			}
+			bmap = set_div_from_lower_bound(bmap, i, last_pos);
+			bmap = isl_basic_map_simplify(bmap);
+			free(pairs);
+			return isl_basic_map_drop_redundant_divs(bmap);
+		}
+		if (last_pos > last_neg) {
+			isl_basic_map_drop_inequality(bmap, last_pos);
+			isl_basic_map_drop_inequality(bmap, last_neg);
+		} else {
+			isl_basic_map_drop_inequality(bmap, last_neg);
+			isl_basic_map_drop_inequality(bmap, last_pos);
+		}
+		bmap = isl_basic_map_drop_div(bmap, i);
+		free(pairs);
+		return isl_basic_map_drop_redundant_divs(bmap);
+	}
+
+	if (n > 0)
+		return coalesce_or_drop_more_redundant_divs(bmap, pairs, n);
+
+	free(pairs);
+	return bmap;
+error:
+	free(pairs);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+	struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+	    isl_basic_map_drop_redundant_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_map_drop_redundant_divs(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_drop_redundant_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop_redundant_divs(struct isl_set *set)
+{
+	return (struct isl_set *)
+	    isl_map_drop_redundant_divs((struct isl_map *)set);
+}






More information about the llvm-commits mailing list