[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_map_subtract.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_subtract.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_subtract.c (added)
+++ polly/trunk/lib/External/isl/isl_map_subtract.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,900 @@
+/*
+ * 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_map_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include "isl_tab.h"
+#include <isl_point_private.h>
+#include <isl_vec_private.h>
+
+/* Expand the constraint "c" into "v".  The initial "dim" dimensions
+ * are the same, but "v" may have more divs than "c" and the divs of "c"
+ * may appear in different positions in "v".
+ * The number of divs in "c" is given by "n_div" and the mapping
+ * of divs in "c" to divs in "v" is given by "div_map".
+ *
+ * Although it shouldn't happen in practice, it is theoretically
+ * possible that two or more divs in "c" are mapped to the same div in "v".
+ * These divs are then necessarily the same, so we simply add their
+ * coefficients.
+ */
+static void expand_constraint(isl_vec *v, unsigned dim,
+	isl_int *c, int *div_map, unsigned n_div)
+{
+	int i;
+
+	isl_seq_cpy(v->el, c, 1 + dim);
+	isl_seq_clr(v->el + 1 + dim, v->size - (1 + dim));
+
+	for (i = 0; i < n_div; ++i) {
+		int pos = 1 + dim + div_map[i];
+		isl_int_add(v->el[pos], v->el[pos], c[1 + dim + i]);
+	}
+}
+
+/* Add all constraints of bmap to tab.  The equalities of bmap
+ * are added as a pair of inequalities.
+ */
+static int tab_add_constraints(struct isl_tab *tab,
+	__isl_keep isl_basic_map *bmap, int *div_map)
+{
+	int i;
+	unsigned dim;
+	unsigned tab_total;
+	unsigned bmap_total;
+	isl_vec *v;
+
+	if (!tab || !bmap)
+		return -1;
+
+	tab_total = isl_basic_map_total_dim(tab->bmap);
+	bmap_total = isl_basic_map_total_dim(bmap);
+	dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
+
+	if (isl_tab_extend_cons(tab, 2 * bmap->n_eq + bmap->n_ineq) < 0)
+		return -1;
+
+	v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
+	if (!v)
+		return -1;
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
+		expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
+		if (tab->empty)
+			break;
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		expand_constraint(v, dim, bmap->ineq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		if (tab->empty)
+			break;
+	}
+
+	isl_vec_free(v);
+	return 0;
+error:
+	isl_vec_free(v);
+	return -1;
+}
+
+/* Add a specific constraint of bmap (or its opposite) to tab.
+ * The position of the constraint is specified by "c", where
+ * the equalities of bmap are counted twice, once for the inequality
+ * that is equal to the equality, and once for its negation.
+ */
+static int tab_add_constraint(struct isl_tab *tab,
+	__isl_keep isl_basic_map *bmap, int *div_map, int c, int oppose)
+{
+	unsigned dim;
+	unsigned tab_total;
+	unsigned bmap_total;
+	isl_vec *v;
+	int r;
+
+	if (!tab || !bmap)
+		return -1;
+
+	tab_total = isl_basic_map_total_dim(tab->bmap);
+	bmap_total = isl_basic_map_total_dim(bmap);
+	dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
+
+	v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
+	if (!v)
+		return -1;
+
+	if (c < 2 * bmap->n_eq) {
+		if ((c % 2) != oppose)
+			isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
+					1 + bmap_total);
+		if (oppose)
+			isl_int_sub_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
+		expand_constraint(v, dim, bmap->eq[c/2], div_map, bmap->n_div);
+		r = isl_tab_add_ineq(tab, v->el);
+		if (oppose)
+			isl_int_add_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
+		if ((c % 2) != oppose)
+			isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
+					1 + bmap_total);
+	} else {
+		c -= 2 * bmap->n_eq;
+		if (oppose) {
+			isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
+					1 + bmap_total);
+			isl_int_sub_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
+		}
+		expand_constraint(v, dim, bmap->ineq[c], div_map, bmap->n_div);
+		r = isl_tab_add_ineq(tab, v->el);
+		if (oppose) {
+			isl_int_add_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
+			isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
+					1 + bmap_total);
+		}
+	}
+
+	isl_vec_free(v);
+	return r;
+}
+
+static int tab_add_divs(struct isl_tab *tab, __isl_keep isl_basic_map *bmap,
+	int **div_map)
+{
+	int i, j;
+	struct isl_vec *vec;
+	unsigned total;
+	unsigned dim;
+
+	if (!bmap)
+		return -1;
+	if (!bmap->n_div)
+		return 0;
+
+	if (!*div_map)
+		*div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div);
+	if (!*div_map)
+		return -1;
+
+	total = isl_basic_map_total_dim(tab->bmap);
+	dim = total - tab->bmap->n_div;
+	vec = isl_vec_alloc(bmap->ctx, 2 + total + bmap->n_div);
+	if (!vec)
+		return -1;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		isl_seq_cpy(vec->el, bmap->div[i], 2 + dim);
+		isl_seq_clr(vec->el + 2 + dim, tab->bmap->n_div);
+		for (j = 0; j < i; ++j)
+			isl_int_set(vec->el[2 + dim + (*div_map)[j]],
+					bmap->div[i][2 + dim + j]);
+		for (j = 0; j < tab->bmap->n_div; ++j)
+			if (isl_seq_eq(tab->bmap->div[j],
+					vec->el, 2 + dim + tab->bmap->n_div))
+				break;
+		(*div_map)[i] = j;
+		if (j == tab->bmap->n_div) {
+			vec->size = 2 + dim + tab->bmap->n_div;
+			if (isl_tab_add_div(tab, vec, NULL, NULL) < 0)
+				goto error;
+		}
+	}
+
+	isl_vec_free(vec);
+
+	return 0;
+error:
+	isl_vec_free(vec);
+
+	return -1;
+}
+
+/* Freeze all constraints of tableau tab.
+ */
+static int tab_freeze_constraints(struct isl_tab *tab)
+{
+	int i;
+
+	for (i = 0; i < tab->n_con; ++i)
+		if (isl_tab_freeze_constraint(tab, i) < 0)
+			return -1;
+
+	return 0;
+}
+
+/* Check for redundant constraints starting at offset.
+ * Put the indices of the redundant constraints in index
+ * and return the number of redundant constraints.
+ */
+static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab,
+	int offset, int **index)
+{
+	int i, n;
+	int n_test = tab->n_con - offset;
+
+	if (isl_tab_detect_redundant(tab) < 0)
+		return -1;
+
+	if (n_test == 0)
+		return 0;
+	if (!*index)
+		*index = isl_alloc_array(ctx, int, n_test);
+	if (!*index)
+		return -1;
+
+	for (n = 0, i = 0; i < n_test; ++i) {
+		int r;
+		r = isl_tab_is_redundant(tab, offset + i);
+		if (r < 0)
+			return -1;
+		if (r)
+			continue;
+		(*index)[n++] = i;
+	}
+
+	return n;
+}
+
+/* basic_map_collect_diff calls add on each of the pieces of
+ * the set difference between bmap and map until the add method
+ * return a negative value.
+ */
+struct isl_diff_collector {
+	int (*add)(struct isl_diff_collector *dc,
+		    __isl_take isl_basic_map *bmap);
+};
+
+/* Compute the set difference between bmap and map and call
+ * dc->add on each of the piece until this function returns
+ * a negative value.
+ * Return 0 on success and -1 on error.  dc->add returning
+ * a negative value is treated as an error, but the calling
+ * function can interpret the results based on the state of dc.
+ *
+ * Assumes that map has known divs.
+ *
+ * The difference is computed by a backtracking algorithm.
+ * Each level corresponds to a basic map in "map".
+ * When a node in entered for the first time, we check
+ * if the corresonding basic map intersects the current piece
+ * of "bmap".  If not, we move to the next level.
+ * Otherwise, we split the current piece into as many
+ * pieces as there are non-redundant constraints of the current
+ * basic map in the intersection.  Each of these pieces is
+ * handled by a child of the current node.
+ * In particular, if there are n non-redundant constraints,
+ * then for each 0 <= i < n, a piece is cut off by adding
+ * constraints 0 <= j < i and adding the opposite of constraint i.
+ * If there are no non-redundant constraints, meaning that the current
+ * piece is a subset of the current basic map, then we simply backtrack.
+ *
+ * In the leaves, we check if the remaining piece has any integer points
+ * and if so, pass it along to dc->add.  As a special case, if nothing
+ * has been removed when we end up in a leaf, we simply pass along
+ * the original basic map.
+ */
+static int basic_map_collect_diff(__isl_take isl_basic_map *bmap,
+	__isl_take isl_map *map, struct isl_diff_collector *dc)
+{
+	int i;
+	int modified;
+	int level;
+	int init;
+	int empty;
+	isl_ctx *ctx;
+	struct isl_tab *tab = NULL;
+	struct isl_tab_undo **snap = NULL;
+	int *k = NULL;
+	int *n = NULL;
+	int **index = NULL;
+	int **div_map = NULL;
+
+	empty = isl_basic_map_is_empty(bmap);
+	if (empty) {
+		isl_basic_map_free(bmap);
+		isl_map_free(map);
+		return empty < 0 ? -1 : 0;
+	}
+
+	bmap = isl_basic_map_cow(bmap);
+	map = isl_map_cow(map);
+
+	if (!bmap || !map)
+		goto error;
+
+	ctx = map->ctx;
+	snap = isl_alloc_array(map->ctx, struct isl_tab_undo *, map->n);
+	k = isl_alloc_array(map->ctx, int, map->n);
+	n = isl_alloc_array(map->ctx, int, map->n);
+	index = isl_calloc_array(map->ctx, int *, map->n);
+	div_map = isl_calloc_array(map->ctx, int *, map->n);
+	if (!snap || !k || !n || !index || !div_map)
+		goto error;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	map = isl_map_order_divs(map);
+
+	tab = isl_tab_from_basic_map(bmap, 1);
+	if (!tab)
+		goto error;
+
+	modified = 0;
+	level = 0;
+	init = 1;
+
+	while (level >= 0) {
+		if (level >= map->n) {
+			int empty;
+			struct isl_basic_map *bm;
+			if (!modified) {
+				if (dc->add(dc, isl_basic_map_copy(bmap)) < 0)
+					goto error;
+				break;
+			}
+			bm = isl_basic_map_copy(tab->bmap);
+			bm = isl_basic_map_cow(bm);
+			bm = isl_basic_map_update_from_tab(bm, tab);
+			bm = isl_basic_map_simplify(bm);
+			bm = isl_basic_map_finalize(bm);
+			empty = isl_basic_map_is_empty(bm);
+			if (empty)
+				isl_basic_map_free(bm);
+			else if (dc->add(dc, bm) < 0)
+				goto error;
+			if (empty < 0)
+				goto error;
+			level--;
+			init = 0;
+			continue;
+		}
+		if (init) {
+			int offset;
+			struct isl_tab_undo *snap2;
+			snap2 = isl_tab_snap(tab);
+			if (tab_add_divs(tab, map->p[level],
+					 &div_map[level]) < 0)
+				goto error;
+			offset = tab->n_con;
+			snap[level] = isl_tab_snap(tab);
+			if (tab_freeze_constraints(tab) < 0)
+				goto error;
+			if (tab_add_constraints(tab, map->p[level],
+						div_map[level]) < 0)
+				goto error;
+			k[level] = 0;
+			n[level] = 0;
+			if (tab->empty) {
+				if (isl_tab_rollback(tab, snap2) < 0)
+					goto error;
+				level++;
+				continue;
+			}
+			modified = 1;
+			n[level] = n_non_redundant(ctx, tab, offset,
+						    &index[level]);
+			if (n[level] < 0)
+				goto error;
+			if (n[level] == 0) {
+				level--;
+				init = 0;
+				continue;
+			}
+			if (isl_tab_rollback(tab, snap[level]) < 0)
+				goto error;
+			if (tab_add_constraint(tab, map->p[level],
+					div_map[level], index[level][0], 1) < 0)
+				goto error;
+			level++;
+			continue;
+		} else {
+			if (k[level] + 1 >= n[level]) {
+				level--;
+				continue;
+			}
+			if (isl_tab_rollback(tab, snap[level]) < 0)
+				goto error;
+			if (tab_add_constraint(tab, map->p[level],
+						div_map[level],
+						index[level][k[level]], 0) < 0)
+				goto error;
+			snap[level] = isl_tab_snap(tab);
+			k[level]++;
+			if (tab_add_constraint(tab, map->p[level],
+						div_map[level],
+						index[level][k[level]], 1) < 0)
+				goto error;
+			level++;
+			init = 1;
+			continue;
+		}
+	}
+
+	isl_tab_free(tab);
+	free(snap);
+	free(n);
+	free(k);
+	for (i = 0; index && i < map->n; ++i)
+		free(index[i]);
+	free(index);
+	for (i = 0; div_map && i < map->n; ++i)
+		free(div_map[i]);
+	free(div_map);
+
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+
+	return 0;
+error:
+	isl_tab_free(tab);
+	free(snap);
+	free(n);
+	free(k);
+	for (i = 0; index && i < map->n; ++i)
+		free(index[i]);
+	free(index);
+	for (i = 0; div_map && i < map->n; ++i)
+		free(div_map[i]);
+	free(div_map);
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+	return -1;
+}
+
+/* A diff collector that actually collects all parts of the
+ * set difference in the field diff.
+ */
+struct isl_subtract_diff_collector {
+	struct isl_diff_collector dc;
+	struct isl_map *diff;
+};
+
+/* isl_subtract_diff_collector callback.
+ */
+static int basic_map_subtract_add(struct isl_diff_collector *dc,
+			    __isl_take isl_basic_map *bmap)
+{
+	struct isl_subtract_diff_collector *sdc;
+	sdc = (struct isl_subtract_diff_collector *)dc;
+
+	sdc->diff = isl_map_union_disjoint(sdc->diff,
+			isl_map_from_basic_map(bmap));
+
+	return sdc->diff ? 0 : -1;
+}
+
+/* Return the set difference between bmap and map.
+ */
+static __isl_give isl_map *basic_map_subtract(__isl_take isl_basic_map *bmap,
+	__isl_take isl_map *map)
+{
+	struct isl_subtract_diff_collector sdc;
+	sdc.dc.add = &basic_map_subtract_add;
+	sdc.diff = isl_map_empty_like_basic_map(bmap);
+	if (basic_map_collect_diff(bmap, map, &sdc.dc) < 0) {
+		isl_map_free(sdc.diff);
+		sdc.diff = NULL;
+	}
+	return sdc.diff;
+}
+
+/* Return the set difference between map1 and map2.
+ * (U_i A_i) \ (U_j B_j) is computed as U_i (A_i \ (U_j B_j))
+ *
+ * If "map1" and "map2" are disjoint, then simply return "map1".
+ */
+static __isl_give isl_map *map_subtract( __isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int i;
+	int disjoint;
+	struct isl_map *diff;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	disjoint = isl_map_is_disjoint(map1, map2);
+	if (disjoint < 0)
+		goto error;
+	if (disjoint) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	map1 = isl_map_compute_divs(map1);
+	map2 = isl_map_compute_divs(map2);
+	if (!map1 || !map2)
+		goto error;
+
+	map1 = isl_map_remove_empty_parts(map1);
+	map2 = isl_map_remove_empty_parts(map2);
+
+	diff = isl_map_empty_like(map1);
+	for (i = 0; i < map1->n; ++i) {
+		struct isl_map *d;
+		d = basic_map_subtract(isl_basic_map_copy(map1->p[i]),
+				       isl_map_copy(map2));
+		if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT))
+			diff = isl_map_union_disjoint(diff, d);
+		else
+			diff = isl_map_union(diff, d);
+	}
+
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return diff;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_subtract);
+}
+
+struct isl_set *isl_set_subtract(struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_subtract(
+			(struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+/* Remove the elements of "dom" from the domain of "map".
+ */
+static __isl_give isl_map *map_subtract_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	isl_map *ext_dom;
+
+	if (!isl_map_compatible_domain(map, dom))
+		isl_die(isl_set_get_ctx(dom), isl_error_invalid,
+			"incompatible spaces", goto error);
+	
+	ext_dom = isl_map_universe(isl_map_get_space(map));
+	ext_dom = isl_map_intersect_domain(ext_dom, dom);
+	return isl_map_subtract(map, ext_dom);
+error:
+	isl_map_free(map);
+	isl_set_free(dom);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	return isl_map_align_params_map_map_and(map, dom, &map_subtract_domain);
+}
+
+/* Remove the elements of "dom" from the range of "map".
+ */
+static __isl_give isl_map *map_subtract_range(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	isl_map *ext_dom;
+
+	if (!isl_map_compatible_range(map, dom))
+		isl_die(isl_set_get_ctx(dom), isl_error_invalid,
+			"incompatible spaces", goto error);
+	
+	ext_dom = isl_map_universe(isl_map_get_space(map));
+	ext_dom = isl_map_intersect_range(ext_dom, dom);
+	return isl_map_subtract(map, ext_dom);
+error:
+	isl_map_free(map);
+	isl_set_free(dom);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	return isl_map_align_params_map_map_and(map, dom, &map_subtract_range);
+}
+
+/* A diff collector that aborts as soon as its add function is called,
+ * setting empty to 0.
+ */
+struct isl_is_empty_diff_collector {
+	struct isl_diff_collector dc;
+	int empty;
+};
+
+/* isl_is_empty_diff_collector callback.
+ */
+static int basic_map_is_empty_add(struct isl_diff_collector *dc,
+			    __isl_take isl_basic_map *bmap)
+{
+	struct isl_is_empty_diff_collector *edc;
+	edc = (struct isl_is_empty_diff_collector *)dc;
+
+	edc->empty = 0;
+
+	isl_basic_map_free(bmap);
+	return -1;
+}
+
+/* Check if bmap \ map is empty by computing this set difference
+ * and breaking off as soon as the difference is known to be non-empty.
+ */
+static int basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_map *map)
+{
+	int r;
+	struct isl_is_empty_diff_collector edc;
+
+	r = isl_basic_map_plain_is_empty(bmap);
+	if (r)
+		return r;
+
+	edc.dc.add = &basic_map_is_empty_add;
+	edc.empty = 1;
+	r = basic_map_collect_diff(isl_basic_map_copy(bmap),
+				   isl_map_copy(map), &edc.dc);
+	if (!edc.empty)
+		return 0;
+
+	return r < 0 ? -1 : 1;
+}
+
+/* Check if map1 \ map2 is empty by checking if the set difference is empty
+ * for each of the basic maps in map1.
+ */
+static int map_diff_is_empty(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	int i;
+	int is_empty = 1;
+
+	if (!map1 || !map2)
+		return -1;
+	
+	for (i = 0; i < map1->n; ++i) {
+		is_empty = basic_map_diff_is_empty(map1->p[i], map2);
+		if (is_empty < 0 || !is_empty)
+			 break;
+	}
+
+	return is_empty;
+}
+
+/* Return 1 if "bmap" contains a single element.
+ */
+int isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	if (bmap->n_div)
+		return 0;
+	if (bmap->n_ineq)
+		return 0;
+	return bmap->n_eq == isl_basic_map_total_dim(bmap);
+}
+
+/* Return 1 if "map" contains a single element.
+ */
+int isl_map_plain_is_singleton(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	if (map->n != 1)
+		return 0;
+
+	return isl_basic_map_plain_is_singleton(map->p[0]);
+}
+
+/* Given a singleton basic map, extract the single element
+ * as an isl_point.
+ */
+static __isl_give isl_point *singleton_extract_point(
+	__isl_keep isl_basic_map *bmap)
+{
+	int j;
+	unsigned dim;
+	struct isl_vec *point;
+	isl_int m;
+
+	if (!bmap)
+		return NULL;
+
+	dim = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, bmap->n_eq == dim, return NULL);
+	point = isl_vec_alloc(bmap->ctx, 1 + dim);
+	if (!point)
+		return NULL;
+
+	isl_int_init(m);
+
+	isl_int_set_si(point->el[0], 1);
+	for (j = 0; j < bmap->n_eq; ++j) {
+		int i = dim - 1 - j;
+		isl_assert(bmap->ctx,
+		    isl_seq_first_non_zero(bmap->eq[j] + 1, i) == -1,
+		    goto error);
+		isl_assert(bmap->ctx,
+		    isl_int_is_one(bmap->eq[j][1 + i]) ||
+		    isl_int_is_negone(bmap->eq[j][1 + i]),
+		    goto error);
+		isl_assert(bmap->ctx,
+		    isl_seq_first_non_zero(bmap->eq[j]+1+i+1, dim-i-1) == -1,
+		    goto error);
+
+		isl_int_gcd(m, point->el[0], bmap->eq[j][1 + i]);
+		isl_int_divexact(m, bmap->eq[j][1 + i], m);
+		isl_int_abs(m, m);
+		isl_seq_scale(point->el, point->el, m, 1 + i);
+		isl_int_divexact(m, point->el[0], bmap->eq[j][1 + i]);
+		isl_int_neg(m, m);
+		isl_int_mul(point->el[1 + i], m, bmap->eq[j][0]);
+	}
+
+	isl_int_clear(m);
+	return isl_point_alloc(isl_basic_map_get_space(bmap), point);
+error:
+	isl_int_clear(m);
+	isl_vec_free(point);
+	return NULL;
+}
+
+/* Return 1 is the singleton map "map1" is a subset of "map2",
+ * i.e., if the single element of "map1" is also an element of "map2".
+ * Assumes "map2" has known divs.
+ */
+static int map_is_singleton_subset(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	int i;
+	int is_subset = 0;
+	struct isl_point *point;
+
+	if (!map1 || !map2)
+		return -1;
+	if (map1->n != 1)
+		return -1;
+
+	point = singleton_extract_point(map1->p[0]);
+	if (!point)
+		return -1;
+
+	for (i = 0; i < map2->n; ++i) {
+		is_subset = isl_basic_map_contains_point(map2->p[i], point);
+		if (is_subset)
+			break;
+	}
+
+	isl_point_free(point);
+	return is_subset;
+}
+
+static int map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	int is_subset = 0;
+	int empty;
+	int rat1, rat2;
+
+	if (!map1 || !map2)
+		return -1;
+
+	if (!isl_map_has_equal_space(map1, map2))
+		return 0;
+
+	empty = isl_map_is_empty(map1);
+	if (empty < 0)
+		return -1;
+	if (empty)
+		return 1;
+
+	empty = isl_map_is_empty(map2);
+	if (empty < 0)
+		return -1;
+	if (empty)
+		return 0;
+
+	rat1 = isl_map_has_rational(map1);
+	rat2 = isl_map_has_rational(map2);
+	if (rat1 < 0 || rat2 < 0)
+		return -1;
+	if (rat1 && !rat2)
+		return 0;
+
+	if (isl_map_plain_is_universe(map2))
+		return 1;
+
+	map2 = isl_map_compute_divs(isl_map_copy(map2));
+	if (isl_map_plain_is_singleton(map1)) {
+		is_subset = map_is_singleton_subset(map1, map2);
+		isl_map_free(map2);
+		return is_subset;
+	}
+	is_subset = map_diff_is_empty(map1, map2);
+	isl_map_free(map2);
+
+	return is_subset;
+}
+
+int isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	return isl_map_align_params_map_map_and_test(map1, map2,
+							&map_is_subset);
+}
+
+int isl_set_is_subset(struct isl_set *set1, struct isl_set *set2)
+{
+	return isl_map_is_subset(
+			(struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+__isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map)
+{
+	int i;
+	struct isl_subtract_diff_collector sdc;
+	sdc.dc.add = &basic_map_subtract_add;
+
+	if (!map)
+		return NULL;
+	if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
+		return map;
+	if (map->n <= 1)
+		return map;
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_remove_empty_parts(map);
+
+	if (!map || map->n <= 1)
+		return map;
+
+	sdc.diff = isl_map_from_basic_map(isl_basic_map_copy(map->p[0]));
+
+	for (i = 1; i < map->n; ++i) {
+		struct isl_basic_map *bmap = isl_basic_map_copy(map->p[i]);
+		struct isl_map *copy = isl_map_copy(sdc.diff);
+		if (basic_map_collect_diff(bmap, copy, &sdc.dc) < 0) {
+			isl_map_free(sdc.diff);
+			sdc.diff = NULL;
+			break;
+		}
+	}
+
+	isl_map_free(map);
+
+	return sdc.diff;
+}
+
+__isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set)
+{
+	return (struct isl_set *)isl_map_make_disjoint((struct isl_map *)set);
+}
+
+__isl_give isl_map *isl_map_complement(__isl_take isl_map *map)
+{
+	isl_map *universe;
+
+	if (!map)
+		return NULL;
+
+	universe = isl_map_universe(isl_map_get_space(map));
+
+	return isl_map_subtract(universe, map);
+}
+
+__isl_give isl_set *isl_set_complement(__isl_take isl_set *set)
+{
+	return isl_map_complement(set);
+}

Added: polly/trunk/lib/External/isl/isl_map_to_basic_set.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_to_basic_set.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_to_basic_set.c (added)
+++ polly/trunk/lib/External/isl/isl_map_to_basic_set.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,10 @@
+#include <isl/map_to_basic_set.h>
+#include <isl/map.h>
+#include <isl/set.h>
+
+#define KEY_BASE	map
+#define KEY_EQUAL	isl_map_plain_is_equal
+#define VAL_BASE	basic_set
+#define VAL_EQUAL	isl_basic_set_plain_is_equal
+
+#include <isl_hmap_templ.c>

Added: polly/trunk/lib/External/isl/isl_mat.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_mat.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_mat.c (added)
+++ polly/trunk/lib/External/isl/isl_mat.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1742 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2014      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 Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/space.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_space_private.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/mat_int.h>
+
+isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->ctx : NULL;
+}
+
+struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_col)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_alloc_type(ctx, struct isl_mat);
+	if (!mat)
+		return NULL;
+
+	mat->row = NULL;
+	mat->block = isl_blk_alloc(ctx, n_row * n_col);
+	if (isl_blk_is_error(mat->block))
+		goto error;
+	mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+	if (n_row && !mat->row)
+		goto error;
+
+	for (i = 0; i < n_row; ++i)
+		mat->row[i] = mat->block.data + i * n_col;
+
+	mat->ctx = ctx;
+	isl_ctx_ref(ctx);
+	mat->ref = 1;
+	mat->n_row = n_row;
+	mat->n_col = n_col;
+	mat->max_col = n_col;
+	mat->flags = 0;
+
+	return mat;
+error:
+	isl_blk_free(ctx, mat->block);
+	free(mat);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_extend(struct isl_mat *mat,
+	unsigned n_row, unsigned n_col)
+{
+	int i;
+	isl_int *old;
+	isl_int **row;
+
+	if (!mat)
+		return NULL;
+
+	if (mat->max_col >= n_col && mat->n_row >= n_row) {
+		if (mat->n_col < n_col)
+			mat->n_col = n_col;
+		return mat;
+	}
+
+	if (mat->max_col < n_col) {
+		struct isl_mat *new_mat;
+
+		if (n_row < mat->n_row)
+			n_row = mat->n_row;
+		new_mat = isl_mat_alloc(mat->ctx, n_row, n_col);
+		if (!new_mat)
+			goto error;
+		for (i = 0; i < mat->n_row; ++i)
+			isl_seq_cpy(new_mat->row[i], mat->row[i], mat->n_col);
+		isl_mat_free(mat);
+		return new_mat;
+	}
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		goto error;
+
+	old = mat->block.data;
+	mat->block = isl_blk_extend(mat->ctx, mat->block, n_row * mat->max_col);
+	if (isl_blk_is_error(mat->block))
+		goto error;
+	row = isl_realloc_array(mat->ctx, mat->row, isl_int *, n_row);
+	if (n_row && !row)
+		goto error;
+	mat->row = row;
+
+	for (i = 0; i < mat->n_row; ++i)
+		mat->row[i] = mat->block.data + (mat->row[i] - old);
+	for (i = mat->n_row; i < n_row; ++i)
+		mat->row[i] = mat->block.data + i * mat->max_col;
+	mat->n_row = n_row;
+	if (mat->n_col < n_col)
+		mat->n_col = n_col;
+
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_alloc_type(ctx, struct isl_mat);
+	if (!mat)
+		return NULL;
+	mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+	if (n_row && !mat->row)
+		goto error;
+	for (i = 0; i < n_row; ++i)
+		mat->row[i] = row[first_row+i] + first_col;
+	mat->ctx = ctx;
+	isl_ctx_ref(ctx);
+	mat->ref = 1;
+	mat->n_row = n_row;
+	mat->n_col = n_col;
+	mat->block = isl_blk_empty();
+	mat->flags = ISL_MAT_BORROWED;
+	return mat;
+error:
+	free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+	if (!mat)
+		return NULL;
+	return isl_mat_sub_alloc6(mat->ctx, mat->row, first_row, n_row,
+				  first_col, n_col);
+}
+
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+struct isl_mat *isl_mat_copy(struct isl_mat *mat)
+{
+	if (!mat)
+		return NULL;
+
+	mat->ref++;
+	return mat;
+}
+
+struct isl_mat *isl_mat_dup(struct isl_mat *mat)
+{
+	int i;
+	struct isl_mat *mat2;
+
+	if (!mat)
+		return NULL;
+	mat2 = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
+	if (!mat2)
+		return NULL;
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col);
+	return mat2;
+}
+
+struct isl_mat *isl_mat_cow(struct isl_mat *mat)
+{
+	struct isl_mat *mat2;
+	if (!mat)
+		return NULL;
+
+	if (mat->ref == 1 && !ISL_F_ISSET(mat, ISL_MAT_BORROWED))
+		return mat;
+
+	mat2 = isl_mat_dup(mat);
+	isl_mat_free(mat);
+	return mat2;
+}
+
+__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat)
+{
+	if (!mat)
+		return NULL;
+
+	if (--mat->ref > 0)
+		return NULL;
+
+	if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED))
+		isl_blk_free(mat->ctx, mat->block);
+	isl_ctx_deref(mat->ctx);
+	free(mat->row);
+	free(mat);
+
+	return NULL;
+}
+
+int isl_mat_rows(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->n_row : -1;
+}
+
+int isl_mat_cols(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->n_col : -1;
+}
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v)
+{
+	if (!mat)
+		return -1;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			return -1);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			return -1);
+	isl_int_set(*v, mat->row[row][col]);
+	return 0;
+}
+
+/* Extract the element at row "row", oolumn "col" of "mat".
+ */
+__isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat,
+	int row, int col)
+{
+	isl_ctx *ctx;
+
+	if (!mat)
+		return NULL;
+	ctx = isl_mat_get_ctx(mat);
+	if (row < 0 || row >= mat->n_row)
+		isl_die(ctx, isl_error_invalid, "row out of range",
+			return NULL);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(ctx, isl_error_invalid, "column out of range",
+			return NULL);
+	return isl_val_int_from_isl_int(ctx, mat->row[row][col]);
+}
+
+__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
+	int row, int col, isl_int v)
+{
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			goto error);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			goto error);
+	isl_int_set(mat->row[row][col], v);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+	int row, int col, int v)
+{
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			goto error);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			goto error);
+	isl_int_set_si(mat->row[row][col], v);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Replace the element at row "row", column "col" of "mat" by "v".
+ */
+__isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat,
+	int row, int col, __isl_take isl_val *v)
+{
+	if (!v)
+		return isl_mat_free(mat);
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting integer value", goto error);
+	mat = isl_mat_set_element(mat, row, col, v->n);
+	isl_val_free(v);
+	return mat;
+error:
+	isl_val_free(v);
+	return isl_mat_free(mat);
+}
+
+__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_mat_alloc(ctx, n_row, n_row);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < n_row; ++i) {
+		isl_seq_clr(mat->row[i], i);
+		isl_int_set(mat->row[i][i], d);
+		isl_seq_clr(mat->row[i]+i+1, n_row-(i+1));
+	}
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_identity(isl_ctx *ctx, unsigned n_row)
+{
+	if (!ctx)
+		return NULL;
+	return isl_mat_diag(ctx, n_row, ctx->one);
+}
+
+/* Is "mat" a (possibly scaled) identity matrix?
+ */
+int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat)
+{
+	int i;
+
+	if (!mat)
+		return -1;
+	if (mat->n_row != mat->n_col)
+		return 0;
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (isl_seq_first_non_zero(mat->row[i], i) != -1)
+			return 0;
+		if (isl_int_ne(mat->row[0][0], mat->row[i][i]))
+			return 0;
+		if (isl_seq_first_non_zero(mat->row[i] + i + 1,
+					    mat->n_col - (i + 1)) != -1)
+			return 0;
+	}
+
+	return 1;
+}
+
+struct isl_vec *isl_mat_vec_product(struct isl_mat *mat, struct isl_vec *vec)
+{
+	int i;
+	struct isl_vec *prod;
+
+	if (!mat || !vec)
+		goto error;
+
+	isl_assert(mat->ctx, mat->n_col == vec->size, goto error);
+
+	prod = isl_vec_alloc(mat->ctx, mat->n_row);
+	if (!prod)
+		goto error;
+
+	for (i = 0; i < prod->size; ++i)
+		isl_seq_inner_product(mat->row[i], vec->el, vec->size,
+					&prod->block.data[i]);
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return prod;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat,
+	__isl_take isl_vec *vec)
+{
+	struct isl_mat *vec_mat;
+	int i;
+
+	if (!mat || !vec)
+		goto error;
+	vec_mat = isl_mat_alloc(vec->ctx, vec->size, 1);
+	if (!vec_mat)
+		goto error;
+	for (i = 0; i < vec->size; ++i)
+		isl_int_set(vec_mat->row[i][0], vec->el[i]);
+	vec_mat = isl_mat_inverse_product(mat, vec_mat);
+	isl_vec_free(vec);
+	if (!vec_mat)
+		return NULL;
+	vec = isl_vec_alloc(vec_mat->ctx, vec_mat->n_row);
+	if (vec)
+		for (i = 0; i < vec->size; ++i)
+			isl_int_set(vec->el[i], vec_mat->row[i][0]);
+	isl_mat_free(vec_mat);
+	return vec;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+struct isl_vec *isl_vec_mat_product(struct isl_vec *vec, struct isl_mat *mat)
+{
+	int i, j;
+	struct isl_vec *prod;
+
+	if (!mat || !vec)
+		goto error;
+
+	isl_assert(mat->ctx, mat->n_row == vec->size, goto error);
+
+	prod = isl_vec_alloc(mat->ctx, mat->n_col);
+	if (!prod)
+		goto error;
+
+	for (i = 0; i < prod->size; ++i) {
+		isl_int_set_si(prod->el[i], 0);
+		for (j = 0; j < vec->size; ++j)
+			isl_int_addmul(prod->el[i], vec->el[j], mat->row[j][i]);
+	}
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return prod;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_aff_direct_sum(struct isl_mat *left,
+	struct isl_mat *right)
+{
+	int i;
+	struct isl_mat *sum;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, left->n_row == right->n_row, goto error);
+	isl_assert(left->ctx, left->n_row >= 1, goto error);
+	isl_assert(left->ctx, left->n_col >= 1, goto error);
+	isl_assert(left->ctx, right->n_col >= 1, goto error);
+	isl_assert(left->ctx,
+	    isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1,
+	    goto error);
+	isl_assert(left->ctx,
+	    isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1,
+	    goto error);
+
+	sum = isl_mat_alloc(left->ctx, left->n_row, left->n_col + right->n_col - 1);
+	if (!sum)
+		goto error;
+	isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]);
+	isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+	isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+
+	isl_seq_clr(sum->row[0]+1, sum->n_col-1);
+	for (i = 1; i < sum->n_row; ++i) {
+		isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]);
+		isl_int_addmul(sum->row[i][0],
+				right->row[0][0], right->row[i][0]);
+		isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0],
+				left->n_col-1);
+		isl_seq_scale(sum->row[i]+left->n_col,
+				right->row[i]+1, right->row[0][0],
+				right->n_col-1);
+	}
+
+	isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+	isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return sum;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+static void exchange(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned i, unsigned j)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_swap(M->row[r][i], M->row[r][j]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_swap((*U)->row[r][i], (*U)->row[r][j]);
+	}
+	if (Q)
+		isl_mat_swap_rows(*Q, i, j);
+}
+
+static void subtract(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned i, unsigned j, isl_int m)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_submul(M->row[r][j], m, M->row[r][i]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]);
+	}
+	if (Q) {
+		for (r = 0; r < (*Q)->n_col; ++r)
+			isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]);
+	}
+}
+
+static void oppose(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned col)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_neg(M->row[r][col], M->row[r][col]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_neg((*U)->row[r][col], (*U)->row[r][col]);
+	}
+	if (Q)
+		isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col);
+}
+
+/* Given matrix M, compute
+ *
+ *		M U = H
+ *		M   = H Q
+ *
+ * with U and Q unimodular matrices and H a matrix in column echelon form
+ * such that on each echelon row the entries in the non-echelon column
+ * are non-negative (if neg == 0) or non-positive (if neg == 1)
+ * and strictly smaller (in absolute value) than the entries in the echelon
+ * column.
+ * If U or Q are NULL, then these matrices are not computed.
+ */
+struct isl_mat *isl_mat_left_hermite(struct isl_mat *M, int neg,
+	struct isl_mat **U, struct isl_mat **Q)
+{
+	isl_int c;
+	int row, col;
+
+	if (U)
+		*U = NULL;
+	if (Q)
+		*Q = NULL;
+	if (!M)
+		goto error;
+	M = isl_mat_cow(M);
+	if (!M)
+		goto error;
+	if (U) {
+		*U = isl_mat_identity(M->ctx, M->n_col);
+		if (!*U)
+			goto error;
+	}
+	if (Q) {
+		*Q = isl_mat_identity(M->ctx, M->n_col);
+		if (!*Q)
+			goto error;
+	}
+
+	col = 0;
+	isl_int_init(c);
+	for (row = 0; row < M->n_row; ++row) {
+		int first, i, off;
+		first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col);
+		if (first == -1)
+			continue;
+		first += col;
+		if (first != col)
+			exchange(M, U, Q, row, first, col);
+		if (isl_int_is_neg(M->row[row][col]))
+			oppose(M, U, Q, row, col);
+		first = col+1;
+		while ((off = isl_seq_first_non_zero(M->row[row]+first,
+						       M->n_col-first)) != -1) {
+			first += off;
+			isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]);
+			subtract(M, U, Q, row, col, first, c);
+			if (!isl_int_is_zero(M->row[row][first]))
+				exchange(M, U, Q, row, first, col);
+			else
+				++first;
+		}
+		for (i = 0; i < col; ++i) {
+			if (isl_int_is_zero(M->row[row][i]))
+				continue;
+			if (neg)
+				isl_int_cdiv_q(c, M->row[row][i], M->row[row][col]);
+			else
+				isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]);
+			if (isl_int_is_zero(c))
+				continue;
+			subtract(M, U, Q, row, col, i, c);
+		}
+		++col;
+	}
+	isl_int_clear(c);
+
+	return M;
+error:
+	if (Q) {
+		isl_mat_free(*Q);
+		*Q = NULL;
+	}
+	if (U) {
+		isl_mat_free(*U);
+		*U = NULL;
+	}
+	isl_mat_free(M);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_right_kernel(struct isl_mat *mat)
+{
+	int i, rank;
+	struct isl_mat *U = NULL;
+	struct isl_mat *K;
+
+	mat = isl_mat_left_hermite(mat, 0, &U, NULL);
+	if (!mat || !U)
+		goto error;
+
+	for (i = 0, rank = 0; rank < mat->n_col; ++rank) {
+		while (i < mat->n_row && isl_int_is_zero(mat->row[i][rank]))
+			++i;
+		if (i >= mat->n_row)
+			break;
+	}
+	K = isl_mat_alloc(U->ctx, U->n_row, U->n_col - rank);
+	if (!K)
+		goto error;
+	isl_mat_sub_copy(K->ctx, K->row, U->row, U->n_row, 0, rank, U->n_col-rank);
+	isl_mat_free(mat);
+	isl_mat_free(U);
+	return K;
+error:
+	isl_mat_free(mat);
+	isl_mat_free(U);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_lin_to_aff(struct isl_mat *mat)
+{
+	int i;
+	struct isl_mat *mat2;
+
+	if (!mat)
+		return NULL;
+	mat2 = isl_mat_alloc(mat->ctx, 1+mat->n_row, 1+mat->n_col);
+	if (!mat2)
+		goto error;
+	isl_int_set_si(mat2->row[0][0], 1);
+	isl_seq_clr(mat2->row[0]+1, mat->n_col);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_int_set_si(mat2->row[1+i][0], 0);
+		isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col);
+	}
+	isl_mat_free(mat);
+	return mat2;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Given two matrices M1 and M2, return the block matrix
+ *
+ *	[ M1  0  ]
+ *	[ 0   M2 ]
+ */
+__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1,
+	__isl_take isl_mat *mat2)
+{
+	int i;
+	isl_mat *mat;
+
+	if (!mat1 || !mat2)
+		goto error;
+
+	mat = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
+				       mat1->n_col + mat2->n_col);
+	if (!mat)
+		goto error;
+	for (i = 0; i < mat1->n_row; ++i) {
+		isl_seq_cpy(mat->row[i], mat1->row[i], mat1->n_col);
+		isl_seq_clr(mat->row[i] + mat1->n_col, mat2->n_col);
+	}
+	for (i = 0; i < mat2->n_row; ++i) {
+		isl_seq_clr(mat->row[mat1->n_row + i], mat1->n_col);
+		isl_seq_cpy(mat->row[mat1->n_row + i] + mat1->n_col,
+						    mat2->row[i], mat2->n_col);
+	}
+	isl_mat_free(mat1);
+	isl_mat_free(mat2);
+	return mat;
+error:
+	isl_mat_free(mat1);
+	isl_mat_free(mat2);
+	return NULL;
+}
+
+static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		if (!isl_int_is_zero(row[i][col]))
+			return i;
+	return -1;
+}
+
+static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+	int i, min = row_first_non_zero(row, n_row, col);
+	if (min < 0)
+		return -1;
+	for (i = min + 1; i < n_row; ++i) {
+		if (isl_int_is_zero(row[i][col]))
+			continue;
+		if (isl_int_abs_lt(row[i][col], row[min][col]))
+			min = i;
+	}
+	return min;
+}
+
+static void inv_exchange(struct isl_mat *left, struct isl_mat *right,
+	unsigned i, unsigned j)
+{
+	left = isl_mat_swap_rows(left, i, j);
+	right = isl_mat_swap_rows(right, i, j);
+}
+
+static void inv_oppose(
+	struct isl_mat *left, struct isl_mat *right, unsigned row)
+{
+	isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row);
+	isl_seq_neg(right->row[row], right->row[row], right->n_col);
+}
+
+static void inv_subtract(struct isl_mat *left, struct isl_mat *right,
+	unsigned row, unsigned i, isl_int m)
+{
+	isl_int_neg(m, m);
+	isl_seq_combine(left->row[i]+row,
+			left->ctx->one, left->row[i]+row,
+			m, left->row[row]+row,
+			left->n_col-row);
+	isl_seq_combine(right->row[i], right->ctx->one, right->row[i],
+			m, right->row[row], right->n_col);
+}
+
+/* Compute inv(left)*right
+ */
+struct isl_mat *isl_mat_inverse_product(struct isl_mat *left,
+	struct isl_mat *right)
+{
+	int row;
+	isl_int a, b;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, left->n_row == left->n_col, goto error);
+	isl_assert(left->ctx, left->n_row == right->n_row, goto error);
+
+	if (left->n_row == 0) {
+		isl_mat_free(left);
+		return right;
+	}
+
+	left = isl_mat_cow(left);
+	right = isl_mat_cow(right);
+	if (!left || !right)
+		goto error;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (row = 0; row < left->n_row; ++row) {
+		int pivot, first, i, off;
+		pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row);
+		if (pivot < 0) {
+			isl_int_clear(a);
+			isl_int_clear(b);
+			isl_assert(left->ctx, pivot >= 0, goto error);
+		}
+		pivot += row;
+		if (pivot != row)
+			inv_exchange(left, right, pivot, row);
+		if (isl_int_is_neg(left->row[row][row]))
+			inv_oppose(left, right, row);
+		first = row+1;
+		while ((off = row_first_non_zero(left->row+first,
+					left->n_row-first, row)) != -1) {
+			first += off;
+			isl_int_fdiv_q(a, left->row[first][row],
+					left->row[row][row]);
+			inv_subtract(left, right, row, first, a);
+			if (!isl_int_is_zero(left->row[first][row]))
+				inv_exchange(left, right, row, first);
+			else
+				++first;
+		}
+		for (i = 0; i < row; ++i) {
+			if (isl_int_is_zero(left->row[i][row]))
+				continue;
+			isl_int_gcd(a, left->row[row][row], left->row[i][row]);
+			isl_int_divexact(b, left->row[i][row], a);
+			isl_int_divexact(a, left->row[row][row], a);
+			isl_int_neg(b, b);
+			isl_seq_combine(left->row[i] + i,
+					a, left->row[i] + i,
+					b, left->row[row] + i,
+					left->n_col - i);
+			isl_seq_combine(right->row[i], a, right->row[i],
+					b, right->row[row], right->n_col);
+		}
+	}
+	isl_int_clear(b);
+
+	isl_int_set(a, left->row[0][0]);
+	for (row = 1; row < left->n_row; ++row)
+		isl_int_lcm(a, a, left->row[row][row]);
+	if (isl_int_is_zero(a)){
+		isl_int_clear(a);
+		isl_assert(left->ctx, 0, goto error);
+	}
+	for (row = 0; row < left->n_row; ++row) {
+		isl_int_divexact(left->row[row][row], a, left->row[row][row]);
+		if (isl_int_is_one(left->row[row][row]))
+			continue;
+		isl_seq_scale(right->row[row], right->row[row],
+				left->row[row][row], right->n_col);
+	}
+	isl_int_clear(a);
+
+	isl_mat_free(left);
+	return right;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+void isl_mat_col_scale(struct isl_mat *mat, unsigned col, isl_int m)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_mul(mat->row[i][col], mat->row[i][col], m);
+}
+
+void isl_mat_col_combine(struct isl_mat *mat, unsigned dst,
+	isl_int m1, unsigned src1, isl_int m2, unsigned src2)
+{
+	int i;
+	isl_int tmp;
+
+	isl_int_init(tmp);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_int_mul(tmp, m1, mat->row[i][src1]);
+		isl_int_addmul(tmp, m2, mat->row[i][src2]);
+		isl_int_set(mat->row[i][dst], tmp);
+	}
+	isl_int_clear(tmp);
+}
+
+struct isl_mat *isl_mat_right_inverse(struct isl_mat *mat)
+{
+	struct isl_mat *inv;
+	int row;
+	isl_int a, b;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	inv = isl_mat_identity(mat->ctx, mat->n_col);
+	inv = isl_mat_cow(inv);
+	if (!inv)
+		goto error;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (row = 0; row < mat->n_row; ++row) {
+		int pivot, first, i, off;
+		pivot = isl_seq_abs_min_non_zero(mat->row[row]+row, mat->n_col-row);
+		if (pivot < 0) {
+			isl_int_clear(a);
+			isl_int_clear(b);
+			isl_assert(mat->ctx, pivot >= 0, goto error);
+		}
+		pivot += row;
+		if (pivot != row)
+			exchange(mat, &inv, NULL, row, pivot, row);
+		if (isl_int_is_neg(mat->row[row][row]))
+			oppose(mat, &inv, NULL, row, row);
+		first = row+1;
+		while ((off = isl_seq_first_non_zero(mat->row[row]+first,
+						    mat->n_col-first)) != -1) {
+			first += off;
+			isl_int_fdiv_q(a, mat->row[row][first],
+						    mat->row[row][row]);
+			subtract(mat, &inv, NULL, row, row, first, a);
+			if (!isl_int_is_zero(mat->row[row][first]))
+				exchange(mat, &inv, NULL, row, row, first);
+			else
+				++first;
+		}
+		for (i = 0; i < row; ++i) {
+			if (isl_int_is_zero(mat->row[row][i]))
+				continue;
+			isl_int_gcd(a, mat->row[row][row], mat->row[row][i]);
+			isl_int_divexact(b, mat->row[row][i], a);
+			isl_int_divexact(a, mat->row[row][row], a);
+			isl_int_neg(a, a);
+			isl_mat_col_combine(mat, i, a, i, b, row);
+			isl_mat_col_combine(inv, i, a, i, b, row);
+		}
+	}
+	isl_int_clear(b);
+
+	isl_int_set(a, mat->row[0][0]);
+	for (row = 1; row < mat->n_row; ++row)
+		isl_int_lcm(a, a, mat->row[row][row]);
+	if (isl_int_is_zero(a)){
+		isl_int_clear(a);
+		goto error;
+	}
+	for (row = 0; row < mat->n_row; ++row) {
+		isl_int_divexact(mat->row[row][row], a, mat->row[row][row]);
+		if (isl_int_is_one(mat->row[row][row]))
+			continue;
+		isl_mat_col_scale(inv, row, mat->row[row][row]);
+	}
+	isl_int_clear(a);
+
+	isl_mat_free(mat);
+
+	return inv;
+error:
+	isl_mat_free(mat);
+	isl_mat_free(inv);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_transpose(struct isl_mat *mat)
+{
+	struct isl_mat *transpose = NULL;
+	int i, j;
+
+	if (!mat)
+		return NULL;
+
+	if (mat->n_col == mat->n_row) {
+		mat = isl_mat_cow(mat);
+		if (!mat)
+			return NULL;
+		for (i = 0; i < mat->n_row; ++i)
+			for (j = i + 1; j < mat->n_col; ++j)
+				isl_int_swap(mat->row[i][j], mat->row[j][i]);
+		return mat;
+	}
+	transpose = isl_mat_alloc(mat->ctx, mat->n_col, mat->n_row);
+	if (!transpose)
+		goto error;
+	for (i = 0; i < mat->n_row; ++i)
+		for (j = 0; j < mat->n_col; ++j)
+			isl_int_set(transpose->row[j][i], mat->row[i][j]);
+	isl_mat_free(mat);
+	return transpose;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_swap_cols(struct isl_mat *mat, unsigned i, unsigned j)
+{
+	int r;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	isl_assert(mat->ctx, i < mat->n_col, goto error);
+	isl_assert(mat->ctx, j < mat->n_col, goto error);
+
+	for (r = 0; r < mat->n_row; ++r)
+		isl_int_swap(mat->row[r][i], mat->row[r][j]);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_swap_rows(struct isl_mat *mat, unsigned i, unsigned j)
+{
+	isl_int *t;
+
+	if (!mat)
+		return NULL;
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	t = mat->row[i];
+	mat->row[i] = mat->row[j];
+	mat->row[j] = t;
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right)
+{
+	int i, j, k;
+	struct isl_mat *prod;
+
+	if (!left || !right)
+		goto error;
+	isl_assert(left->ctx, left->n_col == right->n_row, goto error);
+	prod = isl_mat_alloc(left->ctx, left->n_row, right->n_col);
+	if (!prod)
+		goto error;
+	if (left->n_col == 0) {
+		for (i = 0; i < prod->n_row; ++i)
+			isl_seq_clr(prod->row[i], prod->n_col);
+		isl_mat_free(left);
+		isl_mat_free(right);
+		return prod;
+	}
+	for (i = 0; i < prod->n_row; ++i) {
+		for (j = 0; j < prod->n_col; ++j) {
+			isl_int_mul(prod->row[i][j],
+				    left->row[i][0], right->row[0][j]);
+			for (k = 1; k < left->n_col; ++k)
+				isl_int_addmul(prod->row[i][j],
+					    left->row[i][k], right->row[k][j]);
+		}
+	}
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return prod;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+/* Replace the variables x in the rows q by x' given by x = M x',
+ * with M the matrix mat.
+ *
+ * If the number of new variables is greater than the original
+ * number of variables, then the rows q have already been
+ * preextended.  If the new number is smaller, then the coefficients
+ * of the divs, which are not changed, need to be shifted down.
+ * The row q may be the equalities, the inequalities or the
+ * div expressions.  In the latter case, has_div is true and
+ * we need to take into account the extra denominator column.
+ */
+static int preimage(struct isl_ctx *ctx, isl_int **q, unsigned n,
+	unsigned n_div, int has_div, struct isl_mat *mat)
+{
+	int i;
+	struct isl_mat *t;
+	int e;
+
+	if (mat->n_col >= mat->n_row)
+		e = 0;
+	else
+		e = mat->n_row - mat->n_col;
+	if (has_div)
+		for (i = 0; i < n; ++i)
+			isl_int_mul(q[i][0], q[i][0], mat->row[0][0]);
+	t = isl_mat_sub_alloc6(mat->ctx, q, 0, n, has_div, mat->n_row);
+	t = isl_mat_product(t, mat);
+	if (!t)
+		return -1;
+	for (i = 0; i < n; ++i) {
+		isl_seq_swp_or_cpy(q[i] + has_div, t->row[i], t->n_col);
+		isl_seq_cpy(q[i] + has_div + t->n_col,
+			    q[i] + has_div + t->n_col + e, n_div);
+		isl_seq_clr(q[i] + has_div + t->n_col + n_div, e);
+	}
+	isl_mat_free(t);
+	return 0;
+}
+
+/* Replace the variables x in bset by x' given by x = M x', with
+ * M the matrix mat.
+ *
+ * If there are fewer variables x' then there are x, then we perform
+ * the transformation in place, which that, 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_preimage(struct isl_basic_set *bset,
+	struct isl_mat *mat)
+{
+	struct isl_ctx *ctx;
+
+	if (!bset || !mat)
+		goto error;
+
+	ctx = bset->ctx;
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+
+	isl_assert(ctx, bset->dim->nparam == 0, goto error);
+	isl_assert(ctx, 1+bset->dim->n_out == mat->n_row, goto error);
+	isl_assert(ctx, mat->n_col > 0, goto error);
+
+	if (mat->n_col > mat->n_row) {
+		bset = isl_basic_set_extend(bset, 0, mat->n_col-1, 0, 0, 0);
+		if (!bset)
+			goto error;
+	} else if (mat->n_col < mat->n_row) {
+		bset->dim = isl_space_cow(bset->dim);
+		if (!bset->dim)
+			goto error;
+		bset->dim->n_out -= mat->n_row - mat->n_col;
+	}
+
+	if (preimage(ctx, bset->eq, bset->n_eq, bset->n_div, 0,
+			isl_mat_copy(mat)) < 0)
+		goto error;
+
+	if (preimage(ctx, bset->ineq, bset->n_ineq, bset->n_div, 0,
+			isl_mat_copy(mat)) < 0)
+		goto error;
+
+	if (preimage(ctx, bset->div, bset->n_div, bset->n_div, 1, mat) < 0)
+		goto error2;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
+	ISL_F_CLR(bset, ISL_BASIC_SET_ALL_EQUALITIES);
+
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_mat_free(mat);
+error2:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat)
+{
+	struct isl_ctx *ctx;
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	ctx = set->ctx;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_preimage(set->p[i],
+						    isl_mat_copy(mat));
+		if (!set->p[i])
+			goto error;
+	}
+	if (mat->n_col != mat->n_row) {
+		set->dim = isl_space_cow(set->dim);
+		if (!set->dim)
+			goto error;
+		set->dim->n_out += mat->n_col;
+		set->dim->n_out -= mat->n_row;
+	}
+	isl_mat_free(mat);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_set_free(set);
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Replace the variables x starting at pos in the rows q
+ * by x' with x = M x' with M the matrix mat.
+ * That is, replace the corresponding coefficients c by c M.
+ */
+static int transform(isl_ctx *ctx, isl_int **q, unsigned n,
+	unsigned pos, __isl_take isl_mat *mat)
+{
+	int i;
+	isl_mat *t;
+
+	t = isl_mat_sub_alloc6(ctx, q, 0, n, pos, mat->n_row);
+	t = isl_mat_product(t, mat);
+	if (!t)
+		return -1;
+	for (i = 0; i < n; ++i)
+		isl_seq_swp_or_cpy(q[i] + pos, t->row[i], t->n_col);
+	isl_mat_free(t);
+	return 0;
+}
+
+/* Replace the variables x of type "type" starting at "first" in "bset"
+ * by x' with x = M x' with M the matrix trans.
+ * That is, replace the corresponding coefficients c by c M.
+ *
+ * The transformation matrix should be a square matrix.
+ */
+__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_ctx *ctx;
+	unsigned pos;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !trans)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (trans->n_row != trans->n_col)
+		isl_die(trans->ctx, isl_error_invalid,
+			"expecting square transformation matrix", goto error);
+	if (first + trans->n_row > isl_basic_set_dim(bset, type))
+		isl_die(trans->ctx, isl_error_invalid,
+			"oversized transformation matrix", goto error);
+
+	pos = isl_basic_set_offset(bset, type) + first;
+
+	if (transform(ctx, bset->eq, bset->n_eq, pos, isl_mat_copy(trans)) < 0)
+		goto error;
+	if (transform(ctx, bset->ineq, bset->n_ineq, pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+	if (transform(ctx, bset->div, bset->n_div, 1 + pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
+
+	isl_mat_free(trans);
+	return bset;
+error:
+	isl_mat_free(trans);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent)
+{
+	int i, j;
+
+	if (!mat) {
+		fprintf(out, "%*snull mat\n", indent, "");
+		return;
+	}
+
+	if (mat->n_row == 0)
+		fprintf(out, "%*s[]\n", indent, "");
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (!i)
+			fprintf(out, "%*s[[", indent, "");
+		else
+			fprintf(out, "%*s[", indent+1, "");
+		for (j = 0; j < mat->n_col; ++j) {
+			if (j)
+			    fprintf(out, ",");
+			isl_int_print(out, mat->row[i][j], 0);
+		}
+		if (i == mat->n_row-1)
+			fprintf(out, "]]\n");
+		else
+			fprintf(out, "]\n");
+	}
+}
+
+void isl_mat_dump(__isl_keep isl_mat *mat)
+{
+	isl_mat_print_internal(mat, stderr, 0);
+}
+
+struct isl_mat *isl_mat_drop_cols(struct isl_mat *mat, unsigned col, unsigned n)
+{
+	int r;
+
+	if (n == 0)
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	if (col != mat->n_col-n) {
+		for (r = 0; r < mat->n_row; ++r)
+			isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+n,
+					mat->n_col - col - n);
+	}
+	mat->n_col -= n;
+	return mat;
+}
+
+struct isl_mat *isl_mat_drop_rows(struct isl_mat *mat, unsigned row, unsigned n)
+{
+	int r;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	for (r = row; r+n < mat->n_row; ++r)
+		mat->row[r] = mat->row[r+n];
+
+	mat->n_row -= n;
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat,
+				unsigned col, unsigned n)
+{
+	isl_mat *ext;
+
+	if (!mat)
+		return NULL;
+	if (n == 0)
+		return mat;
+
+	ext = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col + n);
+	if (!ext)
+		goto error;
+
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row, 0, 0, col);
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row,
+				col + n, col, mat->n_col - col);
+
+	isl_mat_free(mat);
+	return ext;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat,
+	unsigned first, unsigned n)
+{
+	int i;
+
+	if (!mat)
+		return NULL;
+	mat = isl_mat_insert_cols(mat, first, n);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_clr(mat->row[i] + first, n);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_zero_cols(mat, mat->n_col, n);
+}
+
+__isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat,
+				unsigned row, unsigned n)
+{
+	isl_mat *ext;
+
+	if (!mat)
+		return NULL;
+	if (n == 0)
+		return mat;
+
+	ext = isl_mat_alloc(mat->ctx, mat->n_row + n, mat->n_col);
+	if (!ext)
+		goto error;
+
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, row, 0, 0, mat->n_col);
+	isl_mat_sub_copy(mat->ctx, ext->row + row + n, mat->row + row,
+				mat->n_row - row, 0, 0, mat->n_col);
+
+	isl_mat_free(mat);
+	return ext;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_rows(mat, mat->n_row, n);
+}
+
+__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
+	unsigned row, unsigned n)
+{
+	int i;
+
+	mat = isl_mat_insert_rows(mat, row, n);
+	if (!mat)
+		return NULL;
+	
+	for (i = 0; i < n; ++i)
+		isl_seq_clr(mat->row[row + i], mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_zero_rows(mat, mat->n_row, n);
+}
+
+void isl_mat_col_submul(struct isl_mat *mat,
+			int dst_col, isl_int f, int src_col)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_submul(mat->row[i][dst_col], f, mat->row[i][src_col]);
+}
+
+void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col)
+{
+	int i;
+
+	if (!mat)
+		return;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_add(mat->row[i][dst_col],
+			    mat->row[i][dst_col], mat->row[i][src_col]);
+}
+
+void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_mul(mat->row[i][dst_col], f, mat->row[i][src_col]);
+}
+
+struct isl_mat *isl_mat_unimodular_complete(struct isl_mat *M, int row)
+{
+	int r;
+	struct isl_mat *H = NULL, *Q = NULL;
+
+	if (!M)
+		return NULL;
+
+	isl_assert(M->ctx, M->n_row == M->n_col, goto error);
+	M->n_row = row;
+	H = isl_mat_left_hermite(isl_mat_copy(M), 0, NULL, &Q);
+	M->n_row = M->n_col;
+	if (!H)
+		goto error;
+	for (r = 0; r < row; ++r)
+		isl_assert(M->ctx, isl_int_is_one(H->row[r][r]), goto error);
+	for (r = row; r < M->n_row; ++r)
+		isl_seq_cpy(M->row[r], Q->row[r], M->n_col);
+	isl_mat_free(H);
+	isl_mat_free(Q);
+	return M;
+error:
+	isl_mat_free(H);
+	isl_mat_free(Q);
+	isl_mat_free(M);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top,
+	__isl_take isl_mat *bot)
+{
+	struct isl_mat *mat;
+
+	if (!top || !bot)
+		goto error;
+
+	isl_assert(top->ctx, top->n_col == bot->n_col, goto error);
+	if (top->n_row == 0) {
+		isl_mat_free(top);
+		return bot;
+	}
+	if (bot->n_row == 0) {
+		isl_mat_free(bot);
+		return top;
+	}
+
+	mat = isl_mat_alloc(top->ctx, top->n_row + bot->n_row, top->n_col);
+	if (!mat)
+		goto error;
+	isl_mat_sub_copy(mat->ctx, mat->row, top->row, top->n_row,
+			 0, 0, mat->n_col);
+	isl_mat_sub_copy(mat->ctx, mat->row + top->n_row, bot->row, bot->n_row,
+			 0, 0, mat->n_col);
+	isl_mat_free(top);
+	isl_mat_free(bot);
+	return mat;
+error:
+	isl_mat_free(top);
+	isl_mat_free(bot);
+	return NULL;
+}
+
+int isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2)
+{
+	int i;
+
+	if (!mat1 || !mat2)
+		return -1;
+
+	if (mat1->n_row != mat2->n_row)
+		return 0;
+
+	if (mat1->n_col != mat2->n_col)
+		return 0;
+
+	for (i = 0; i < mat1->n_row; ++i)
+		if (!isl_seq_eq(mat1->row[i], mat2->row[i], mat1->n_col))
+			return 0;
+
+	return 1;
+}
+
+__isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec)
+{
+	struct isl_mat *mat;
+
+	if (!vec)
+		return NULL;
+	mat = isl_mat_alloc(vec->ctx, 1, vec->size);
+	if (!mat)
+		goto error;
+
+	isl_seq_cpy(mat->row[0], vec->el, vec->size);
+
+	isl_vec_free(vec);
+	return mat;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Return a copy of row "row" of "mat" as an isl_vec.
+ */
+__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row)
+{
+	isl_vec *v;
+
+	if (!mat)
+		return NULL;
+	if (row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			return NULL);
+
+	v = isl_vec_alloc(isl_mat_get_ctx(mat), mat->n_col);
+	if (!v)
+		return NULL;
+	isl_seq_cpy(v->el, mat->row[row], mat->n_col);
+
+	return v;
+}
+
+__isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top,
+	__isl_take isl_vec *bot)
+{
+	return isl_mat_concat(top, isl_mat_from_row_vec(bot));
+}
+
+__isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat,
+	unsigned dst_col, unsigned src_col, unsigned n)
+{
+	isl_mat *res;
+
+	if (!mat)
+		return NULL;
+	if (n == 0 || dst_col == src_col)
+		return mat;
+
+	res = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
+	if (!res)
+		goto error;
+
+	if (dst_col < src_col) {
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 0, 0, dst_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col, src_col, n);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col + n, dst_col, src_col - dst_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 src_col + n, src_col + n,
+				 res->n_col - src_col - n);
+	} else {
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 0, 0, src_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 src_col, src_col + n, dst_col - src_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col, src_col, n);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col + n, dst_col + n,
+				 res->n_col - dst_col - n);
+	}
+	isl_mat_free(mat);
+
+	return res;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+void isl_mat_gcd(__isl_keep isl_mat *mat, isl_int *gcd)
+{
+	int i;
+	isl_int g;
+
+	isl_int_set_si(*gcd, 0);
+	if (!mat)
+		return;
+
+	isl_int_init(g);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_seq_gcd(mat->row[i], mat->n_col, &g);
+		isl_int_gcd(*gcd, *gcd, g);
+	}
+	isl_int_clear(g);
+}
+
+__isl_give isl_mat *isl_mat_scale_down(__isl_take isl_mat *mat, isl_int m)
+{
+	int i;
+
+	if (isl_int_is_one(m))
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_scale_down(mat->row[i], mat->row[i], m, mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row,
+	isl_int m)
+{
+	if (isl_int_is_one(m))
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	isl_seq_scale_down(mat->row[row], mat->row[row], m, mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat)
+{
+	isl_int gcd;
+
+	if (!mat)
+		return NULL;
+
+	isl_int_init(gcd);
+	isl_mat_gcd(mat, &gcd);
+	mat = isl_mat_scale_down(mat, gcd);
+	isl_int_clear(gcd);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row)
+{
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	isl_seq_normalize(mat->ctx, mat->row[row], mat->n_col);
+
+	return mat;
+}
+
+/* Number of initial non-zero columns.
+ */
+int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat)
+{
+	int i;
+
+	if (!mat)
+		return -1;
+
+	for (i = 0; i < mat->n_col; ++i)
+		if (row_first_non_zero(mat->row, mat->n_row, i) < 0)
+			break;
+
+	return i;
+}

Added: polly/trunk/lib/External/isl/isl_mat_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_mat_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_mat_private.h (added)
+++ polly/trunk/lib/External/isl/isl_mat_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,46 @@
+#include <isl/mat.h>
+#include <isl_blk.h>
+
+struct isl_mat {
+	int ref;
+
+	struct isl_ctx *ctx;
+
+#define ISL_MAT_BORROWED		(1 << 0)
+	unsigned flags;
+
+	unsigned n_row;
+	unsigned n_col;
+
+	isl_int **row;
+
+	/* actual size of the rows in memory; n_col <= max_col */
+	unsigned max_col;
+
+	struct isl_blk block;
+};
+
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d);
+
+__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row,
+	isl_int m);
+
+__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row);
+
+int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat);
+
+void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col);
+void isl_mat_col_submul(struct isl_mat *mat,
+			int dst_col, isl_int f, int src_col);
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v);
+__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
+	int row, int col, isl_int v);

Added: polly/trunk/lib/External/isl/isl_morph.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_morph.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_morph.c (added)
+++ polly/trunk/lib/External/isl/isl_morph.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,917 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 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_map_private.h>
+#include <isl_aff_private.h>
+#include <isl_morph.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_space_private.h>
+#include <isl_equalities.h>
+
+isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+	return isl_basic_set_get_ctx(morph->dom);
+}
+
+__isl_give isl_morph *isl_morph_alloc(
+	__isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
+	__isl_take isl_mat *map, __isl_take isl_mat *inv)
+{
+	isl_morph *morph;
+
+	if (!dom || !ran || !map || !inv)
+		goto error;
+
+	morph = isl_alloc_type(dom->ctx, struct isl_morph);
+	if (!morph)
+		goto error;
+
+	morph->ref = 1;
+	morph->dom = dom;
+	morph->ran = ran;
+	morph->map = map;
+	morph->inv = inv;
+
+	return morph;
+error:
+	isl_basic_set_free(dom);
+	isl_basic_set_free(ran);
+	isl_mat_free(map);
+	isl_mat_free(inv);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	morph->ref++;
+	return morph;
+}
+
+__isl_give isl_morph *isl_morph_dup(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	return isl_morph_alloc(isl_basic_set_copy(morph->dom),
+		isl_basic_set_copy(morph->ran),
+		isl_mat_copy(morph->map), isl_mat_copy(morph->inv));
+}
+
+__isl_give isl_morph *isl_morph_cow(__isl_take isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	if (morph->ref == 1)
+		return morph;
+	morph->ref--;
+	return isl_morph_dup(morph);
+}
+
+void isl_morph_free(__isl_take isl_morph *morph)
+{
+	if (!morph)
+		return;
+
+	if (--morph->ref > 0)
+		return;
+
+	isl_basic_set_free(morph->dom);
+	isl_basic_set_free(morph->ran);
+	isl_mat_free(morph->map);
+	isl_mat_free(morph->inv);
+	free(morph);
+}
+
+/* Is "morph" an identity on the parameters?
+ */
+static int identity_on_parameters(__isl_keep isl_morph *morph)
+{
+	int is_identity;
+	unsigned nparam;
+	isl_mat *sub;
+
+	nparam = isl_morph_dom_dim(morph, isl_dim_param);
+	if (nparam != isl_morph_ran_dim(morph, isl_dim_param))
+		return 0;
+	if (nparam == 0)
+		return 1;
+	sub = isl_mat_sub_alloc(morph->map, 0, 1 + nparam, 0, 1 + nparam);
+	is_identity = isl_mat_is_scaled_identity(sub);
+	isl_mat_free(sub);
+
+	return is_identity;
+}
+
+/* Return an affine expression of the variables of the range of "morph"
+ * in terms of the parameters and the variables of the domain on "morph".
+ *
+ * In order for the space manipulations to make sense, we require
+ * that the parameters are not modified by "morph".
+ */
+__isl_give isl_multi_aff *isl_morph_get_var_multi_aff(
+	__isl_keep isl_morph *morph)
+{
+	isl_space *dom, *ran, *space;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+	unsigned nparam, nvar;
+	int i;
+	int is_identity;
+
+	if (!morph)
+		return NULL;
+
+	is_identity = identity_on_parameters(morph);
+	if (is_identity < 0)
+		return NULL;
+	if (!is_identity)
+		isl_die(isl_morph_get_ctx(morph), isl_error_invalid,
+			"cannot handle parameter compression", return NULL);
+
+	dom = isl_morph_get_dom_space(morph);
+	ls = isl_local_space_from_space(isl_space_copy(dom));
+	ran = isl_morph_get_ran_space(morph);
+	space = isl_space_map_from_domain_and_range(dom, ran);
+	ma = isl_multi_aff_zero(space);
+
+	nparam = isl_multi_aff_dim(ma, isl_dim_param);
+	nvar = isl_multi_aff_dim(ma, isl_dim_out);
+	for (i = 0; i < nvar; ++i) {
+		isl_val *val;
+		isl_vec *v;
+		isl_aff *aff;
+
+		v = isl_mat_get_row(morph->map, 1 + nparam + i);
+		v = isl_vec_insert_els(v, 0, 1);
+		val = isl_mat_get_element_val(morph->map, 0, 0);
+		v = isl_vec_set_element_val(v, 0, val);
+		aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_local_space_free(ls);
+	return ma;
+}
+
+/* Return the domain space of "morph".
+ */
+__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	return isl_basic_set_get_space(morph->dom);
+}
+
+__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+	
+	return isl_space_copy(morph->ran->dim);
+}
+
+unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
+{
+	if (!morph)
+		return 0;
+
+	return isl_basic_set_dim(morph->dom, type);
+}
+
+unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
+{
+	if (!morph)
+		return 0;
+
+	return isl_basic_set_dim(morph->ran, type);
+}
+
+__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	unsigned dom_offset;
+
+	if (n == 0)
+		return morph;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	dom_offset = 1 + isl_space_offset(morph->dom->dim, type);
+
+	morph->dom = isl_basic_set_remove_dims(morph->dom, type, first, n);
+
+	morph->map = isl_mat_drop_cols(morph->map, dom_offset + first, n);
+
+	morph->inv = isl_mat_drop_rows(morph->inv, dom_offset + first, n);
+
+	if (morph->dom && morph->ran && morph->map && morph->inv)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	unsigned ran_offset;
+
+	if (n == 0)
+		return morph;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	ran_offset = 1 + isl_space_offset(morph->ran->dim, type);
+
+	morph->ran = isl_basic_set_remove_dims(morph->ran, type, first, n);
+
+	morph->map = isl_mat_drop_rows(morph->map, ran_offset + first, n);
+
+	morph->inv = isl_mat_drop_cols(morph->inv, ran_offset + first, n);
+
+	if (morph->dom && morph->ran && morph->map && morph->inv)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Project domain of morph onto its parameter domain.
+ */
+__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph)
+{
+	unsigned n;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+	n = isl_basic_set_dim(morph->dom, isl_dim_set);
+	morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, n);
+	if (!morph)
+		return NULL;
+	morph->dom = isl_basic_set_params(morph->dom);
+	if (morph->dom)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Project range of morph onto its parameter domain.
+ */
+__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph)
+{
+	unsigned n;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+	n = isl_basic_set_dim(morph->ran, isl_dim_set);
+	morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n);
+	if (!morph)
+		return NULL;
+	morph->ran = isl_basic_set_params(morph->ran);
+	if (morph->ran)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out)
+{
+	if (!morph)
+		return;
+
+	isl_basic_set_print(morph->dom, out, 0, "", "", ISL_FORMAT_ISL);
+	isl_basic_set_print(morph->ran, out, 0, "", "", ISL_FORMAT_ISL);
+	isl_mat_print_internal(morph->map, out, 4);
+	isl_mat_print_internal(morph->inv, out, 4);
+}
+
+void isl_morph_dump(__isl_take isl_morph *morph)
+{
+	isl_morph_print_internal(morph, stderr);
+}
+
+__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset)
+{
+	isl_mat *id;
+	isl_basic_set *universe;
+	unsigned total;
+
+	if (!bset)
+		return NULL;
+
+	total = isl_basic_set_total_dim(bset);
+	id = isl_mat_identity(bset->ctx, 1 + total);
+	universe = isl_basic_set_universe(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(universe, isl_basic_set_copy(universe),
+		id, isl_mat_copy(id));
+}
+
+/* Create a(n identity) morphism between empty sets of the same dimension
+ * a "bset".
+ */
+__isl_give isl_morph *isl_morph_empty(__isl_keep isl_basic_set *bset)
+{
+	isl_mat *id;
+	isl_basic_set *empty;
+	unsigned total;
+
+	if (!bset)
+		return NULL;
+
+	total = isl_basic_set_total_dim(bset);
+	id = isl_mat_identity(bset->ctx, 1 + total);
+	empty = isl_basic_set_empty(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(empty, isl_basic_set_copy(empty),
+		id, isl_mat_copy(id));
+}
+
+/* Given a matrix that maps a (possibly) parametric domain to
+ * a parametric domain, add in rows that map the "nparam" parameters onto
+ * themselves.
+ */
+static __isl_give isl_mat *insert_parameter_rows(__isl_take isl_mat *mat,
+	unsigned nparam)
+{
+	int i;
+
+	if (nparam == 0)
+		return mat;
+	if (!mat)
+		return NULL;
+
+	mat = isl_mat_insert_rows(mat, 1, nparam);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < nparam; ++i) {
+		isl_seq_clr(mat->row[1 + i], mat->n_col);
+		isl_int_set(mat->row[1 + i][1 + i], mat->row[0][0]);
+	}
+
+	return mat;
+}
+
+/* Construct a basic set described by the "n" equalities of "bset" starting
+ * at "first".
+ */
+static __isl_give isl_basic_set *copy_equalities(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n)
+{
+	int i, k;
+	isl_basic_set *eq;
+	unsigned total;
+
+	isl_assert(bset->ctx, bset->n_div == 0, return NULL);
+
+	total = isl_basic_set_total_dim(bset);
+	eq = isl_basic_set_alloc_space(isl_space_copy(bset->dim), 0, n, 0);
+	if (!eq)
+		return NULL;
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_set_alloc_equality(eq);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(eq->eq[k], bset->eq[first + k], 1 + total);
+	}
+
+	return eq;
+error:
+	isl_basic_set_free(eq);
+	return NULL;
+}
+
+/* Given a basic set, exploit the equalties in the basic set to construct
+ * a morphishm that maps the basic set to a lower-dimensional space.
+ * Specifically, the morphism reduces the number of dimensions of type "type".
+ *
+ * This function is a slight generalization of isl_mat_variable_compression
+ * in that it allows the input to be parametric and that it allows for the
+ * compression of either parameters or set variables.
+ *
+ * We first select the equalities of interest, that is those that involve
+ * variables of type "type" and no later variables.
+ * Denote those equalities as
+ *
+ *		-C(p) + M x = 0
+ *
+ * where C(p) depends on the parameters if type == isl_dim_set and
+ * is a constant if type == isl_dim_param.
+ *
+ * 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
+ *
+ *		-C(p) + H1 x1' = 0   or   x1' = H1^{-1} C(p) = C'(p)
+ *
+ * If the denominator of the constant term does not divide the
+ * the common denominator of the parametric terms, then every
+ * integer point is mapped to a non-integer point and then the original set has no
+ * integer solutions (since the x' are a unimodular transformation
+ * of the x).  In this case, an empty morphism is returned.
+ * Otherwise, the transformation is given by
+ *
+ *		x = U1 H1^{-1} C(p) + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *		x2' = Q2 x
+ *
+ * Both matrices are extended to map the full original space to the full
+ * compressed space.
+ */
+__isl_give isl_morph *isl_basic_set_variable_compression(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type)
+{
+	unsigned otype;
+	unsigned ntype;
+	unsigned orest;
+	unsigned nrest;
+	int f_eq, n_eq;
+	isl_space *dim;
+	isl_mat *H, *U, *Q, *C = NULL, *H1, *U1, *U2;
+	isl_basic_set *dom, *ran;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_morph_empty(bset);
+
+	isl_assert(bset->ctx, bset->n_div == 0, return NULL);
+
+	otype = 1 + isl_space_offset(bset->dim, type);
+	ntype = isl_basic_set_dim(bset, type);
+	orest = otype + ntype;
+	nrest = isl_basic_set_total_dim(bset) - (orest - 1);
+
+	for (f_eq = 0; f_eq < bset->n_eq; ++f_eq)
+		if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1)
+			break;
+	for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq)
+		if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1)
+			break;
+	if (n_eq == 0)
+		return isl_morph_identity(bset);
+
+	H = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype);
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+	if (!H || !U || !Q)
+		goto error;
+	Q = isl_mat_drop_rows(Q, 0, n_eq);
+	Q = isl_mat_diagonal(isl_mat_identity(bset->ctx, otype), Q);
+	Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest));
+	C = isl_mat_alloc(bset->ctx, 1 + n_eq, otype);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_seq_clr(C->row[0] + 1, otype - 1);
+	isl_mat_sub_neg(C->ctx, C->row + 1, bset->eq + f_eq, n_eq, 0, 0, otype);
+	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);
+	if (!C)
+		goto error;
+	isl_mat_free(H);
+
+	if (!isl_int_is_one(C->row[0][0])) {
+		int i;
+		isl_int g;
+
+		isl_int_init(g);
+		for (i = 0; i < n_eq; ++i) {
+			isl_seq_gcd(C->row[1 + i] + 1, otype - 1, &g);
+			isl_int_gcd(g, g, C->row[0][0]);
+			if (!isl_int_is_divisible_by(C->row[1 + i][0], g))
+				break;
+		}
+		isl_int_clear(g);
+
+		if (i < n_eq) {
+			isl_mat_free(C);
+			isl_mat_free(U);
+			isl_mat_free(Q);
+			return isl_morph_empty(bset);
+		}
+
+		C = isl_mat_normalize(C);
+	}
+
+	U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, n_eq);
+	U1 = isl_mat_lin_to_aff(U1);
+	U2 = isl_mat_sub_alloc(U, 0, U->n_row, n_eq, U->n_row - n_eq);
+	U2 = isl_mat_lin_to_aff(U2);
+	isl_mat_free(U);
+
+	C = isl_mat_product(U1, C);
+	C = isl_mat_aff_direct_sum(C, U2);
+	C = insert_parameter_rows(C, otype - 1);
+	C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest));
+
+	dim = isl_space_copy(bset->dim);
+	dim = isl_space_drop_dims(dim, type, 0, ntype);
+	dim = isl_space_add_dims(dim, type, ntype - n_eq);
+	ran = isl_basic_set_universe(dim);
+	dom = copy_equalities(bset, f_eq, n_eq);
+
+	return isl_morph_alloc(dom, ran, Q, C);
+error:
+	isl_mat_free(C);
+	isl_mat_free(H);
+	isl_mat_free(U);
+	isl_mat_free(Q);
+	return NULL;
+}
+
+/* Construct a parameter compression for "bset".
+ * We basically just call isl_mat_parameter_compression with the right input
+ * and then extend the resulting matrix to include the variables.
+ *
+ * The implementation assumes that "bset" does not have any equalities
+ * that only involve the parameters and that isl_basic_set_gauss has
+ * been applied to "bset".
+ *
+ * Let the equalities be given as
+ *
+ *	B(p) + A x = 0.
+ *
+ * We use isl_mat_parameter_compression_ext to compute the compression
+ *
+ *	p = T p'.
+ */
+__isl_give isl_morph *isl_basic_set_parameter_compression(
+	__isl_keep isl_basic_set *bset)
+{
+	unsigned nparam;
+	unsigned nvar;
+	unsigned n_div;
+	int n_eq;
+	isl_mat *H, *B;
+	isl_mat *map, *inv;
+	isl_basic_set *dom, *ran;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_morph_empty(bset);
+	if (bset->n_eq == 0)
+		return isl_morph_identity(bset);
+
+	n_eq = bset->n_eq;
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+	if (isl_seq_first_non_zero(bset->eq[bset->n_eq - 1] + 1 + nparam,
+				    nvar + n_div) == -1)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"input not allowed to have parameter equalities",
+			return NULL);
+	if (n_eq > nvar + n_div)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"input not gaussed", return NULL);
+
+	B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
+	H = isl_mat_sub_alloc6(bset->ctx, bset->eq,
+				0, n_eq, 1 + nparam, nvar + n_div);
+	inv = isl_mat_parameter_compression_ext(B, H);
+	inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar));
+	map = isl_mat_right_inverse(isl_mat_copy(inv));
+
+	dom = isl_basic_set_universe(isl_space_copy(bset->dim));
+	ran = isl_basic_set_universe(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(dom, ran, map, inv);
+}
+
+/* Add stride constraints to "bset" based on the inverse mapping
+ * that was plugged in.  In particular, if morph maps x' to x,
+ * the the constraints of the original input
+ *
+ *	A x' + b >= 0
+ *
+ * have been rewritten to
+ *
+ *	A inv x + b >= 0
+ *
+ * However, this substitution may loose information on the integrality of x',
+ * so we need to impose that
+ *
+ *	inv x
+ *
+ * is integral.  If inv = B/d, this means that we need to impose that
+ *
+ *	B x = 0		mod d
+ *
+ * or
+ *
+ *	exists alpha in Z^m: B x = d alpha
+ *
+ * This function is similar to add_strides in isl_affine_hull.c
+ */
+static __isl_give isl_basic_set *add_strides(__isl_take isl_basic_set *bset,
+	__isl_keep isl_morph *morph)
+{
+	int i, div, k;
+	isl_int gcd;
+
+	if (isl_int_is_one(morph->inv->row[0][0]))
+		return bset;
+
+	isl_int_init(gcd);
+
+	for (i = 0; 1 + i < morph->inv->n_row; ++i) {
+		isl_seq_gcd(morph->inv->row[1 + i], morph->inv->n_col, &gcd);
+		if (isl_int_is_divisible_by(gcd, morph->inv->row[0][0]))
+			continue;
+		div = isl_basic_set_alloc_div(bset);
+		if (div < 0)
+			goto error;
+		isl_int_set_si(bset->div[div][0], 0);
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k], morph->inv->row[1 + i],
+			    morph->inv->n_col);
+		isl_seq_clr(bset->eq[k] + morph->inv->n_col, bset->n_div);
+		isl_int_set(bset->eq[k][morph->inv->n_col + div],
+			    morph->inv->row[0][0]);
+	}
+
+	isl_int_clear(gcd);
+
+	return bset;
+error:
+	isl_int_clear(gcd);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Apply the morphism to the basic set.
+ * We basically just compute the preimage of "bset" under the inverse mapping
+ * in morph, add in stride constraints and intersect with the range
+ * of the morphism.
+ */
+__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
+	__isl_take isl_basic_set *bset)
+{
+	isl_basic_set *res = NULL;
+	isl_mat *mat = NULL;
+	int i, k;
+	int max_stride;
+
+	if (!morph || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_is_equal(bset->dim, morph->dom->dim),
+		    goto error);
+
+	max_stride = morph->inv->n_row - 1;
+	if (isl_int_is_one(morph->inv->row[0][0]))
+		max_stride = 0;
+	res = isl_basic_set_alloc_space(isl_space_copy(morph->ran->dim),
+		bset->n_div + max_stride, bset->n_eq + max_stride, bset->n_ineq);
+
+	for (i = 0; i < bset->n_div; ++i)
+		if (isl_basic_set_alloc_div(res) < 0)
+			goto error;
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
+					0, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(res->eq[k], mat->row[i], mat->n_col);
+		isl_seq_scale(res->eq[k] + mat->n_col, bset->eq[i] + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->ineq, 0, bset->n_ineq,
+					0, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(res->ineq[k], mat->row[i], mat->n_col);
+		isl_seq_scale(res->ineq[k] + mat->n_col,
+				bset->ineq[i] + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->div, 0, bset->n_div,
+					1, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_div; ++i) {
+		isl_int_mul(res->div[i][0],
+				morph->inv->row[0][0], bset->div[i][0]);
+		isl_seq_cpy(res->div[i] + 1, mat->row[i], mat->n_col);
+		isl_seq_scale(res->div[i] + 1 + mat->n_col,
+				bset->div[i] + 1 + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	res = add_strides(res, morph);
+
+	if (isl_basic_set_is_rational(bset))
+		res = isl_basic_set_set_rational(res);
+
+	res = isl_basic_set_simplify(res);
+	res = isl_basic_set_finalize(res);
+
+	res = isl_basic_set_intersect(res, isl_basic_set_copy(morph->ran));
+
+	isl_morph_free(morph);
+	isl_basic_set_free(bset);
+	return res;
+error:
+	isl_mat_free(mat);
+	isl_morph_free(morph);
+	isl_basic_set_free(bset);
+	isl_basic_set_free(res);
+	return NULL;
+}
+
+/* Apply the morphism to the set.
+ */
+__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
+	__isl_take isl_set *set)
+{
+	int i;
+
+	if (!morph || !set)
+		goto error;
+
+	isl_assert(set->ctx, isl_space_is_equal(set->dim, morph->dom->dim), goto error);
+
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+
+	isl_space_free(set->dim);
+	set->dim = isl_space_copy(morph->ran->dim);
+	if (!set->dim)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_morph_basic_set(isl_morph_copy(morph), set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+
+	return set;
+error:
+	isl_set_free(set);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Construct a morphism that first does morph2 and then morph1.
+ */
+__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
+	__isl_take isl_morph *morph2)
+{
+	isl_mat *map, *inv;
+	isl_basic_set *dom, *ran;
+
+	if (!morph1 || !morph2)
+		goto error;
+
+	map = isl_mat_product(isl_mat_copy(morph1->map), isl_mat_copy(morph2->map));
+	inv = isl_mat_product(isl_mat_copy(morph2->inv), isl_mat_copy(morph1->inv));
+	dom = isl_morph_basic_set(isl_morph_inverse(isl_morph_copy(morph2)),
+				  isl_basic_set_copy(morph1->dom));
+	dom = isl_basic_set_intersect(dom, isl_basic_set_copy(morph2->dom));
+	ran = isl_morph_basic_set(isl_morph_copy(morph1),
+				  isl_basic_set_copy(morph2->ran));
+	ran = isl_basic_set_intersect(ran, isl_basic_set_copy(morph1->ran));
+
+	isl_morph_free(morph1);
+	isl_morph_free(morph2);
+
+	return isl_morph_alloc(dom, ran, map, inv);
+error:
+	isl_morph_free(morph1);
+	isl_morph_free(morph2);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph)
+{
+	isl_basic_set *bset;
+	isl_mat *mat;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	bset = morph->dom;
+	morph->dom = morph->ran;
+	morph->ran = bset;
+
+	mat = morph->map;
+	morph->map = morph->inv;
+	morph->inv = mat;
+
+	return morph;
+}
+
+/* We detect all the equalities first to avoid implicit equalties
+ * being discovered during the computations.  In particular,
+ * the compression on the variables could expose additional stride
+ * constraints on the parameters.  This would result in existentially
+ * quantified variables after applying the resulting morph, which
+ * in turn could break invariants of the calling functions.
+ */
+__isl_give isl_morph *isl_basic_set_full_compression(
+	__isl_keep isl_basic_set *bset)
+{
+	isl_morph *morph, *morph2;
+
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_detect_equalities(bset);
+
+	morph = isl_basic_set_variable_compression(bset, isl_dim_param);
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+	morph2 = isl_basic_set_parameter_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph2), bset);
+
+	morph = isl_morph_compose(morph2, morph);
+
+	morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+	isl_basic_set_free(bset);
+
+	morph = isl_morph_compose(morph2, morph);
+
+	return morph;
+}
+
+__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
+	__isl_take isl_vec *vec)
+{
+	if (!morph)
+		goto error;
+
+	vec = isl_mat_vec_product(isl_mat_copy(morph->map), vec);
+
+	isl_morph_free(morph);
+	return vec;
+error:
+	isl_morph_free(morph);
+	isl_vec_free(vec);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_morph.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_morph.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_morph.h (added)
+++ polly/trunk/lib/External/isl/isl_morph.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,86 @@
+/*
+ * 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 
+ */
+
+#ifndef ISL_MORHP_H
+#define ISL_MORHP_H
+
+#include <stdio.h>
+#include <isl/space.h>
+#include <isl/mat.h>
+#include <isl/set.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* An isl_morph is a "morphism" on (basic) sets.
+ * "map" is an affine mapping from "dom" to "ran"
+ * and "inv" is the inverse mapping.
+ */
+struct isl_morph {
+	int ref;
+
+	isl_basic_set *dom;
+	isl_basic_set *ran;
+
+	isl_mat *map;
+	isl_mat *inv;
+};
+typedef struct isl_morph isl_morph;
+
+isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph);
+
+__isl_give isl_morph *isl_morph_alloc(
+	__isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
+	__isl_take isl_mat *map, __isl_take isl_mat *inv);
+__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph);
+__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset);
+void isl_morph_free(__isl_take isl_morph *morph);
+
+__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph);
+__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph);
+__isl_give isl_multi_aff *isl_morph_get_var_multi_aff(
+	__isl_keep isl_morph *morph);
+unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type);
+unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type);
+
+__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph);
+__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph);
+
+__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
+	__isl_take isl_morph *morph2);
+__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph);
+
+void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out);
+void isl_morph_dump(__isl_take isl_morph *morph);
+
+__isl_give isl_morph *isl_basic_set_variable_compression(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type);
+__isl_give isl_morph *isl_basic_set_parameter_compression(
+	__isl_keep isl_basic_set *bset);
+__isl_give isl_morph *isl_basic_set_full_compression(
+	__isl_keep isl_basic_set *bset);
+
+__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
+	__isl_take isl_set *set);
+__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
+	__isl_take isl_vec *vec);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

Added: polly/trunk/lib/External/isl/isl_multi_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_multi_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_multi_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_multi_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1498 @@
+/*
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_space_private.h>
+#include <isl/set.h>
+#include <isl_reordering.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xMULTI(BASE) isl_multi_ ## BASE
+#define MULTI(BASE) xMULTI(BASE)
+#define MULTI_NAME(BASE) "isl_multi_" #BASE
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+
+isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_get_ctx(multi->space) : NULL;
+}
+
+__isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_copy(multi->space) : NULL;
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "multi".
+ * Return -1 if no such dimension can be found.
+ */
+int FN(MULTI(BASE),find_dim_by_name)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, const char *name)
+{
+	if (!multi)
+		return -1;
+	return isl_space_find_dim_by_name(multi->space, type, name);
+}
+
+__isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
+	__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	int n;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	n = isl_space_dim(space, isl_dim_out);
+	multi = isl_calloc(ctx, MULTI(BASE),
+			 sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
+	if (!multi)
+		goto error;
+
+	multi->space = space;
+	multi->n = n;
+	multi->ref = 1;
+	return multi;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
+{
+	int i;
+	MULTI(BASE) *dup;
+
+	if (!multi)
+		return NULL;
+
+	dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i)
+		dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
+						    FN(EL,copy)(multi->p[i]));
+
+	return dup;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	if (multi->ref == 1)
+		return multi;
+
+	multi->ref--;
+	return FN(MULTI(BASE),dup)(multi);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	multi->ref++;
+	return multi;
+}
+
+__isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+
+	if (--multi->ref > 0)
+		return NULL;
+
+	isl_space_free(multi->space);
+	for (i = 0; i < multi->n; ++i)
+		FN(EL,free)(multi->p[i]);
+	free(multi);
+
+	return NULL;
+}
+
+/* Check whether "multi" has non-zero coefficients for any dimension
+ * in the given range or if any of these dimensions appear
+ * with non-zero coefficients in any of the integer divisions involved.
+ */
+int FN(MULTI(BASE),involves_dims)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return -1;
+	if (multi->n == 0 || n == 0)
+		return 0;
+
+	for (i = 0; i < multi->n; ++i) {
+		int involves;
+
+		involves = FN(EL,involves_dims)(multi->p[i], type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+
+	return 0;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot insert output/set dimensions",
+			return FN(MULTI(BASE),free)(multi));
+	if (n == 0 && !isl_space_is_named_or_nested(multi->space, type))
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_insert_dims(multi->space, type, first, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,insert_dims)(multi->p[i], type, first, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = FN(MULTI(BASE),dim)(multi, type);
+
+	return FN(MULTI(BASE),insert_dims)(multi, type, pos, n);
+}
+
+unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_dim(multi->space, type) : 0;
+}
+
+/* Return the position of the first dimension of "type" with id "id".
+ * Return -1 if there is no such dimension.
+ */
+int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, __isl_keep isl_id *id)
+{
+	if (!multi)
+		return -1;
+	return isl_space_find_dim_by_id(multi->space, type, id);
+}
+
+/* Return the id of the given dimension.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos)
+{
+	return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	if (type == isl_dim_out)
+		return multi;
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+
+const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
+}
+
+/* Does the specified tuple have an id?
+ */
+int FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_has_tuple_id(multi->space, type) : -1;
+}
+
+/* Return the id of the specified tuple.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
+}
+
+__isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
+	int pos)
+{
+	isl_ctx *ctx;
+
+	if (!multi)
+		return NULL;
+	ctx = FN(MULTI(BASE),get_ctx)(multi);
+	if (pos < 0 || pos >= multi->n)
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", return NULL);
+	return FN(EL,copy)(multi->p[pos]);
+}
+
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
+	__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
+{
+	isl_space *multi_space = NULL;
+	isl_space *el_space = NULL;
+	int match;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !el)
+		goto error;
+
+	multi_space = FN(MULTI(BASE),get_space)(multi);
+	match = FN(EL,matching_params)(el, multi_space);
+	if (match < 0)
+		goto error;
+	if (!match) {
+		multi = FN(MULTI(BASE),align_params)(multi,
+						    FN(EL,get_space)(el));
+		isl_space_free(multi_space);
+		multi_space = FN(MULTI(BASE),get_space)(multi);
+		el = FN(EL,align_params)(el, isl_space_copy(multi_space));
+	}
+	if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
+		goto error;
+
+	if (pos < 0 || pos >= multi->n)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	FN(EL,free)(multi->p[pos]);
+	multi->p[pos] = el;
+
+	isl_space_free(multi_space);
+	isl_space_free(el_space);
+
+	return multi;
+error:
+	FN(MULTI(BASE),free)(multi);
+	FN(EL,free)(el);
+	isl_space_free(multi_space);
+	isl_space_free(el_space);
+	return NULL;
+}
+
+/* Reset the space of "multi".  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,
+ * which we pass along to the element function since we don't how
+ * that is represented either.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !space || !domain)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,reset_domain_space)(multi->p[i],
+				 isl_space_copy(domain));
+		if (!multi->p[i])
+			goto error;
+	}
+	isl_space_free(domain);
+	isl_space_free(multi->space);
+	multi->space = space;
+
+	return multi;
+error:
+	isl_space_free(domain);
+	isl_space_free(space);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
+{
+	isl_space *space;
+
+	space = isl_space_extend_domain_with_range(isl_space_copy(domain),
+						isl_space_copy(multi->space));
+	return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
+{
+	isl_space *domain;
+
+	domain = isl_space_domain(isl_space_copy(space));
+	return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
+}
+
+/* Set the id of the given dimension of "multi" to "id".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !id)
+		goto error;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_dim_id(space, type, pos, id);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+	isl_id_free(id);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
+	__isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
+	const char *s)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_tuple_name(space, type, s);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
+	__isl_take MULTI(BASE) *multi, enum isl_dim_type type,
+	__isl_take isl_id *id)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		goto error;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_tuple_id(space, type, id);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Drop the id on the specified tuple.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
+	__isl_take MULTI(BASE) *multi, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!multi)
+		return NULL;
+	if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_reset_tuple_id(space, type);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "multi".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_reset_user(space);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !exp)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,realign_domain)(multi->p[i],
+						isl_reordering_copy(exp));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	multi = FN(MULTI(BASE),reset_domain_space)(multi,
+						    isl_space_copy(exp->dim));
+
+	isl_reordering_free(exp);
+	return multi;
+error:
+	isl_reordering_free(exp);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+/* Align the parameters of "multi" to those of "model".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+	isl_reordering *exp;
+
+	if (!multi || !model)
+		goto error;
+
+	if (isl_space_match(multi->space, isl_dim_param,
+			     model, isl_dim_param)) {
+		isl_space_free(model);
+		return multi;
+	}
+
+	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(multi->space))
+		isl_die(ctx, isl_error_invalid,
+			"input has unnamed parameters", goto error);
+
+	model = isl_space_params(model);
+	exp = isl_parameter_alignment_reordering(multi->space, model);
+	exp = isl_reordering_extend_space(exp,
+				    FN(MULTI(BASE),get_domain_space)(multi));
+	multi = FN(MULTI(BASE),realign_domain)(multi, exp);
+
+	isl_space_free(model);
+	return multi;
+error:
+	isl_space_free(model);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+#if !defined(NO_GIST) || !defined(NO_INTERSECT_DOMAIN)
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_set_and)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *set,
+	__isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi,
+					__isl_take isl_set *set))
+{
+	isl_ctx *ctx;
+
+	if (!multi || !set)
+		goto error;
+	if (isl_space_match(multi->space, isl_dim_param,
+			    set->dim, isl_dim_param))
+		return fn(multi, set);
+	ctx = FN(MULTI(BASE),get_ctx)(multi);
+	if (!isl_space_has_named_params(multi->space) ||
+	    !isl_space_has_named_params(set->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	multi = FN(MULTI(BASE),align_params)(multi, isl_set_get_space(set));
+	set = isl_set_align_params(set, FN(MULTI(BASE),get_space)(multi));
+	return fn(multi, set);
+error:
+	FN(MULTI(BASE),free)(multi);
+	isl_set_free(set);
+	return NULL;
+}
+#endif
+
+#ifndef NO_GIST
+__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_aligned)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !context)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,gist)(multi->p[i], isl_set_copy(context));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_set_free(context);
+	return multi;
+error:
+	isl_set_free(context);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi,
+	__isl_take isl_set *context)
+{
+	return FN(MULTI(BASE),align_params_multi_set_and)(multi, context,
+						&FN(MULTI(BASE),gist_aligned));
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
+{
+	isl_space *space = FN(MULTI(BASE),get_domain_space)(multi);
+	isl_set *dom_context = isl_set_universe(space);
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return FN(MULTI(BASE),gist)(multi, dom_context);
+}
+#endif
+
+#ifndef NO_INTERSECT_DOMAIN
+/* Transform the domain of "multi" by combining it with "domain"
+ * using "fn".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_aligned)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain,
+	__isl_give EL *(*fn)(EL *el, __isl_take isl_set *set2))
+{
+	int i;
+
+	if (!multi || !domain)
+		goto error;
+
+	if (multi->n == 0) {
+		isl_set_free(domain);
+		return multi;
+	}
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = fn(multi->p[i], isl_set_copy(domain));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_set_free(domain);
+	return multi;
+error:
+	isl_set_free(domain);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+/* Intersect the domain of "multi" with "domain".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain_aligned)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+	return FN(MULTI(BASE),intersect_aligned)(multi, domain,
+						&FN(EL,intersect_domain));
+}
+
+/* Intersect the domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+	return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain,
+				    &FN(MULTI(BASE),intersect_domain_aligned));
+}
+
+/* Intersect the parameter domain of "multi" with "domain".
+ *
+ * The parameters of "multi" and "domain" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params_aligned)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+	return FN(MULTI(BASE),intersect_aligned)(multi, domain,
+						&FN(EL,intersect_params));
+}
+
+/* Intersect the parameter domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+	return FN(MULTI(BASE),align_params_multi_set_and)(multi, domain,
+				    &FN(MULTI(BASE),intersect_params_aligned));
+}
+#endif
+
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
+	__isl_take isl_space *space, __isl_take LIST(EL) *list)
+{
+	int i;
+	int n;
+	isl_ctx *ctx;
+	MULTI(BASE) *multi;
+
+	if (!space || !list)
+		goto error;
+
+	ctx = isl_space_get_ctx(space);
+	n = FN(FN(LIST(EL),n),BASE)(list);
+	if (n != isl_space_dim(space, isl_dim_out))
+		isl_die(ctx, isl_error_invalid,
+			"invalid number of elements in list", goto error);
+
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+	for (i = 0; i < n; ++i) {
+		multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
+					FN(FN(LIST(EL),get),BASE)(list, i));
+	}
+
+	isl_space_free(space);
+	FN(LIST(EL),free)(list);
+	return multi;
+error:
+	isl_space_free(space);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+#ifndef NO_IDENTITY
+/* Create a multi expression in the given space that maps each
+ * input dimension to the corresponding output dimension.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
+{
+	int i, n;
+	isl_local_space *ls;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	if (isl_space_is_set(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting map space", goto error);
+
+	n = isl_space_dim(space, isl_dim_out);
+	if (n != isl_space_dim(space, isl_dim_in))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"number of input and output dimensions needs to be "
+			"the same", goto error);
+
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+
+	if (!n) {
+		isl_space_free(space);
+		return multi;
+	}
+
+	space = isl_space_domain(space);
+	ls = isl_local_space_from_space(space);
+
+	for (i = 0; i < n; ++i) {
+		EL *el;
+		el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
+						isl_dim_set, i);
+		multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
+	}
+
+	isl_local_space_free(ls);
+
+	return multi;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+#endif
+
+/* Construct a multi expression in the given space with value zero in
+ * each of the output dimensions.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
+{
+	int n;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	n = isl_space_dim(space , isl_dim_out);
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+
+	if (!n)
+		isl_space_free(space);
+	else {
+		int i;
+		isl_local_space *ls;
+		EL *el;
+
+		space = isl_space_domain(space);
+		ls = isl_local_space_from_space(space);
+		el = FN(EL,zero_on_domain)(ls);
+
+		for (i = 0; i < n; ++i)
+			multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
+							    FN(EL,copy)(el));
+
+		FN(EL,free)(el);
+	}
+
+	return multi;
+}
+
+#ifndef NO_FROM_BASE
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
+{
+	MULTI(BASE) *multi;
+
+	multi = FN(MULTI(BASE),alloc)(FN(EL,get_space)(el));
+	multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
+
+	return multi;
+}
+#endif
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	unsigned dim;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	dim = FN(MULTI(BASE),dim)(multi, type);
+	if (first + n > dim || first + n < first)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"index out of bounds",
+			return FN(MULTI(BASE),cow)(multi));
+
+	multi->space = isl_space_drop_dims(multi->space, type, first, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),cow)(multi);
+
+	if (type == isl_dim_out) {
+		for (i = 0; i < n; ++i)
+			FN(EL,free)(multi->p[first + i]);
+		for (i = first; i + n < multi->n; ++i)
+			multi->p[i] = multi->p[i + n];
+		multi->n -= n;
+
+		return multi;
+	}
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),cow)(multi);
+	}
+
+	return multi;
+}
+
+/* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
+		__isl_take MULTI(BASE) *multi2))
+{
+	isl_ctx *ctx;
+
+	if (!multi1 || !multi2)
+		goto error;
+	if (isl_space_match(multi1->space, isl_dim_param,
+			    multi2->space, isl_dim_param))
+		return fn(multi1, multi2);
+	ctx = FN(MULTI(BASE),get_ctx)(multi1);
+	if (!isl_space_has_named_params(multi1->space) ||
+	    !isl_space_has_named_params(multi2->space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	multi1 = FN(MULTI(BASE),align_params)(multi1,
+					    FN(MULTI(BASE),get_space)(multi2));
+	multi2 = FN(MULTI(BASE),align_params)(multi2,
+					    FN(MULTI(BASE),get_space)(multi1));
+	return fn(multi1, multi2);
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	int i, n1, n2;
+	EL *el;
+	isl_space *space;
+	MULTI(BASE) *res;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
+					FN(MULTI(BASE),get_space)(multi2));
+	res = FN(MULTI(BASE),alloc)(space);
+
+	n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
+
+	for (i = 0; i < n1; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
+		res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
+	}
+
+	for (i = 0; i < n2; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
+		res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
+	}
+
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return res;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+					&FN(MULTI(BASE),range_product_aligned));
+}
+
+/* Is the range of "multi" a wrapped relation?
+ */
+int FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
+{
+	if (!multi)
+		return -1;
+	return isl_space_range_is_wrapping(multi->space);
+}
+
+/* Given a function A -> [B -> C], extract the function A -> B.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_range_is_wrapping(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range is not a product",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	multi = FN(MULTI(BASE),drop_dims)(multi,
+					isl_dim_out, keep, total - keep);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Given a function A -> [B -> C], extract the function A -> C.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_range_is_wrapping(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range is not a product",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	int i;
+	EL *el;
+	isl_space *space;
+	MULTI(BASE) *res;
+	int in1, in2, out1, out2;
+
+	in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
+	in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
+	out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
+	space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
+				  FN(MULTI(BASE),get_space)(multi2));
+	res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+	space = isl_space_domain(space);
+
+	for (i = 0; i < out1; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
+		el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
+		el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+		res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
+	}
+
+	for (i = 0; i < out2; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
+		el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
+		el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+		res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
+	}
+
+	isl_space_free(space);
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return res;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+					&FN(MULTI(BASE),product_aligned));
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	if (!multi->space->nested[1])
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_flatten_range(multi->space);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	return multi;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> (B, D).
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	MULTI(BASE) *multi;
+
+	multi = FN(MULTI(BASE),range_product)(multi1, multi2);
+	multi = FN(MULTI(BASE),flatten_range)(multi);
+	return multi;
+}
+
+/* Given two multi expressions, "multi1"
+ *
+ *	[A] -> [B1 B2]
+ *
+ * where B2 starts at position "pos", and "multi2"
+ *
+ *	[A] -> [D]
+ *
+ * return the multi expression
+ *
+ *	[A] -> [B1 D B2]
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
+	__isl_take MULTI(BASE) *multi1, unsigned pos,
+	__isl_take MULTI(BASE) *multi2)
+{
+	MULTI(BASE) *res;
+	unsigned dim;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	if (pos > dim)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	res = FN(MULTI(BASE),copy)(multi1);
+	res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
+	multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
+
+	res = FN(MULTI(BASE),flat_range_product)(res, multi2);
+	res = FN(MULTI(BASE),flat_range_product)(res, multi1);
+
+	return res;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Given two multi expressions, "multi1"
+ *
+ *	[A1 A2] -> [B1 B2]
+ *
+ * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
+ * and "multi2"
+ *
+ *	[C] -> [D]
+ *
+ * return the multi expression
+ *
+ *	[A1 C A2] -> [B1 D B2]
+ *
+ * We first insert input dimensions to obtain
+ *
+ *	[A1 C A2] -> [B1 B2]
+ *
+ * and
+ *
+ *	[A1 C A2] -> [D]
+ *
+ * and then apply range_splice.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
+	__isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
+	__isl_take MULTI(BASE) *multi2)
+{
+	unsigned n_in1;
+	unsigned n_in2;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
+	if (in_pos > n_in1)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
+
+	multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
+	multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
+						n_in1 - in_pos);
+	multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
+
+	return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+	__attribute__ ((unused));
+
+/* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
+ * return the result.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+{
+	int i;
+	isl_ctx *ctx;
+
+	multi1 = FN(MULTI(BASE),cow)(multi1);
+	if (!multi1 || !multi2)
+		goto error;
+
+	ctx = FN(MULTI(BASE),get_ctx)(multi1);
+	if (!isl_space_is_equal(multi1->space, multi2->space))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+
+	for (i = 0; i < multi1->n; ++i) {
+		multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
+		if (!multi1->p[i])
+			goto error;
+	}
+
+	FN(MULTI(BASE),free)(multi2);
+	return multi1;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Multiply the elements of "multi" by "v" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
+	__isl_take isl_val *v)
+{
+	int i;
+
+	if (!multi || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return multi;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return multi;
+error:
+	isl_val_free(v);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Divide the elements of "multi" by "v" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!multi || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return multi;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,scale_down_val)(multi->p[i],
+						    isl_val_copy(v));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return multi;
+error:
+	isl_val_free(v);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Multiply the elements of "multi" by the corresponding element of "mv"
+ * and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+	int i;
+
+	if (!multi || !mv)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(mv, i);
+		multi->p[i] = FN(EL,scale_val)(multi->p[i], v);
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return multi;
+error:
+	isl_multi_val_free(mv);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Divide the elements of "multi" by the corresponding element of "mv"
+ * and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+	int i;
+
+	if (!multi || !mv)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(mv, i);
+		multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v);
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return multi;
+error:
+	isl_multi_val_free(mv);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+#ifndef NO_MOVE_DIMS
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * We only support moving input dimensions to parameters and vice versa.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+
+	if (n == 0 &&
+	    !isl_space_is_named_or_nested(multi->space, src_type) &&
+	    !isl_space_is_named_or_nested(multi->space, dst_type))
+		return multi;
+
+	if (dst_type == isl_dim_out || src_type == isl_dim_out)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot move output/set dimension",
+			return FN(MULTI(BASE),free)(multi));
+	if (dst_type == isl_dim_div || src_type == isl_dim_div)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot move divs",
+			return FN(MULTI(BASE),free)(multi));
+	if (src_pos + n > isl_space_dim(multi->space, src_type))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range out of bounds",
+			return FN(MULTI(BASE),free)(multi));
+	if (dst_type == src_type)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
+			"moving dims within the same type not supported",
+			return FN(MULTI(BASE),free)(multi));
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
+						src_type, src_pos, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+#endif
+
+/* Convert a multiple expression defined over a parameter domain
+ * into one that is defined over a zero-dimensional set.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_is_set(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"not living in a set space",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_from_range(space);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Are "multi1" and "multi2" obviously equal?
+ */
+int FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
+	__isl_keep MULTI(BASE) *multi2)
+{
+	int i;
+	int equal;
+
+	if (!multi1 || !multi2)
+		return -1;
+	if (multi1->n != multi2->n)
+		return 0;
+	equal = isl_space_is_equal(multi1->space, multi2->space);
+	if (equal < 0 || !equal)
+		return equal;
+
+	for (i = 0; i < multi1->n; ++i) {
+		equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]);
+		if (equal < 0 || !equal)
+			return equal;
+	}
+
+	return 1;
+}
+
+#ifndef NO_DOMAIN
+/* Return the shared domain of the elements of "multi".
+ */
+__isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+	isl_set *dom;
+
+	if (!multi)
+		return NULL;
+
+	dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
+	for (i = 0; i < multi->n; ++i) {
+		isl_set *dom_i;
+
+		dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
+		dom = isl_set_intersect(dom, dom_i);
+	}
+
+	FN(MULTI(BASE),free)(multi);
+	return dom;
+}
+#endif

Added: polly/trunk/lib/External/isl/isl_multi_templ.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_multi_templ.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_multi_templ.h (added)
+++ polly/trunk/lib/External/isl/isl_multi_templ.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,18 @@
+#include <isl/space.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xMULTI(BASE) isl_multi_ ## BASE
+#define MULTI(BASE) xMULTI(BASE)
+
+struct MULTI(BASE) {
+	int ref;
+	isl_space *space;
+
+	int n;
+	EL *p[1];
+};
+
+__isl_give MULTI(BASE) *CAT(MULTI(BASE),_alloc)(__isl_take isl_space *space);

Added: polly/trunk/lib/External/isl/isl_obj.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_obj.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_obj.c (added)
+++ polly/trunk/lib/External/isl/isl_obj.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 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/aff.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/polynomial.h>
+#include <isl/obj.h>
+
+static void *isl_obj_val_copy(void *v)
+{
+	return isl_val_copy((isl_val *)v);
+}
+
+static void isl_obj_val_free(void *v)
+{
+	isl_val_free((isl_val *)v);
+}
+
+static __isl_give isl_printer *isl_obj_val_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_val(p, (isl_val *)v);
+}
+
+static void *isl_obj_val_add(void *v1, void *v2)
+{
+	return isl_val_add((isl_val *) v1, (isl_val *) v2);
+}
+
+struct isl_obj_vtable isl_obj_val_vtable = {
+	isl_obj_val_copy,
+	isl_obj_val_add,
+	isl_obj_val_print,
+	isl_obj_val_free
+};
+
+static void *isl_obj_map_copy(void *v)
+{
+	return isl_map_copy((struct isl_map *)v);
+}
+
+static void isl_obj_map_free(void *v)
+{
+	isl_map_free((struct isl_map *)v);
+}
+
+static __isl_give isl_printer *isl_obj_map_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_map(p, (struct isl_map *)v);
+}
+
+static void *isl_obj_map_add(void *v1, void *v2)
+{
+	return isl_map_union((struct isl_map *)v1, (struct isl_map *)v2);
+}
+
+struct isl_obj_vtable isl_obj_map_vtable = {
+	isl_obj_map_copy,
+	isl_obj_map_add,
+	isl_obj_map_print,
+	isl_obj_map_free
+};
+
+static void *isl_obj_union_map_copy(void *v)
+{
+	return isl_union_map_copy((isl_union_map *)v);
+}
+
+static void isl_obj_union_map_free(void *v)
+{
+	isl_union_map_free((isl_union_map *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_map_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_union_map(p, (isl_union_map *)v);
+}
+
+static void *isl_obj_union_map_add(void *v1, void *v2)
+{
+	return isl_union_map_union((isl_union_map *)v1, (isl_union_map *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_map_vtable = {
+	isl_obj_union_map_copy,
+	isl_obj_union_map_add,
+	isl_obj_union_map_print,
+	isl_obj_union_map_free
+};
+
+static void *isl_obj_set_copy(void *v)
+{
+	return isl_set_copy((struct isl_set *)v);
+}
+
+static void isl_obj_set_free(void *v)
+{
+	isl_set_free((struct isl_set *)v);
+}
+
+static __isl_give isl_printer *isl_obj_set_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_set(p, (struct isl_set *)v);
+}
+
+static void *isl_obj_set_add(void *v1, void *v2)
+{
+	return isl_set_union((struct isl_set *)v1, (struct isl_set *)v2);
+}
+
+struct isl_obj_vtable isl_obj_set_vtable = {
+	isl_obj_set_copy,
+	isl_obj_set_add,
+	isl_obj_set_print,
+	isl_obj_set_free
+};
+
+static void *isl_obj_union_set_copy(void *v)
+{
+	return isl_union_set_copy((isl_union_set *)v);
+}
+
+static void isl_obj_union_set_free(void *v)
+{
+	isl_union_set_free((isl_union_set *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_set_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_union_set(p, (isl_union_set *)v);
+}
+
+static void *isl_obj_union_set_add(void *v1, void *v2)
+{
+	return isl_union_set_union((isl_union_set *)v1, (isl_union_set *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_set_vtable = {
+	isl_obj_union_set_copy,
+	isl_obj_union_set_add,
+	isl_obj_union_set_print,
+	isl_obj_union_set_free
+};
+
+static void *isl_obj_pw_multi_aff_copy(void *v)
+{
+	return isl_pw_multi_aff_copy((isl_pw_multi_aff *) v);
+}
+
+static void isl_obj_pw_multi_aff_free(void *v)
+{
+	isl_pw_multi_aff_free((isl_pw_multi_aff *) v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_multi_aff_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_pw_multi_aff(p, (isl_pw_multi_aff *) v);
+}
+
+static void *isl_obj_pw_multi_aff_add(void *v1, void *v2)
+{
+	return isl_pw_multi_aff_add((isl_pw_multi_aff *) v1,
+				    (isl_pw_multi_aff *) v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_multi_aff_vtable = {
+	isl_obj_pw_multi_aff_copy,
+	isl_obj_pw_multi_aff_add,
+	isl_obj_pw_multi_aff_print,
+	isl_obj_pw_multi_aff_free
+};
+
+static void *isl_obj_none_copy(void *v)
+{
+	return v;
+}
+
+static void isl_obj_none_free(void *v)
+{
+}
+
+static __isl_give isl_printer *isl_obj_none_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return p;
+}
+
+static void *isl_obj_none_add(void *v1, void *v2)
+{
+	return NULL;
+}
+
+struct isl_obj_vtable isl_obj_none_vtable = {
+	isl_obj_none_copy,
+	isl_obj_none_add,
+	isl_obj_none_print,
+	isl_obj_none_free
+};
+
+static void *isl_obj_pw_qp_copy(void *v)
+{
+	return isl_pw_qpolynomial_copy((struct isl_pw_qpolynomial *)v);
+}
+
+static void isl_obj_pw_qp_free(void *v)
+{
+	isl_pw_qpolynomial_free((struct isl_pw_qpolynomial *)v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_qp_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_pw_qpolynomial(p,
+						(struct isl_pw_qpolynomial *)v);
+}
+
+static void *isl_obj_pw_qp_add(void *v1, void *v2)
+{
+	return isl_pw_qpolynomial_add((struct isl_pw_qpolynomial *)v1,
+					(struct isl_pw_qpolynomial *)v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_qpolynomial_vtable = {
+	isl_obj_pw_qp_copy,
+	isl_obj_pw_qp_add,
+	isl_obj_pw_qp_print,
+	isl_obj_pw_qp_free
+};
+
+static void *isl_obj_union_pw_qp_copy(void *v)
+{
+	return isl_union_pw_qpolynomial_copy((struct isl_union_pw_qpolynomial *)v);
+}
+
+static void isl_obj_union_pw_qp_free(void *v)
+{
+	isl_union_pw_qpolynomial_free((struct isl_union_pw_qpolynomial *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_pw_qp_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_union_pw_qpolynomial(p,
+					(struct isl_union_pw_qpolynomial *)v);
+}
+
+static void *isl_obj_union_pw_qp_add(void *v1, void *v2)
+{
+	return isl_union_pw_qpolynomial_add(
+					(struct isl_union_pw_qpolynomial *)v1,
+					(struct isl_union_pw_qpolynomial *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_pw_qpolynomial_vtable = {
+	isl_obj_union_pw_qp_copy,
+	isl_obj_union_pw_qp_add,
+	isl_obj_union_pw_qp_print,
+	isl_obj_union_pw_qp_free
+};
+
+static void *isl_obj_pw_qpf_copy(void *v)
+{
+	return isl_pw_qpolynomial_fold_copy((struct isl_pw_qpolynomial_fold *)v);
+}
+
+static void isl_obj_pw_qpf_free(void *v)
+{
+	isl_pw_qpolynomial_fold_free((struct isl_pw_qpolynomial_fold *)v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_qpf_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_pw_qpolynomial_fold(p,
+					(struct isl_pw_qpolynomial_fold *)v);
+}
+
+static void *isl_obj_pw_qpf_add(void *v1, void *v2)
+{
+	return isl_pw_qpolynomial_fold_fold((struct isl_pw_qpolynomial_fold *)v1,
+					    (struct isl_pw_qpolynomial_fold *)v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable = {
+	isl_obj_pw_qpf_copy,
+	isl_obj_pw_qpf_add,
+	isl_obj_pw_qpf_print,
+	isl_obj_pw_qpf_free
+};
+
+static void *isl_obj_union_pw_qpf_copy(void *v)
+{
+	return isl_union_pw_qpolynomial_fold_copy((struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static void isl_obj_union_pw_qpf_free(void *v)
+{
+	isl_union_pw_qpolynomial_fold_free((struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_pw_qpf_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_union_pw_qpolynomial_fold(p,
+				    (struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static void *isl_obj_union_pw_qpf_add(void *v1, void *v2)
+{
+	return isl_union_pw_qpolynomial_fold_fold(
+				    (struct isl_union_pw_qpolynomial_fold *)v1,
+				    (struct isl_union_pw_qpolynomial_fold *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable = {
+	isl_obj_union_pw_qpf_copy,
+	isl_obj_union_pw_qpf_add,
+	isl_obj_union_pw_qpf_print,
+	isl_obj_union_pw_qpf_free
+};

Added: polly/trunk/lib/External/isl/isl_options.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_options.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_options.c (added)
+++ polly/trunk/lib/External/isl/isl_options.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,305 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isl/ctx.h>
+#include <isl_options_private.h>
+#include <isl/ast_build.h>
+#include <isl/schedule.h>
+#include <isl/version.h>
+
+struct isl_arg_choice isl_pip_context_choice[] = {
+	{"gbr",		ISL_CONTEXT_GBR},
+	{"lexmin",	ISL_CONTEXT_LEXMIN},
+	{0}
+};
+
+struct isl_arg_choice isl_gbr_choice[] = {
+	{"never",	ISL_GBR_NEVER},
+	{"once",	ISL_GBR_ONCE},
+	{"always",	ISL_GBR_ALWAYS},
+	{0}
+};
+
+struct isl_arg_choice isl_closure_choice[] = {
+	{"isl",		ISL_CLOSURE_ISL},
+	{"box",		ISL_CLOSURE_BOX},
+	{0}
+};
+
+static struct isl_arg_choice bound[] = {
+	{"bernstein",	ISL_BOUND_BERNSTEIN},
+	{"range",	ISL_BOUND_RANGE},
+	{0}
+};
+
+static struct isl_arg_choice on_error[] = {
+	{"warn",	ISL_ON_ERROR_WARN},
+	{"continue",	ISL_ON_ERROR_CONTINUE},
+	{"abort",	ISL_ON_ERROR_ABORT},
+	{0}
+};
+
+static struct isl_arg_choice isl_schedule_algorithm_choice[] = {
+	{"isl",		ISL_SCHEDULE_ALGORITHM_ISL},
+	{"feautrier",   ISL_SCHEDULE_ALGORITHM_FEAUTRIER},
+	{0}
+};
+
+static struct isl_arg_flags bernstein_recurse[] = {
+	{"none",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, 0},
+	{"factors",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_FACTORS},
+	{"intervals",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_INTERVALS},
+	{"full",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS},
+	{0}
+};
+
+static struct isl_arg_choice convex[] = {
+	{"wrap",	ISL_CONVEX_HULL_WRAP},
+	{"fm",		ISL_CONVEX_HULL_FM},
+	{0}
+};
+
+static struct isl_arg_choice fuse[] = {
+	{"max",		ISL_SCHEDULE_FUSE_MAX},
+	{"min",		ISL_SCHEDULE_FUSE_MIN},
+	{0}
+};
+
+static struct isl_arg_choice separation_bounds[] = {
+	{"explicit",	ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT},
+	{"implicit",	ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT},
+	{0}
+};
+
+static void print_version(void)
+{
+	printf("%s", isl_version());
+}
+
+ISL_ARGS_START(struct isl_options, isl_options_args)
+ISL_ARG_CHOICE(struct isl_options, context, 0, "context", \
+	isl_pip_context_choice,	ISL_CONTEXT_GBR,
+	"how to handle the pip context tableau")
+ISL_ARG_CHOICE(struct isl_options, gbr, 0, "gbr", \
+	isl_gbr_choice,	ISL_GBR_ALWAYS,
+	"how often to use generalized basis reduction")
+ISL_ARG_CHOICE(struct isl_options, closure, 0, "closure", \
+	isl_closure_choice,	ISL_CLOSURE_ISL,
+	"closure operation to use")
+ISL_ARG_BOOL(struct isl_options, gbr_only_first, 0, "gbr-only-first", 0,
+	"only perform basis reduction in first direction")
+ISL_ARG_CHOICE(struct isl_options, bound, 0, "bound", bound,
+	ISL_BOUND_BERNSTEIN, "algorithm to use for computing bounds")
+ISL_ARG_CHOICE(struct isl_options, on_error, 0, "on-error", on_error,
+	ISL_ON_ERROR_WARN, "how to react if an error is detected")
+ISL_ARG_FLAGS(struct isl_options, bernstein_recurse, 0,
+	"bernstein-recurse", bernstein_recurse, ISL_BERNSTEIN_FACTORS, NULL)
+ISL_ARG_BOOL(struct isl_options, bernstein_triangulate, 0,
+	"bernstein-triangulate", 1,
+	"triangulate domains during Bernstein expansion")
+ISL_ARG_BOOL(struct isl_options, pip_symmetry, 0, "pip-symmetry", 1,
+	"detect simple symmetries in PIP input")
+ISL_ARG_CHOICE(struct isl_options, convex, 0, "convex-hull", \
+	convex,	ISL_CONVEX_HULL_WRAP, "convex hull algorithm to use")
+ISL_ARG_BOOL(struct isl_options, coalesce_bounded_wrapping, 0,
+	"coalesce-bounded-wrapping", 1, "bound wrapping during coalescing")
+ISL_ARG_INT(struct isl_options, schedule_max_coefficient, 0,
+	"schedule-max-coefficient", "limit", -1, "Only consider schedules "
+	"where the coefficients of the variable and parameter dimensions "
+        "do not exceed <limit>. A value of -1 allows arbitrary coefficients.")
+ISL_ARG_INT(struct isl_options, schedule_max_constant_term, 0,
+	"schedule-max-constant-term", "limit", -1, "Only consider schedules "
+	"where the coefficients of the constant dimension do not exceed "
+	"<limit>. A value of -1 allows arbitrary coefficients.")
+ISL_ARG_BOOL(struct isl_options, schedule_parametric, 0,
+	"schedule-parametric", 1, "construct possibly parametric schedules")
+ISL_ARG_BOOL(struct isl_options, schedule_outer_coincidence, 0,
+	"schedule-outer-coincidence", 0,
+	"try to construct schedules where the outer member of each band "
+	"satisfies the coincidence constraints")
+ISL_ARG_BOOL(struct isl_options, schedule_maximize_band_depth, 0,
+	"schedule-maximize-band-depth", 0,
+	"maximize the number of scheduling dimensions in a band")
+ISL_ARG_BOOL(struct isl_options, schedule_split_scaled, 0,
+	"schedule-split-scaled", 1,
+	"split non-tilable bands with scaled schedules")
+ISL_ARG_BOOL(struct isl_options, schedule_separate_components, 0,
+	"schedule-separate-components", 1,
+	"separate components in dependence graph")
+ISL_ARG_CHOICE(struct isl_options, schedule_algorithm, 0,
+	"schedule-algorithm", isl_schedule_algorithm_choice,
+	ISL_SCHEDULE_ALGORITHM_ISL, "scheduling algorithm to use")
+ISL_ARG_CHOICE(struct isl_options, schedule_fuse, 0, "schedule-fuse", fuse,
+	ISL_SCHEDULE_FUSE_MAX, "level of fusion during scheduling")
+ISL_ARG_BOOL(struct isl_options, tile_scale_tile_loops, 0,
+	"tile-scale-tile-loops", 1, "scale tile loops")
+ISL_ARG_BOOL(struct isl_options, tile_shift_point_loops, 0,
+	"tile-shift-point-loops", 1, "shift point loops to start at zero")
+ISL_ARG_STR(struct isl_options, ast_iterator_type, 0,
+	"ast-iterator-type", "type", "int",
+	"type used for iterators during printing of AST")
+ISL_ARG_BOOL(struct isl_options, ast_always_print_block, 0,
+	"ast-always-print-block", 0, "print for and if bodies as a block "
+	"regardless of the number of statements in the body")
+ISL_ARG_BOOL(struct isl_options, ast_build_atomic_upper_bound, 0,
+	"ast-build-atomic-upper-bound", 1, "generate atomic upper bounds")
+ISL_ARG_BOOL(struct isl_options, ast_build_prefer_pdiv, 0,
+	"ast-build-prefer-pdiv", 1, "prefer pdiv operation over fdiv")
+ISL_ARG_BOOL(struct isl_options, ast_build_exploit_nested_bounds, 0,
+	"ast-build-exploit-nested-bounds", 1,
+	"simplify conditions based on bounds of nested for loops")
+ISL_ARG_BOOL(struct isl_options, ast_build_group_coscheduled, 0,
+	"ast-build-group-coscheduled", 0,
+	"keep coscheduled domain elements together")
+ISL_ARG_CHOICE(struct isl_options, ast_build_separation_bounds, 0,
+	"ast-build-separation-bounds", separation_bounds,
+	ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT,
+	"bounds to use during separation")
+ISL_ARG_BOOL(struct isl_options, ast_build_scale_strides, 0,
+	"ast-build-scale-strides", 1,
+	"allow iterators of strided loops to be scaled down")
+ISL_ARG_BOOL(struct isl_options, ast_build_allow_else, 0,
+	"ast-build-allow-else", 1, "generate if statements with else branches")
+ISL_ARG_BOOL(struct isl_options, ast_build_allow_or, 0,
+	"ast-build-allow-or", 1, "generate if conditions with disjunctions")
+ISL_ARG_BOOL(struct isl_options, print_stats, 0, "print-stats", 0,
+	"print statistics for every isl_ctx")
+ISL_ARG_ULONG(struct isl_options, max_operations, 0,
+	"max-operations", 0, "default number of maximal operations per isl_ctx")
+ISL_ARG_VERSION(print_version)
+ISL_ARGS_END
+
+ISL_ARG_DEF(isl_options, struct isl_options, isl_options_args)
+
+ISL_ARG_CTX_DEF(isl_options, struct isl_options, isl_options_args)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	on_error)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	on_error)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	coalesce_bounded_wrapping)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	coalesce_bounded_wrapping)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	gbr_only_first)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	gbr_only_first)
+
+ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_coefficient)
+ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_coefficient)
+
+ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_constant_term)
+ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_constant_term)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_band_depth)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_band_depth)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_split_scaled)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_split_scaled)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_separate_components)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_separate_components)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_outer_coincidence)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_outer_coincidence)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_algorithm)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_algorithm)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_fuse)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_fuse)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_scale_tile_loops)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_scale_tile_loops)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_shift_point_loops)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_shift_point_loops)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_atomic_upper_bound)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_atomic_upper_bound)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_prefer_pdiv)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_prefer_pdiv)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_exploit_nested_bounds)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_exploit_nested_bounds)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_group_coscheduled)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_group_coscheduled)
+
+ISL_CTX_SET_STR_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_iterator_type)
+ISL_CTX_GET_STR_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_iterator_type)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_always_print_block)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_always_print_block)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_separation_bounds)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_separation_bounds)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_scale_strides)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_scale_strides)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_else)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_else)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_or)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_or)

Added: polly/trunk/lib/External/isl/isl_options_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_options_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_options_private.h (added)
+++ polly/trunk/lib/External/isl/isl_options_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,67 @@
+#ifndef ISL_OPTIONS_PRIVATE_H
+#define ISL_OPTIONS_PRIVATE_H
+
+#include <isl/options.h>
+
+struct isl_options {
+	#define			ISL_CONTEXT_GBR		0
+	#define			ISL_CONTEXT_LEXMIN	1
+	unsigned		context;
+
+	#define			ISL_GBR_NEVER	0
+	#define			ISL_GBR_ONCE	1
+	#define			ISL_GBR_ALWAYS	2
+	unsigned		gbr;
+	unsigned		gbr_only_first;
+
+	#define			ISL_CLOSURE_ISL		0
+	#define			ISL_CLOSURE_BOX		1
+	unsigned		closure;
+
+	int			bound;
+	unsigned		on_error;
+
+	#define			ISL_BERNSTEIN_FACTORS	1
+	#define			ISL_BERNSTEIN_INTERVALS	2
+	int			bernstein_recurse;
+
+	int			bernstein_triangulate;
+
+	int			pip_symmetry;
+
+	#define			ISL_CONVEX_HULL_WRAP	0
+	#define			ISL_CONVEX_HULL_FM	1
+	int			convex;
+
+	int			coalesce_bounded_wrapping;
+
+	int			schedule_max_coefficient;
+	int			schedule_max_constant_term;
+	int			schedule_parametric;
+	int			schedule_outer_coincidence;
+	int			schedule_maximize_band_depth;
+	int			schedule_split_scaled;
+	int			schedule_separate_components;
+	unsigned		schedule_algorithm;
+	int			schedule_fuse;
+
+	int			tile_scale_tile_loops;
+	int			tile_shift_point_loops;
+
+	char			*ast_iterator_type;
+	int			ast_always_print_block;
+
+	int			ast_build_atomic_upper_bound;
+	int			ast_build_prefer_pdiv;
+	int			ast_build_exploit_nested_bounds;
+	int			ast_build_group_coscheduled;
+	int			ast_build_separation_bounds;
+	int			ast_build_scale_strides;
+	int			ast_build_allow_else;
+	int			ast_build_allow_or;
+
+	int			print_stats;
+	unsigned long		max_operations;
+};
+
+#endif

Added: polly/trunk/lib/External/isl/isl_output.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_output.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_output.c (added)
+++ polly/trunk/lib/External/isl/isl_output.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,2698 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_polynomial_private.h>
+#include <isl_printer_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/union_map.h>
+#include <isl/constraint.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_val_private.h>
+#include <isl/ast_build.h>
+#include <isl_sort.h>
+
+static const char *s_to[2] = { " -> ", " \\to " };
+static const char *s_and[2] = { " and ", " \\wedge " };
+static const char *s_or[2] = { " or ", " \\vee " };
+static const char *s_le[2] = { "<=", "\\le" };
+static const char *s_ge[2] = { ">=", "\\ge" };
+static const char *s_open_set[2] = { "{ ", "\\{\\, " };
+static const char *s_close_set[2] = { " }", " \\,\\}" };
+static const char *s_open_list[2] = { "[", "(" };
+static const char *s_close_list[2] = { "]", ")" };
+static const char *s_such_that[2] = { " : ", " \\mid " };
+static const char *s_open_exists[2] = { "exists (", "\\exists \\, " };
+static const char *s_close_exists[2] = { ")", "" };
+static const char *s_div_prefix[2] = { "e", "\\alpha_" };
+static const char *s_param_prefix[2] = { "p", "p_" };
+static const char *s_input_prefix[2] = { "i", "i_" };
+static const char *s_output_prefix[2] = { "o", "o_" };
+
+static __isl_give isl_printer *print_constraint_polylib(
+	struct isl_basic_map *bmap, int ineq, int n, __isl_take isl_printer *p)
+{
+	int i;
+	unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	unsigned n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	isl_int *c = ineq ? bmap->ineq[n] : bmap->eq[n];
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, ineq);
+	for (i = 0; i < n_out; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+n_in+i]);
+	}
+	for (i = 0; i < n_in; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+i]);
+	}
+	for (i = 0; i < bmap->n_div; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+n_in+n_out+i]);
+	}
+	for (i = 0; i < nparam; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+i]);
+	}
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_isl_int(p, c[0]);
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+static __isl_give isl_printer *print_constraints_polylib(
+	struct isl_basic_map *bmap, __isl_take isl_printer *p)
+{
+	int i;
+
+	p = isl_printer_set_isl_int_width(p, 5);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		p = print_constraint_polylib(bmap, 0, i, p);
+	for (i = 0; i < bmap->n_ineq; ++i)
+		p = print_constraint_polylib(bmap, 1, i, p);
+
+	return p;
+}
+
+static __isl_give isl_printer *bset_print_constraints_polylib(
+	struct isl_basic_set *bset, __isl_take isl_printer *p)
+{
+	return print_constraints_polylib((struct isl_basic_map *)bset, p);
+}
+
+static __isl_give isl_printer *isl_basic_map_print_polylib(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, int ext)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, bmap->n_eq + bmap->n_ineq);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_int(p, 1 + total + 1);
+	if (ext) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_out));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_in));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_div));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_param));
+	}
+	p = isl_printer_end_line(p);
+	return print_constraints_polylib(bmap, p);
+}
+
+static __isl_give isl_printer *isl_basic_set_print_polylib(
+	__isl_keep isl_basic_set *bset, __isl_take isl_printer *p, int ext)
+{
+	return isl_basic_map_print_polylib((struct isl_basic_map *)bset, p, ext);
+}
+
+static __isl_give isl_printer *isl_map_print_polylib(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, int ext)
+{
+	int i;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, map->n);
+	p = isl_printer_end_line(p);
+	for (i = 0; i < map->n; ++i) {
+		p = isl_printer_start_line(p);
+		p = isl_printer_end_line(p);
+		p = isl_basic_map_print_polylib(map->p[i], p, ext);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *isl_set_print_polylib(__isl_keep isl_set *set,
+	__isl_take isl_printer *p, int ext)
+{
+	return isl_map_print_polylib((struct isl_map *)set, p, ext);
+}
+
+static int count_same_name(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos, const char *name)
+{
+	enum isl_dim_type t;
+	unsigned p, s;
+	int count = 0;
+
+	for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
+		s = t == type ? pos : isl_space_dim(dim, t);
+		for (p = 0; p < s; ++p) {
+			const char *n = isl_space_get_dim_name(dim, t, p);
+			if (n && !strcmp(n, name))
+				count++;
+		}
+	}
+	return count;
+}
+
+static __isl_give isl_printer *print_name(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p, enum isl_dim_type type, unsigned pos,
+	int latex)
+{
+	const char *name;
+	char buffer[20];
+	int primes;
+
+	name = type == isl_dim_div ? NULL : isl_space_get_dim_name(dim, type, pos);
+
+	if (!name) {
+		const char *prefix;
+		if (type == isl_dim_param)
+			prefix = s_param_prefix[latex];
+		else if (type == isl_dim_div)
+			prefix = s_div_prefix[latex];
+		else if (isl_space_is_set(dim) || type == isl_dim_in)
+			prefix = s_input_prefix[latex];
+		else
+			prefix = s_output_prefix[latex];
+		snprintf(buffer, sizeof(buffer), "%s%d", prefix, pos);
+		name = buffer;
+	}
+	primes = count_same_name(dim, name == buffer ? isl_dim_div : type,
+				 pos, name);
+	p = isl_printer_print_str(p, name);
+	while (primes-- > 0)
+		p = isl_printer_print_str(p, "'");
+	return p;
+}
+
+static enum isl_dim_type pos2type(__isl_keep isl_space *dim, unsigned *pos)
+{
+	enum isl_dim_type type;
+	unsigned n_in = isl_space_dim(dim, isl_dim_in);
+	unsigned n_out = isl_space_dim(dim, isl_dim_out);
+	unsigned nparam = isl_space_dim(dim, isl_dim_param);
+
+	if (*pos < 1 + nparam) {
+		type = isl_dim_param;
+		*pos -= 1;
+	} else if (*pos < 1 + nparam + n_in) {
+		type = isl_dim_in;
+		*pos -= 1 + nparam;
+	} else if (*pos < 1 + nparam + n_in + n_out) {
+		type = isl_dim_out;
+		*pos -= 1 + nparam + n_in;
+	} else {
+		type = isl_dim_div;
+		*pos -= 1 + nparam + n_in + n_out;
+	}
+
+	return type;
+}
+
+static __isl_give isl_printer *print_div(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div, int pos, __isl_take isl_printer *p);
+
+static __isl_give isl_printer *print_term(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div,
+	isl_int c, unsigned pos, __isl_take isl_printer *p, int latex)
+{
+	enum isl_dim_type type;
+	int print_div_def;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	type = pos2type(dim, &pos);
+	print_div_def = type == isl_dim_div && div &&
+			!isl_int_is_zero(div->row[pos][0]);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		if (p->output_format == ISL_FORMAT_C || print_div_def)
+			p = isl_printer_print_str(p, "*");
+	}
+	if (print_div_def)
+		p = print_div(dim, div, pos, p);
+	else
+		p = print_name(dim, p, type, pos, latex);
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_of_len(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div,
+	__isl_take isl_printer *p, isl_int *c, int len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_term(dim, div, c[i], i, p, 0);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+static __isl_give isl_printer *print_affine(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, isl_int *c)
+{
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+	return print_affine_of_len(dim, NULL, p, c, len);
+}
+
+/* Internal data structure for print_space.
+ *
+ * latex is set if that is the output format.
+ * print_dim (if not NULL) is called on each dimension.
+ * user is set by the caller of print_space and may be used inside print_dim.
+ *
+ * space is the global space that is being printed.  This field is set by
+ *	print_space.
+ * type is the tuple of the global space that is currently being printed.
+ *	This field is set by print_space.
+ */
+struct isl_print_space_data {
+	int latex;
+	__isl_give isl_printer *(*print_dim)(__isl_take isl_printer *p,
+		struct isl_print_space_data *data, unsigned pos);
+	void *user;
+
+	isl_space *space;
+	enum isl_dim_type type;
+};
+
+/* offset is the offset of local_dim inside data->type of data->space.
+ */
+static __isl_give isl_printer *print_nested_var_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim, enum isl_dim_type local_type,
+	struct isl_print_space_data *data, int offset)
+{
+	int i;
+
+	if (data->space != local_dim && local_type == isl_dim_out)
+		offset += local_dim->n_in;
+
+	for (i = 0; i < isl_space_dim(local_dim, local_type); ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		if (data->print_dim)
+			p = data->print_dim(p, data, offset + i);
+		else
+			p = print_name(data->space, p, data->type, offset + i,
+					data->latex);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_var_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, enum isl_dim_type type)
+{
+	struct isl_print_space_data data = { .space = space, .type = type };
+
+	return print_nested_var_list(p, space, type, &data, 0);
+}
+
+static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim,
+	struct isl_print_space_data *data, int offset);
+
+static __isl_give isl_printer *print_nested_tuple(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim, enum isl_dim_type local_type,
+	struct isl_print_space_data *data, int offset)
+{
+	const char *name = NULL;
+	unsigned n = isl_space_dim(local_dim, local_type);
+	if ((local_type == isl_dim_in || local_type == isl_dim_out)) {
+		name = isl_space_get_tuple_name(local_dim, local_type);
+		if (name) {
+			if (data->latex)
+				p = isl_printer_print_str(p, "\\mathrm{");
+			p = isl_printer_print_str(p, name);
+			if (data->latex)
+				p = isl_printer_print_str(p, "}");
+		}
+	}
+	if (!data->latex || n != 1 || name)
+		p = isl_printer_print_str(p, s_open_list[data->latex]);
+	if ((local_type == isl_dim_in || local_type == isl_dim_out) &&
+	    local_dim->nested[local_type - isl_dim_in]) {
+		if (data->space != local_dim && local_type == isl_dim_out)
+			offset += local_dim->n_in;
+		p = print_nested_map_dim(p,
+				local_dim->nested[local_type - isl_dim_in],
+				data, offset);
+	} else
+		p = print_nested_var_list(p, local_dim, local_type, data,
+					  offset);
+	if (!data->latex || n != 1 || name)
+		p = isl_printer_print_str(p, s_close_list[data->latex]);
+	return p;
+}
+
+static __isl_give isl_printer *print_tuple(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p, enum isl_dim_type type,
+	struct isl_print_space_data *data)
+{
+	data->space = dim;
+	data->type = type;
+	return print_nested_tuple(p, dim, type, data, 0);
+}
+
+static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim,
+	struct isl_print_space_data *data, int offset)
+{
+	p = print_nested_tuple(p, local_dim, isl_dim_in, data, offset);
+	p = isl_printer_print_str(p, s_to[data->latex]);
+	p = print_nested_tuple(p, local_dim, isl_dim_out, data, offset);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_space(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p, int rational,
+	struct isl_print_space_data *data)
+{
+	if (rational && !data->latex)
+		p = isl_printer_print_str(p, "rat: ");
+	if (isl_space_is_params(dim))
+		;
+	else if (isl_space_is_set(dim))
+		p = print_tuple(dim, p, isl_dim_set, data);
+	else {
+		p = print_tuple(dim, p, isl_dim_in, data);
+		p = isl_printer_print_str(p, s_to[data->latex]);
+		p = print_tuple(dim, p, isl_dim_out, data);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_omega_parameters(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p)
+{
+	if (isl_space_dim(dim, isl_dim_param) == 0)
+		return p;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "symbolic ");
+	p = print_var_list(p, dim, isl_dim_param);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+static __isl_give isl_printer *print_constraint(struct isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p,
+	isl_int *c, int last, const char *op, int first_constraint, int latex)
+{
+	if (!first_constraint)
+		p = isl_printer_print_str(p, s_and[latex]);
+
+	isl_int_abs(c[last], c[last]);
+
+	p = print_term(dim, NULL, c[last], last, p, latex);
+
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, op);
+	p = isl_printer_print_str(p, " ");
+
+	isl_int_set_si(c[last], 0);
+	p = print_affine(bmap, dim, p, c);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, int latex)
+{
+	int i;
+	struct isl_vec *c;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	c = isl_vec_alloc(bmap->ctx, 1 + total);
+	if (!c)
+		goto error;
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		int l = isl_seq_last_non_zero(bmap->eq[i], 1 + total);
+		if (l < 0) {
+			if (i != bmap->n_eq - 1)
+				p = isl_printer_print_str(p, s_and[latex]);
+			p = isl_printer_print_str(p, "0 = 0");
+			continue;
+		}
+		if (isl_int_is_neg(bmap->eq[i][l]))
+			isl_seq_cpy(c->el, bmap->eq[i], 1 + total);
+		else
+			isl_seq_neg(c->el, bmap->eq[i], 1 + total);
+		p = print_constraint(bmap, dim, p, c->el, l,
+				    "=", i == bmap->n_eq - 1, latex);
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		int l = isl_seq_last_non_zero(bmap->ineq[i], 1 + total);
+		int s;
+		const char *op;
+		if (l < 0)
+			continue;
+		s = isl_int_sgn(bmap->ineq[i][l]);
+		if (s < 0)
+			isl_seq_cpy(c->el, bmap->ineq[i], 1 + total);
+		else
+			isl_seq_neg(c->el, bmap->ineq[i], 1 + total);
+		op = s < 0 ? s_le[latex] : s_ge[latex];
+		p = print_constraint(bmap, dim, p, c->el, l,
+					op, !bmap->n_eq && !i, latex);
+	}
+
+	isl_vec_free(c);
+
+	return p;
+error:
+	isl_vec_free(c);
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_div(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div, int pos, __isl_take isl_printer *p)
+{
+	int c = p->output_format == ISL_FORMAT_C;
+	p = isl_printer_print_str(p, c ? "floord(" : "floor((");
+	p = print_affine_of_len(dim, div, p,
+				div->row[pos] + 1, div->n_col - 1);
+	p = isl_printer_print_str(p, c ? ", " : ")/");
+	p = isl_printer_print_isl_int(p, div->row[pos][0]);
+	p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+/* Print a comma separated list of div names, with their definitions
+ * (provided that they have a definition and we are printing in isl format).
+ */
+static __isl_give isl_printer *print_div_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div, int latex)
+{
+	int i;
+	unsigned n_div;
+
+	if (!p || !space || !div)
+		return isl_printer_free(p);
+
+	n_div = isl_mat_rows(div);
+
+	for (i = 0; i < n_div; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_name(space, p, isl_dim_div, i, latex);
+		if (p->output_format != ISL_FORMAT_ISL ||
+		    isl_int_is_zero(div->row[i][0]))
+			continue;
+		p = isl_printer_print_str(p, " = ");
+		p = print_div(space, div, i, p);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_disjunct(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, int latex)
+{
+	if (bmap->n_div > 0) {
+		isl_space *space;
+		isl_mat *div;
+
+		space = isl_basic_map_get_space(bmap);
+		div = isl_basic_map_get_divs(bmap);
+		p = isl_printer_print_str(p, s_open_exists[latex]);
+		p = print_div_list(p, space, div, latex);
+		isl_space_free(space);
+		isl_mat_free(div);
+		p = isl_printer_print_str(p, ": ");
+	}
+
+	p = print_constraints(bmap, dim, p, latex);
+
+	if (bmap->n_div > 0)
+		p = isl_printer_print_str(p, s_close_exists[latex]);
+	return p;
+}
+
+/* Print a colon followed by the constraints of "bmap"
+ * to "p", provided there are any constraints.
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ */
+static __isl_give isl_printer *print_optional_disjunct(
+	__isl_keep isl_basic_map *bmap, __isl_keep isl_space *space,
+	__isl_take isl_printer *p, int latex)
+{
+	if (isl_basic_map_is_universe(bmap))
+		return p;
+
+	p = isl_printer_print_str(p, ": ");
+	p = print_disjunct(bmap, space, p, latex);
+
+	return p;
+}
+
+static __isl_give isl_printer *basic_map_print_omega(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p)
+{
+	p = isl_printer_print_str(p, "{ [");
+	p = print_var_list(p, bmap->dim, isl_dim_in);
+	p = isl_printer_print_str(p, "] -> [");
+	p = print_var_list(p, bmap->dim, isl_dim_out);
+	p = isl_printer_print_str(p, "] ");
+	p = print_optional_disjunct(bmap, bmap->dim, p, 0);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *basic_set_print_omega(
+	__isl_keep isl_basic_set *bset, __isl_take isl_printer *p)
+{
+	p = isl_printer_print_str(p, "{ [");
+	p = print_var_list(p, bset->dim, isl_dim_set);
+	p = isl_printer_print_str(p, "] ");
+	p = print_optional_disjunct(bset, bset->dim, p, 0);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_omega(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	int i;
+
+	for (i = 0; i < map->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " union ");
+		p = basic_map_print_omega(map->p[i], p);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *isl_set_print_omega(__isl_keep isl_set *set,
+	__isl_take isl_printer *p)
+{
+	int i;
+
+	for (i = 0; i < set->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " union ");
+		p = basic_set_print_omega(set->p[i], p);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *isl_basic_map_print_isl(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p,
+	int latex)
+{
+	struct isl_print_space_data data = { .latex = latex };
+	int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+
+	if (isl_basic_map_dim(bmap, isl_dim_param) > 0) {
+		p = print_tuple(bmap->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = print_space(bmap->dim, p, rational, &data);
+	p = isl_printer_print_str(p, " : ");
+	p = print_disjunct(bmap, bmap->dim, p, latex);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, int latex)
+{
+	int i;
+
+	if (isl_map_plain_is_universe(map))
+		return p;
+
+	p = isl_printer_print_str(p, s_such_that[latex]);
+	if (map->n == 0)
+		p = isl_printer_print_str(p, "1 = 0");
+	for (i = 0; i < map->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, s_or[latex]);
+		if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1)
+			p = isl_printer_print_str(p, "(");
+		p = print_disjunct(map->p[i], map->dim, p, latex);
+		if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+/* Print the disjuncts of a map (or set).
+ * If the map turns out to be a universal parameter domain, then
+ * we need to print the colon.  Otherwise, the output looks identical
+ * to the empty set.
+ */
+static __isl_give isl_printer *print_disjuncts_map(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, int latex)
+{
+	if (isl_map_plain_is_universe(map) && isl_space_is_params(map->dim))
+		return isl_printer_print_str(p, s_such_that[latex]);
+	else
+		return print_disjuncts(map, p, latex);
+}
+
+struct isl_aff_split {
+	isl_basic_map *aff;
+	isl_map *map;
+};
+
+static void free_split(__isl_take struct isl_aff_split *split, int n)
+{
+	int i;
+
+	if (!split)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		isl_basic_map_free(split[i].aff);
+		isl_map_free(split[i].map);
+	}
+
+	free(split);
+}
+
+static __isl_give isl_basic_map *get_aff(__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned nparam, n_in, n_out, total;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_free_inequality(bmap, bmap->n_ineq) < 0)
+		goto error;
+
+	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);
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		j = isl_seq_last_non_zero(bmap->eq[i] + 1, total);
+		if (j >= nparam && j < nparam + n_in + n_out &&
+		    (isl_int_is_one(bmap->eq[i][1 + j]) ||
+		     isl_int_is_negone(bmap->eq[i][1 + j])))
+			continue;
+		if (isl_basic_map_drop_equality(bmap, i) < 0)
+			goto error;
+	}
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static int aff_split_cmp(const void *p1, const void *p2, void *user)
+{
+	const struct isl_aff_split *s1, *s2;
+	s1 = (const struct isl_aff_split *) p1;
+	s2 = (const struct isl_aff_split *) p2;
+
+	return isl_basic_map_plain_cmp(s1->aff, s2->aff);
+}
+
+static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap,
+	__isl_keep isl_basic_map *aff)
+{
+	int i, j;
+	unsigned total;
+
+	if (!bmap || !aff)
+		goto error;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total,
+					    bmap->n_div) != -1)
+			continue;
+		for (j = 0; j < aff->n_eq; ++j) {
+			if (!isl_seq_eq(bmap->eq[i], aff->eq[j], 1 + total) &&
+			    !isl_seq_is_neg(bmap->eq[i], aff->eq[j], 1 + total))
+				continue;
+			if (isl_basic_map_drop_equality(bmap, i) < 0)
+				goto error;
+			break;
+		}
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map)
+{
+	int i, n;
+	struct isl_aff_split *split;
+	isl_ctx *ctx;
+
+	ctx = isl_map_get_ctx(map);
+	split = isl_calloc_array(ctx, struct isl_aff_split, map->n);
+	if (!split)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_basic_map *bmap;
+		split[i].aff = get_aff(isl_basic_map_copy(map->p[i]));
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = isl_basic_map_cow(bmap);
+		bmap = drop_aff(bmap, split[i].aff);
+		split[i].map = isl_map_from_basic_map(bmap);
+		if (!split[i].aff || !split[i].map)
+			goto error;
+	}
+
+	if (isl_sort(split, map->n, sizeof(struct isl_aff_split),
+			&aff_split_cmp, NULL) < 0)
+		goto error;
+
+	n = map->n;
+	for (i = n - 1; i >= 1; --i) {
+		if (!isl_basic_map_plain_is_equal(split[i - 1].aff,
+						 split[i].aff))
+			continue;
+		isl_basic_map_free(split[i].aff);
+		split[i - 1].map = isl_map_union(split[i - 1].map,
+						 split[i].map);
+		if (i != n - 1)
+			split[i] = split[n - 1];
+		split[n - 1].aff = NULL;
+		split[n - 1].map = NULL;
+		--n;
+	}
+
+	return split;
+error:
+	free_split(split, map->n);
+	return NULL;
+}
+
+static int defining_equality(__isl_keep isl_basic_map *eq,
+	__isl_keep isl_space *dim, enum isl_dim_type type, int pos)
+{
+	int i;
+	unsigned total;
+
+	if (!eq)
+		return -1;
+
+	pos += isl_space_offset(dim, type);
+	total = isl_basic_map_total_dim(eq);
+
+	for (i = 0; i < eq->n_eq; ++i) {
+		if (isl_seq_last_non_zero(eq->eq[i] + 1, total) != pos)
+			continue;
+		if (isl_int_is_one(eq->eq[i][1 + pos]))
+			isl_seq_neg(eq->eq[i], eq->eq[i], 1 + total);
+		return i;
+	}
+
+	return -1;
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_basic_map keeping track of equalities.
+ *
+ * If the current dimension is defined by these equalities, then print
+ * the corresponding expression.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_eq(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_basic_map *eq = data->user;
+	int j;
+
+	j = defining_equality(eq, data->space, data->type, pos);
+	if (j >= 0) {
+		pos += 1 + isl_space_offset(data->space, data->type);
+		p = print_affine_of_len(eq->dim, NULL, p, eq->eq[j], pos);
+	} else {
+		p = print_name(data->space, p, data->type, pos, data->latex);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p,
+	struct isl_aff_split *split, int n)
+{
+	struct isl_print_space_data data = { 0 };
+	int i;
+	int rational;
+
+	data.print_dim = &print_dim_eq;
+	for (i = 0; i < n; ++i) {
+		isl_space *dim;
+
+		if (!split[i].map)
+			break;
+		dim = split[i].map->dim;
+		rational = split[i].map->n > 0 &&
+		    ISL_F_ISSET(split[i].map->p[0], ISL_BASIC_MAP_RATIONAL);
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		data.user = split[i].aff;
+		p = print_space(dim, p, rational, &data);
+		p = print_disjuncts_map(split[i].map, p, 0);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_isl_body(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	struct isl_print_space_data data = { 0 };
+	struct isl_aff_split *split = NULL;
+	int rational;
+
+	if (map->n > 0)
+		split = split_aff(map);
+	if (split) {
+		p = print_split_map(p, split, map->n);
+	} else {
+		rational = map->n > 0 &&
+		    ISL_F_ISSET(map->p[0], ISL_BASIC_MAP_RATIONAL);
+		p = print_space(map->dim, p, rational, &data);
+		p = print_disjuncts_map(map, p, 0);
+	}
+	free_split(split, map->n);
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_isl(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (isl_map_dim(map, isl_dim_param) > 0) {
+		p = print_tuple(map->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	p = isl_printer_print_str(p, s_open_set[0]);
+	p = isl_map_print_isl_body(map, p);
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+static __isl_give isl_printer *print_latex_map(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, __isl_keep isl_basic_map *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	data.latex = 1;
+	if (isl_map_dim(map, isl_dim_param) > 0) {
+		p = print_tuple(map->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, s_to[1]);
+	}
+	p = isl_printer_print_str(p, s_open_set[1]);
+	data.print_dim = &print_dim_eq;
+	data.user = aff;
+	p = print_space(map->dim, p, 0, &data);
+	p = print_disjuncts_map(map, p, 1);
+	p = isl_printer_print_str(p, s_close_set[1]);
+
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_latex(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	int i;
+	struct isl_aff_split *split = NULL;
+
+	if (map->n > 0)
+		split = split_aff(map);
+
+	if (!split)
+		return print_latex_map(map, p, NULL);
+
+	for (i = 0; i < map->n; ++i) {
+		if (!split[i].map)
+			break;
+		if (i)
+			p = isl_printer_print_str(p, " \\cup ");
+		p = print_latex_map(split[i].map, p, split[i].aff);
+	}
+
+	free_split(split, map->n);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_basic_map(__isl_take isl_printer *p,
+	__isl_keep isl_basic_map *bmap)
+{
+	if (!p || !bmap)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_basic_map_print_isl(bmap, p, 0);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return basic_map_print_omega(bmap, p);
+	isl_assert(bmap->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_basic_map_print(__isl_keep isl_basic_map *bmap, FILE *out, int indent,
+	const char *prefix, const char *suffix, unsigned output_format)
+{
+	isl_printer *printer;
+
+	if (!bmap)
+		return;
+
+	printer = isl_printer_to_file(bmap->ctx, out);
+	printer = isl_printer_set_indent(printer, indent);
+	printer = isl_printer_set_prefix(printer, prefix);
+	printer = isl_printer_set_suffix(printer, suffix);
+	printer = isl_printer_set_output_format(printer, output_format);
+	isl_printer_print_basic_map(printer, bmap);
+
+	isl_printer_free(printer);
+}
+
+__isl_give isl_printer *isl_printer_print_basic_set(__isl_take isl_printer *p,
+	__isl_keep isl_basic_set *bset)
+{
+	if (!p || !bset)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_basic_map_print_isl(bset, p, 0);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_basic_set_print_polylib(bset, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_basic_set_print_polylib(bset, p, 1);
+	else if (p->output_format == ISL_FORMAT_POLYLIB_CONSTRAINTS)
+		return bset_print_constraints_polylib(bset, p);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return basic_set_print_omega(bset, p);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_basic_set_print(struct isl_basic_set *bset, FILE *out, int indent,
+	const char *prefix, const char *suffix, unsigned output_format)
+{
+	isl_printer *printer;
+
+	if (!bset)
+		return;
+
+	printer = isl_printer_to_file(bset->ctx, out);
+	printer = isl_printer_set_indent(printer, indent);
+	printer = isl_printer_set_prefix(printer, prefix);
+	printer = isl_printer_set_suffix(printer, suffix);
+	printer = isl_printer_set_output_format(printer, output_format);
+	isl_printer_print_basic_set(printer, bset);
+
+	isl_printer_free(printer);
+}
+
+__isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *p,
+	__isl_keep isl_set *set)
+{
+	if (!p || !set)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_map_print_isl((isl_map *)set, p);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_set_print_polylib(set, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_set_print_polylib(set, p, 1);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return isl_set_print_omega(set, p);
+	else if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_map_print_latex((isl_map *)set, p);
+	isl_assert(set->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_set_print(struct isl_set *set, FILE *out, int indent,
+	unsigned output_format)
+{
+	isl_printer *printer;
+
+	if (!set)
+		return;
+
+	printer = isl_printer_to_file(set->ctx, out);
+	printer = isl_printer_set_indent(printer, indent);
+	printer = isl_printer_set_output_format(printer, output_format);
+	printer = isl_printer_print_set(printer, set);
+
+	isl_printer_free(printer);
+}
+
+__isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *p,
+	__isl_keep isl_map *map)
+{
+	if (!p || !map)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_map_print_isl(map, p);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_map_print_polylib(map, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_map_print_polylib(map, p, 1);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return isl_map_print_omega(map, p);
+	else if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_map_print_latex(map, p);
+	isl_assert(map->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+struct isl_union_print_data {
+	isl_printer *p;
+	int first;
+};
+
+static int print_map_body(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_map_print_isl_body(map, data->p);
+	isl_map_free(map);
+
+	return 0;
+}
+
+static __isl_give isl_printer *isl_union_map_print_isl(
+	__isl_keep isl_union_map *umap, __isl_take isl_printer *p)
+{
+	struct isl_union_print_data data = { p, 1 };
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *dim;
+
+	dim = isl_union_map_get_space(umap);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	isl_space_free(dim);
+	p = isl_printer_print_str(p, s_open_set[0]);
+	isl_union_map_foreach_map(umap, &print_map_body, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+static int print_latex_map_body(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, " \\cup ");
+	data->first = 0;
+
+	data->p = isl_map_print_latex(map, data->p);
+	isl_map_free(map);
+
+	return 0;
+}
+
+static __isl_give isl_printer *isl_union_map_print_latex(
+	__isl_keep isl_union_map *umap, __isl_take isl_printer *p)
+{
+	struct isl_union_print_data data = { p, 1 };
+	isl_union_map_foreach_map(umap, &print_latex_map_body, &data);
+	p = data.p;
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p,
+	__isl_keep isl_union_map *umap)
+{
+	if (!p || !umap)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_union_map_print_isl(umap, p);
+	if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_union_map_print_latex(umap, p);
+
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_map", goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p,
+	__isl_keep isl_union_set *uset)
+{
+	if (!p || !uset)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_union_map_print_isl((isl_union_map *)uset, p);
+	if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_union_map_print_latex((isl_union_map *)uset, p);
+
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_set", goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_map_print(__isl_keep isl_map *map, FILE *out, int indent,
+	unsigned output_format)
+{
+	isl_printer *printer;
+
+	if (!map)
+		return;
+
+	printer = isl_printer_to_file(map->ctx, out);
+	printer = isl_printer_set_indent(printer, indent);
+	printer = isl_printer_set_output_format(printer, output_format);
+	printer = isl_printer_print_map(printer, map);
+
+	isl_printer_free(printer);
+}
+
+static int upoly_rec_n_non_zero(__isl_keep struct isl_upoly_rec *rec)
+{
+	int i;
+	int n;
+
+	for (i = 0, n = 0; i < rec->n; ++i)
+		if (!isl_upoly_is_zero(rec->p[i]))
+			++n;
+
+	return n;
+}
+
+static __isl_give isl_printer *upoly_print_cst(__isl_keep struct isl_upoly *up,
+	__isl_take isl_printer *p, int first)
+{
+	struct isl_upoly_cst *cst;
+	int neg;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		goto error;
+	neg = !first && isl_int_is_neg(cst->n);
+	if (!first)
+		p = isl_printer_print_str(p, neg ? " - " :  " + ");
+	if (neg)
+		isl_int_neg(cst->n, cst->n);
+	if (isl_int_is_zero(cst->d)) {
+		int sgn = isl_int_sgn(cst->n);
+		p = isl_printer_print_str(p, sgn < 0 ? "-infty" :
+					    sgn == 0 ? "NaN" : "infty");
+	} else
+		p = isl_printer_print_isl_int(p, cst->n);
+	if (neg)
+		isl_int_neg(cst->n, cst->n);
+	if (!isl_int_is_zero(cst->d) && !isl_int_is_one(cst->d)) {
+		p = isl_printer_print_str(p, "/");
+		p = isl_printer_print_isl_int(p, cst->d);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_base(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div, int var)
+{
+	unsigned total;
+
+	total = isl_space_dim(dim, isl_dim_all);
+	if (var < total)
+		p = print_term(dim, NULL, dim->ctx->one, 1 + var, p, 0);
+	else
+		p = print_div(dim, div, var - total, p);
+	return p;
+}
+
+static __isl_give isl_printer *print_pow(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div, int var, int exp)
+{
+	p = print_base(p, dim, div, var);
+	if (exp == 1)
+		return p;
+	if (p->output_format == ISL_FORMAT_C) {
+		int i;
+		for (i = 1; i < exp; ++i) {
+			p = isl_printer_print_str(p, "*");
+			p = print_base(p, dim, div, var);
+		}
+	} else {
+		p = isl_printer_print_str(p, "^");
+		p = isl_printer_print_int(p, exp);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *upoly_print(__isl_keep struct isl_upoly *up,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p, int outer)
+{
+	int i, n, first, print_parens;
+	struct isl_upoly_rec *rec;
+
+	if (!p || !up || !dim || !div)
+		goto error;
+
+	if (isl_upoly_is_cst(up))
+		return upoly_print_cst(up, p, 1);
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+	n = upoly_rec_n_non_zero(rec);
+	print_parens = n > 1 ||
+		    (outer && rec->up.var >= isl_space_dim(dim, isl_dim_all));
+	if (print_parens)
+		p = isl_printer_print_str(p, "(");
+	for (i = 0, first = 1; i < rec->n; ++i) {
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		if (isl_upoly_is_negone(rec->p[i])) {
+			if (!i)
+				p = isl_printer_print_str(p, "-1");
+			else if (first)
+				p = isl_printer_print_str(p, "-");
+			else
+				p = isl_printer_print_str(p, " - ");
+		} else if (isl_upoly_is_cst(rec->p[i]) &&
+				!isl_upoly_is_one(rec->p[i]))
+			p = upoly_print_cst(rec->p[i], p, first);
+		else {
+			if (!first)
+				p = isl_printer_print_str(p, " + ");
+			if (i == 0 || !isl_upoly_is_one(rec->p[i]))
+				p = upoly_print(rec->p[i], dim, div, p, 0);
+		}
+		first = 0;
+		if (i == 0)
+			continue;
+		if (!isl_upoly_is_one(rec->p[i]) &&
+		    !isl_upoly_is_negone(rec->p[i]))
+			p = isl_printer_print_str(p, " * ");
+		p = print_pow(p, dim, div, rec->up.var, i);
+	}
+	if (print_parens)
+		p = isl_printer_print_str(p, ")");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial(__isl_take isl_printer *p,
+	__isl_keep isl_qpolynomial *qp)
+{
+	if (!p || !qp)
+		goto error;
+	p = upoly_print(qp->upoly, qp->dim, qp->div, p, 1);
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial_isl(__isl_take isl_printer *p,
+	__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!p || !qp)
+		goto error;
+
+	if (isl_space_dim(qp->dim, isl_dim_param) > 0) {
+		p = print_tuple(qp->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	if (!isl_space_is_params(qp->dim)) {
+		p = print_space(qp->dim, p, 0, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = print_qpolynomial(p, qp);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_qpolynomial *qp)
+{
+	isl_int den;
+
+	isl_int_init(den);
+	isl_qpolynomial_get_den(qp, &den);
+	if (!isl_int_is_one(den)) {
+		isl_qpolynomial *f;
+		p = isl_printer_print_str(p, "(");
+		qp = isl_qpolynomial_copy(qp);
+		f = isl_qpolynomial_rat_cst_on_domain(isl_space_copy(qp->dim),
+						den, qp->dim->ctx->one);
+		qp = isl_qpolynomial_mul(qp, f);
+	}
+	if (qp)
+		p = upoly_print(qp->upoly, dim, qp->div, p, 0);
+	else
+		p = isl_printer_free(p);
+	if (!isl_int_is_one(den)) {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, den);
+		isl_qpolynomial_free(qp);
+	}
+	isl_int_clear(den);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp)
+{
+	if (!p || !qp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_qpolynomial_isl(p, qp);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_qpolynomial_c(p, qp->dim, qp);
+	else
+		isl_die(qp->dim->ctx, isl_error_unsupported,
+			"output format not supported for isl_qpolynomials",
+			goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out,
+	unsigned output_format)
+{
+	isl_printer *p;
+
+	if  (!qp)
+		return;
+
+	isl_assert(qp->dim->ctx, output_format == ISL_FORMAT_ISL, return);
+	p = isl_printer_to_file(qp->dim->ctx, out);
+	p = isl_printer_print_qpolynomial(p, qp);
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *qpolynomial_fold_print(
+	__isl_keep isl_qpolynomial_fold *fold, __isl_take isl_printer *p)
+{
+	int i;
+
+	if (fold->type == isl_fold_min)
+		p = isl_printer_print_str(p, "min");
+	else if (fold->type == isl_fold_max)
+		p = isl_printer_print_str(p, "max");
+	p = isl_printer_print_str(p, "(");
+	for (i = 0; i < fold->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_qpolynomial(p, fold->qp[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold,
+	FILE *out, unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!fold)
+		return;
+
+	isl_assert(fold->dim->ctx, output_format == ISL_FORMAT_ISL, return);
+
+	p = isl_printer_to_file(fold->dim->ctx, out);
+	p = isl_printer_print_qpolynomial_fold(p, fold);
+
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *isl_pwqp_print_isl_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	struct isl_print_space_data data = { 0 };
+	int i = 0;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		if (!isl_space_is_params(pwqp->p[i].set->dim)) {
+			p = print_space(pwqp->p[i].set->dim, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = print_qpolynomial(p, pwqp->p[i].qp);
+		p = print_disjuncts((isl_map *)pwqp->p[i].set, p, 0);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_isl(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!p || !pwqp)
+		goto error;
+
+	if (isl_space_dim(pwqp->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwqp->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	if (pwqp->n == 0) {
+		if (!isl_space_is_set(pwqp->dim)) {
+			p = print_tuple(pwqp->dim, p, isl_dim_in, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = isl_printer_print_str(p, "0");
+	}
+	p = isl_pwqp_print_isl_body(p, pwqp);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out,
+	unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!pwqp)
+		return;
+
+	p = isl_printer_to_file(pwqp->dim->ctx, out);
+	p = isl_printer_set_output_format(p, output_format);
+	p = isl_printer_print_pw_qpolynomial(p, pwqp);
+
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *isl_pwf_print_isl_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	struct isl_print_space_data data = { 0 };
+	int i = 0;
+
+	for (i = 0; i < pwf->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		if (!isl_space_is_params(pwf->p[i].set->dim)) {
+			p = print_space(pwf->p[i].set->dim, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = qpolynomial_fold_print(pwf->p[i].fold, p);
+		p = print_disjuncts((isl_map *)pwf->p[i].set, p, 0);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_fold_isl(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (isl_space_dim(pwf->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwf->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	if (pwf->n == 0) {
+		if (!isl_space_is_set(pwf->dim)) {
+			p = print_tuple(pwf->dim, p, isl_dim_in, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = isl_printer_print_str(p, "0");
+	}
+	p = isl_pwf_print_isl_body(p, pwf);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c);
+
+static __isl_give isl_printer *print_name_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type, unsigned pos)
+{
+	if (type == isl_dim_div) {
+		p = isl_printer_print_str(p, "floord(");
+		p = print_affine_c(p, dim, bset, bset->div[pos] + 1);
+		p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, bset->div[pos][0]);
+		p = isl_printer_print_str(p, ")");
+	} else {
+		const char *name;
+
+		name = isl_space_get_dim_name(dim, type, pos);
+		if (!name)
+			name = "UNNAMED";
+		p = isl_printer_print_str(p, name);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_term_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int c, unsigned pos)
+{
+	enum isl_dim_type type;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		p = isl_printer_print_str(p, "*");
+	}
+	type = pos2type(dim, &pos);
+	p = print_name_c(p, dim, bset, type, pos);
+	return p;
+}
+
+static __isl_give isl_printer *print_partial_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int *c, unsigned len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_term_c(p, dim, bset, c[i], i);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c)
+{
+	unsigned len = 1 + isl_basic_set_total_dim(bset);
+	return print_partial_affine_c(p, dim, bset, c, len);
+}
+
+/* We skip the constraint if it is implied by the div expression.
+ *
+ * *first indicates whether this is the first constraint in the conjunction and
+ * is updated if the constraint is actually printed.
+ */
+static __isl_give isl_printer *print_constraint_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int *c, const char *op, int *first)
+{
+	unsigned o_div;
+	unsigned n_div;
+	int div;
+
+	o_div = isl_basic_set_offset(bset, isl_dim_div);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	div = isl_seq_last_non_zero(c + o_div, n_div);
+	if (div >= 0 && isl_basic_set_is_div_constraint(bset, c, div))
+		return p;
+
+	if (!*first)
+		p = isl_printer_print_str(p, " && ");
+
+	p = print_affine_c(p, dim, bset, c);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, op);
+	p = isl_printer_print_str(p, " 0");
+
+	*first = 0;
+
+	return p;
+}
+
+static __isl_give isl_printer *print_basic_set_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	int first = 1;
+	unsigned n_div = isl_basic_set_dim(bset, isl_dim_div);
+	unsigned total = isl_basic_set_total_dim(bset) - n_div;
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		j = isl_seq_last_non_zero(bset->eq[i] + 1 + total, n_div);
+		if (j < 0)
+			p = print_constraint_c(p, dim, bset,
+						bset->eq[i], "==", &first);
+		else {
+			if (i)
+				p = isl_printer_print_str(p, " && ");
+			p = isl_printer_print_str(p, "(");
+			p = print_partial_affine_c(p, dim, bset, bset->eq[i],
+						   1 + total + j);
+			p = isl_printer_print_str(p, ") % ");
+			p = isl_printer_print_isl_int(p,
+						bset->eq[i][1 + total + j]);
+			p = isl_printer_print_str(p, " == 0");
+			first = 0;
+		}
+	}
+	for (i = 0; i < bset->n_ineq; ++i)
+		p = print_constraint_c(p, dim, bset, bset->ineq[i], ">=",
+					&first);
+	return p;
+}
+
+static __isl_give isl_printer *print_set_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return isl_printer_free(p);
+
+	if (set->n == 0)
+		p = isl_printer_print_str(p, "0");
+
+	for (i = 0; i < set->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " || ");
+		if (set->n > 1)
+			p = isl_printer_print_str(p, "(");
+		p = print_basic_set_c(p, dim, set->p[i]);
+		if (set->n > 1)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	int i;
+
+	if (pwqp->n == 1 && isl_set_plain_is_universe(pwqp->p[0].set))
+		return print_qpolynomial_c(p, pwqp->dim, pwqp->p[0].qp);
+
+	for (i = 0; i < pwqp->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pwqp->dim, pwqp->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_c(p, pwqp->dim, pwqp->p[i].qp);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	if (!p || !pwqp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_qpolynomial_isl(p, pwqp);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_qpolynomial_c(p, pwqp);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static int print_pwqp_body(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_pwqp_print_isl_body(data->p, pwqp);
+	isl_pw_qpolynomial_free(pwqp);
+
+	return 0;
+}
+
+static __isl_give isl_printer *print_union_pw_qpolynomial_isl(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+	struct isl_union_print_data data = { p, 1 };
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *dim;
+
+	dim = isl_union_pw_qpolynomial_get_space(upwqp);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	isl_space_free(dim);
+	p = isl_printer_print_str(p, "{ ");
+	isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &print_pwqp_body,
+							&data);
+	p = data.p;
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+	if (!p || !upwqp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_qpolynomial_isl(p, upwqp);
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_pw_qpolynomial",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_space *dim,
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	int i;
+
+	for (i = 0; i < fold->n - 1; ++i)
+		if (fold->type == isl_fold_min)
+			p = isl_printer_print_str(p, "min(");
+		else if (fold->type == isl_fold_max)
+			p = isl_printer_print_str(p, "max(");
+
+	for (i = 0; i < fold->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_qpolynomial_c(p, dim, fold->qp[i]);
+		if (i)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold)
+{
+	if  (!p || !fold)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return qpolynomial_fold_print(fold, p);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_qpolynomial_fold_c(p, fold->dim, fold);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	int i;
+
+	if (pwf->n == 1 && isl_set_plain_is_universe(pwf->p[0].set))
+		return print_qpolynomial_fold_c(p, pwf->dim, pwf->p[0].fold);
+
+	for (i = 0; i < pwf->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pwf->dim, pwf->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_fold_c(p, pwf->dim, pwf->p[i].fold);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	if (!p || !pwf)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_qpolynomial_fold_isl(p, pwf);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_qpolynomial_fold_c(p, pwf);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf,
+	FILE *out, unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!pwf)
+		return;
+
+	p = isl_printer_to_file(pwf->dim->ctx, out);
+	p = isl_printer_set_output_format(p, output_format);
+	p = isl_printer_print_pw_qpolynomial_fold(p, pwf);
+
+	isl_printer_free(p);
+}
+
+static int print_pwf_body(__isl_take isl_pw_qpolynomial_fold *pwf, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_pwf_print_isl_body(data->p, pwf);
+	isl_pw_qpolynomial_fold_free(pwf);
+
+	return 0;
+}
+
+static __isl_give isl_printer *print_union_pw_qpolynomial_fold_isl(
+	__isl_take isl_printer *p,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	struct isl_union_print_data data = { p, 1 };
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *dim;
+
+	dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	isl_space_free(dim);
+	p = isl_printer_print_str(p, "{ ");
+	isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(upwf,
+							&print_pwf_body, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold(
+	__isl_take isl_printer *p,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	if (!p || !upwf)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_qpolynomial_fold_isl(p, upwf);
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_pw_qpolynomial_fold",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+	__isl_keep isl_constraint *c)
+{
+	isl_basic_map *bmap;
+
+	if (!p || !c)
+		goto error;
+
+	bmap = isl_basic_map_from_constraint(isl_constraint_copy(c));
+	p = isl_printer_print_basic_map(p, bmap);
+	isl_basic_map_free(bmap);
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *isl_printer_print_space_isl(
+	__isl_take isl_printer *p, __isl_keep isl_space *dim)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!dim)
+		goto error;
+
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+
+	p = isl_printer_print_str(p, "{ ");
+	if (isl_space_is_params(dim))
+		p = isl_printer_print_str(p, s_such_that[0]);
+	else
+		p = print_space(dim, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p,
+	__isl_keep isl_space *space)
+{
+	if (!p || !space)
+		return isl_printer_free(p);
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_printer_print_space_isl(p, space);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return print_omega_parameters(space, p);
+
+	isl_die(isl_space_get_ctx(space), isl_error_unsupported,
+		"output format not supported for space",
+		return isl_printer_free(p));
+}
+
+__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls)
+{
+	struct isl_print_space_data data = { 0 };
+	unsigned total;
+	unsigned n_div;
+
+	if (!ls)
+		goto error;
+
+	total = isl_local_space_dim(ls, isl_dim_all);
+	if (isl_local_space_dim(ls, isl_dim_param) > 0) {
+		p = print_tuple(ls->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = print_space(ls->dim, p, 0, &data);
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	if (n_div > 0) {
+		p = isl_printer_print_str(p, " : ");
+		p = isl_printer_print_str(p, s_open_exists[0]);
+		p = print_div_list(p, ls->dim, ls->div, 0);
+	} else if (isl_space_is_params(ls->dim))
+		p = isl_printer_print_str(p, s_such_that[0]);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_aff_body(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	unsigned total;
+
+	if (isl_aff_is_nan(aff))
+		return isl_printer_print_str(p, "NaN");
+
+	total = isl_local_space_dim(aff->ls, isl_dim_all);
+	p = isl_printer_print_str(p, "(");
+	p = print_affine_of_len(aff->ls->dim, aff->ls->div, p,
+				aff->v->el + 1, 1 + total);
+	if (isl_int_is_one(aff->v->el[0]))
+		p = isl_printer_print_str(p, ")");
+	else {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, aff->v->el[0]);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_aff(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (isl_space_is_params(aff->ls->dim))
+		;
+	else {
+		p = print_tuple(aff->ls->dim, p, isl_dim_set, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "[");
+	p = print_aff_body(p, aff);
+	p = isl_printer_print_str(p, "]");
+
+	return p;
+}
+
+static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!aff)
+		goto error;
+
+	if (isl_local_space_dim(aff->ls, isl_dim_param) > 0) {
+		p = print_tuple(aff->ls->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = print_aff(p, aff);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	struct isl_print_space_data data = { 0 };
+	int i;
+
+	if (!pwaff)
+		goto error;
+
+	if (isl_space_dim(pwaff->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwaff->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	for (i = 0; i < pwaff->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff(p, pwaff->p[i].aff);
+		p = print_disjuncts((isl_map *)pwaff->p[i].set, p, 0);
+	}
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int *c);
+
+static __isl_give isl_printer *print_ls_name_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, enum isl_dim_type type, unsigned pos)
+{
+	if (type == isl_dim_div) {
+		p = isl_printer_print_str(p, "floord(");
+		p = print_ls_affine_c(p, ls, ls->div->row[pos] + 1);
+		p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, ls->div->row[pos][0]);
+		p = isl_printer_print_str(p, ")");
+	} else {
+		const char *name;
+
+		name = isl_space_get_dim_name(ls->dim, type, pos);
+		if (!name)
+			name = "UNNAMED";
+		p = isl_printer_print_str(p, name);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_term_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int c, unsigned pos)
+{
+	enum isl_dim_type type;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		p = isl_printer_print_str(p, "*");
+	}
+	type = pos2type(ls->dim, &pos);
+	p = print_ls_name_c(p, ls, type, pos);
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_partial_affine_c(
+	__isl_take isl_printer *p, __isl_keep isl_local_space *ls,
+	isl_int *c, unsigned len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_ls_term_c(p, ls, c[i], i);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int *c)
+{
+	unsigned len = 1 + isl_local_space_dim(ls, isl_dim_all);
+	return print_ls_partial_affine_c(p, ls, c, len);
+}
+
+static __isl_give isl_printer *print_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	unsigned total;
+
+	total = isl_local_space_dim(aff->ls, isl_dim_all);
+	if (!isl_int_is_one(aff->v->el[0]))
+		p = isl_printer_print_str(p, "(");
+	p = print_ls_partial_affine_c(p, aff->ls, aff->v->el + 1, 1 + total);
+	if (!isl_int_is_one(aff->v->el[0])) {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, aff->v->el[0]);
+	}
+	return p;
+}
+
+/* In the C format, we cannot express that "pwaff" may be undefined
+ * on parts of the domain space.  We therefore assume that the expression
+ * will only be evaluated on its definition domain and compute the gist
+ * of each cell with respect to this domain.
+ */
+static __isl_give isl_printer *print_pw_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	isl_set *domain;
+	isl_ast_build *build;
+	isl_ast_expr *expr;
+
+	if (pwaff->n < 1)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print empty isl_pw_aff in C format",
+			return isl_printer_free(p));
+
+	domain = isl_pw_aff_domain(isl_pw_aff_copy(pwaff));
+	build = isl_ast_build_from_context(domain);
+	expr = isl_ast_build_expr_from_pw_aff(build, isl_pw_aff_copy(pwaff));
+	p = isl_printer_print_ast_expr(p, expr);
+	isl_ast_expr_free(expr);
+	isl_ast_build_free(build);
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	if (!p || !aff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_aff_isl(p, aff);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_aff_c(p, aff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	if (!p || !pwaff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_aff_isl(p, pwaff);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_aff_c(p, pwaff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_aff.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding expression.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_ma(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_multi_aff *ma = data->user;
+
+	if (data->type == isl_dim_out)
+		p = print_aff_body(p, ma->p[pos]);
+	else
+		p = print_name(data->space, p, data->type, pos, data->latex);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	data.print_dim = &print_dim_ma;
+	data.user = maff;
+	return print_space(maff->space, p, 0, &data);
+}
+
+static __isl_give isl_printer *print_multi_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!maff)
+		goto error;
+
+	if (isl_space_dim(maff->space, isl_dim_param) > 0) {
+		p = print_tuple(maff->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = print_multi_aff(p, maff);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	if (!p || !maff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_aff_isl(p, maff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	int i;
+
+	if (!pma)
+		goto error;
+
+	for (i = 0; i < pma->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_multi_aff(p, pma->p[i].maff);
+		p = print_disjuncts((isl_map *)pma->p[i].set, p, 0);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_pw_multi_aff *pma)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!pma)
+		goto error;
+
+	if (isl_space_dim(pma->dim, isl_dim_param) > 0) {
+		p = print_tuple(pma->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = print_pw_multi_aff_body(p, pma);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_unnamed_pw_multi_aff_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	int i;
+
+	for (i = 0; i < pma->n - 1; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pma->dim, pma->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_aff_c(p, pma->p[i].maff->p[0]);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	return print_aff_c(p, pma->p[pma->n - 1].maff->p[0]);
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_pw_multi_aff *pma)
+{
+	int n;
+	const char *name;
+
+	if (!pma)
+		goto error;
+	if (pma->n < 1)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print empty isl_pw_multi_aff in C format",
+			goto error);
+	name = isl_pw_multi_aff_get_tuple_name(pma, isl_dim_out);
+	if (!name && isl_pw_multi_aff_dim(pma, isl_dim_out) == 1)
+		return print_unnamed_pw_multi_aff_c(p, pma);
+	if (!name)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print unnamed isl_pw_multi_aff in C format",
+			goto error);
+
+	p = isl_printer_print_str(p, name);
+	n = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	if (n != 0)
+		isl_die(p->ctx, isl_error_unsupported,
+			"not supported yet", goto error);
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_multi_aff(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	if (!p || !pma)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_multi_aff_isl(p, pma);
+	if (p->output_format == ISL_FORMAT_C)
+		return print_pw_multi_aff_c(p, pma);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static int print_pw_multi_aff_body_wrap(__isl_take isl_pw_multi_aff *pma,
+	void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *) user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = print_pw_multi_aff_body(data->p, pma);
+	isl_pw_multi_aff_free(pma);
+
+	return 0;
+}
+
+static __isl_give isl_printer *print_union_pw_multi_aff_isl(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma)
+{
+	struct isl_union_print_data data = { p, 1 };
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *space;
+
+	space = isl_union_pw_multi_aff_get_space(upma);
+	if (isl_space_dim(space, isl_dim_param) > 0) {
+		p = print_tuple(space, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	isl_space_free(space);
+	p = isl_printer_print_str(p, s_open_set[0]);
+	isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+					&print_pw_multi_aff_body_wrap, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_multi_aff(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma)
+{
+	if (!p || !upma)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_multi_aff_isl(p, upma);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_pw_aff.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding piecewise affine expression.
+ * Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_mpa(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	int i;
+	int need_parens;
+	isl_multi_pw_aff *mpa = data->user;
+	isl_pw_aff *pa;
+
+	if (data->type != isl_dim_out)
+		return print_name(data->space, p, data->type, pos, data->latex);
+
+	pa = mpa->p[pos];
+	if (pa->n == 0)
+		return isl_printer_print_str(p, "(0 : 1 = 0)");
+
+	need_parens = pa->n != 1 || !isl_set_plain_is_universe(pa->p[0].set);
+	if (need_parens)
+		p = isl_printer_print_str(p, "(");
+	for (i = 0; i < pa->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff_body(p, pa->p[i].aff);
+		p = print_disjuncts(pa->p[i].set, p, 0);
+	}
+	if (need_parens)
+		p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print "mpa" to "p" in isl format.
+ */
+static __isl_give isl_printer *print_multi_pw_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_pw_aff *mpa)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!mpa)
+		return isl_printer_free(p);
+
+	if (isl_space_dim(mpa->space, isl_dim_param) > 0) {
+		p = print_tuple(mpa->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mpa;
+	data.user = mpa;
+	p = print_space(mpa->space, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_multi_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa)
+{
+	if (!p || !mpa)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_pw_aff_isl(p, mpa);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		return isl_printer_free(p));
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_val.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding value.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_mv(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_multi_val *mv = data->user;
+
+	if (data->type == isl_dim_out)
+		return isl_printer_print_val(p, mv->p[pos]);
+	else
+		return print_name(data->space, p, data->type, pos, data->latex);
+}
+
+/* Print the isl_multi_val "mv" to "p" in isl format.
+ */
+static __isl_give isl_printer *print_multi_val_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_val *mv)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!mv)
+		return isl_printer_free(p);
+
+	if (isl_space_dim(mv->space, isl_dim_param) > 0) {
+		p = print_tuple(mv->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mv;
+	data.user = mv;
+	p = print_space(mv->space, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+/* Print the isl_multi_val "mv" to "p".
+ *
+ * Currently only supported in isl format.
+ */
+__isl_give isl_printer *isl_printer_print_multi_val(
+	__isl_take isl_printer *p, __isl_keep isl_multi_val *mv)
+{
+	if (!p || !mv)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_val_isl(p, mv);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		return isl_printer_free(p));
+}

Added: polly/trunk/lib/External/isl/isl_point.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_point.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_point.c (added)
+++ polly/trunk/lib/External/isl/isl_point.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,585 @@
+#include <isl_map_private.h>
+#include <isl_point_private.h>
+#include <isl/set.h>
+#include <isl_sample.h>
+#include <isl_scan.h>
+#include <isl_seq.h>
+#include <isl_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl/deprecated/point_int.h>
+
+isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt)
+{
+	return pnt ? isl_space_get_ctx(pnt->dim) : NULL;
+}
+
+__isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt)
+{
+	return pnt ? isl_space_copy(pnt->dim) : NULL;
+}
+
+__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim,
+	__isl_take isl_vec *vec)
+{
+	struct isl_point *pnt;
+
+	if (!dim || !vec)
+		goto error;
+
+	if (vec->size > 1 + isl_space_dim(dim, isl_dim_all)) {
+		vec = isl_vec_cow(vec);
+		if (!vec)
+			goto error;
+		vec->size = 1 + isl_space_dim(dim, isl_dim_all);
+	}
+
+	pnt = isl_alloc_type(dim->ctx, struct isl_point);
+	if (!pnt)
+		goto error;
+
+	pnt->ref = 1;
+	pnt->dim = dim;
+	pnt->vec = vec;
+
+	return pnt;
+error:
+	isl_space_free(dim);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_zero(__isl_take isl_space *dim)
+{
+	isl_vec *vec;
+
+	if (!dim)
+		return NULL;
+	vec = isl_vec_alloc(dim->ctx, 1 + isl_space_dim(dim, isl_dim_all));
+	if (!vec)
+		goto error;
+	isl_int_set_si(vec->el[0], 1);
+	isl_seq_clr(vec->el + 1, vec->size - 1);
+	return isl_point_alloc(dim, vec);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_dup(__isl_keep isl_point *pnt)
+{
+	struct isl_point *pnt2;
+
+	if (!pnt)
+		return NULL;
+	pnt2 = isl_point_alloc(isl_space_copy(pnt->dim), isl_vec_copy(pnt->vec));
+	return pnt2;
+}
+
+__isl_give isl_point *isl_point_cow(__isl_take isl_point *pnt)
+{
+	struct isl_point *pnt2;
+	if (!pnt)
+		return NULL;
+
+	if (pnt->ref == 1)
+		return pnt;
+
+	pnt2 = isl_point_dup(pnt);
+	isl_point_free(pnt);
+	return pnt2;
+}
+
+__isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt)
+{
+	if (!pnt)
+		return NULL;
+
+	pnt->ref++;
+	return pnt;
+}
+
+void isl_point_free(__isl_take isl_point *pnt)
+{
+	if (!pnt)
+		return;
+
+	if (--pnt->ref > 0)
+		return;
+
+	isl_space_free(pnt->dim);
+	isl_vec_free(pnt->vec);
+	free(pnt);
+}
+
+__isl_give isl_point *isl_point_void(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	return isl_point_alloc(dim, isl_vec_alloc(dim->ctx, 0));
+}
+
+int isl_point_is_void(__isl_keep isl_point *pnt)
+{
+	if (!pnt)
+		return -1;
+
+	return pnt->vec->size == 0;
+}
+
+int isl_point_get_coordinate(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int *v)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return -1;
+
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"position out of bounds", return -1);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+	isl_int_set(*v, pnt->vec->el[1 + pos]);
+
+	return 0;
+}
+
+/* Return the value of coordinate "pos" of type "type" of "pnt".
+ */
+__isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!pnt)
+		return NULL;
+
+	ctx = isl_point_get_ctx(pnt);
+	if (isl_point_is_void(pnt))
+		isl_die(ctx, isl_error_invalid,
+			"void point does not have coordinates", return NULL);
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return NULL);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	v = isl_val_rat_from_isl_int(ctx, pnt->vec->el[1 + pos],
+						pnt->vec->el[0]);
+	return isl_val_normalize(v);
+}
+
+__isl_give isl_point *isl_point_set_coordinate(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_set(pnt->vec->el[1 + pos], v);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+/* Replace coordinate "pos" of type "type" of "pnt" by "v".
+ */
+__isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	if (!pnt || !v)
+		goto error;
+	if (isl_point_is_void(pnt))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"void point does not have coordinates", goto error);
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"position out of bounds", goto error);
+	if (!isl_val_is_rat(v))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	if (isl_int_eq(pnt->vec->el[1 + pos], v->n) &&
+	    isl_int_eq(pnt->vec->el[0], v->d)) {
+		isl_val_free(v);
+		return pnt;
+	}
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		goto error;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (isl_int_eq(pnt->vec->el[0], v->d)) {
+		isl_int_set(pnt->vec->el[1 + pos], v->n);
+	} else if (isl_int_is_one(v->d)) {
+		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
+	} else {
+		isl_seq_scale(pnt->vec->el + 1,
+				pnt->vec->el + 1, v->d, pnt->vec->size - 1);
+		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
+		isl_int_mul(pnt->vec->el[0], pnt->vec->el[0], v->d);
+		pnt->vec = isl_vec_normalize(pnt->vec);
+		if (!pnt->vec)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pnt;
+error:
+	isl_val_free(v);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_add_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_sub_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+struct isl_foreach_point {
+	struct isl_scan_callback callback;
+	int (*fn)(__isl_take isl_point *pnt, void *user);
+	void *user;
+	isl_space *dim;
+};
+
+static int foreach_point(struct isl_scan_callback *cb, __isl_take isl_vec *sample)
+{
+	struct isl_foreach_point *fp = (struct isl_foreach_point *)cb;
+	isl_point *pnt;
+
+	pnt = isl_point_alloc(isl_space_copy(fp->dim), sample);
+
+	return fp->fn(pnt, fp->user);
+}
+
+int isl_set_foreach_point(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_point *pnt, void *user), void *user)
+{
+	struct isl_foreach_point fp = { { &foreach_point }, fn, user };
+	int i;
+
+	if (!set)
+		return -1;
+
+	fp.dim = isl_set_get_space(set);
+	if (!fp.dim)
+		return -1;
+
+	set = isl_set_copy(set);
+	set = isl_set_cow(set);
+	set = isl_set_make_disjoint(set);
+	set = isl_set_compute_divs(set);
+	if (!set)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
+					&fp.callback) < 0)
+			goto error;
+
+	isl_set_free(set);
+	isl_space_free(fp.dim);
+
+	return 0;
+error:
+	isl_set_free(set);
+	isl_space_free(fp.dim);
+	return -1;
+}
+
+/* Return 1 if "bmap" contains the point "point".
+ * "bmap" is assumed to have known divs.
+ * The point is first extended with the divs and then passed
+ * to basic_map_contains.
+ */
+int isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_point *point)
+{
+	int i;
+	struct isl_vec *vec;
+	unsigned dim;
+	int contains;
+
+	if (!bmap || !point)
+		return -1;
+	isl_assert(bmap->ctx, isl_space_is_equal(bmap->dim, point->dim), return -1);
+	if (bmap->n_div == 0)
+		return isl_basic_map_contains(bmap, point->vec);
+
+	dim = isl_basic_map_total_dim(bmap) - bmap->n_div;
+	vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div);
+	if (!vec)
+		return -1;
+
+	isl_seq_cpy(vec->el, point->vec->el, point->vec->size);
+	for (i = 0; i < bmap->n_div; ++i) {
+		isl_seq_inner_product(bmap->div[i] + 1, vec->el,
+					1 + dim + i, &vec->el[1+dim+i]);
+		isl_int_fdiv_q(vec->el[1+dim+i], vec->el[1+dim+i],
+				bmap->div[i][0]);
+	}
+
+	contains = isl_basic_map_contains(bmap, vec);
+
+	isl_vec_free(vec);
+	return contains;
+}
+
+int isl_map_contains_point(__isl_keep isl_map *map, __isl_keep isl_point *point)
+{
+	int i;
+	int found = 0;
+
+	if (!map || !point)
+		return -1;
+
+	map = isl_map_copy(map);
+	map = isl_map_compute_divs(map);
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		found = isl_basic_map_contains_point(map->p[i], point);
+		if (found < 0)
+			goto error;
+		if (found)
+			break;
+	}
+	isl_map_free(map);
+
+	return found;
+error:
+	isl_map_free(map);
+	return -1;
+}
+
+int isl_set_contains_point(__isl_keep isl_set *set, __isl_keep isl_point *point)
+{
+	return isl_map_contains_point((isl_map *)set, point);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt)
+{
+	isl_basic_set *bset;
+	isl_basic_set *model;
+
+	if (!pnt)
+		return NULL;
+
+	model = isl_basic_set_empty(isl_space_copy(pnt->dim));
+	bset = isl_basic_set_from_vec(isl_vec_copy(pnt->vec));
+	bset = isl_basic_set_from_underlying_set(bset, model);
+	isl_point_free(pnt);
+
+	return bset;
+}
+
+__isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt)
+{
+	isl_basic_set *bset;
+	bset = isl_basic_set_from_point(pnt);
+	return isl_set_from_basic_set(bset);
+}
+
+__isl_give isl_basic_set *isl_basic_set_box_from_points(
+	__isl_take isl_point *pnt1, __isl_take isl_point *pnt2)
+{
+	isl_basic_set *bset;
+	unsigned total;
+	int i;
+	int k;
+	isl_int t;
+
+	isl_int_init(t);
+
+	if (!pnt1 || !pnt2)
+		goto error;
+
+	isl_assert(pnt1->dim->ctx,
+			isl_space_is_equal(pnt1->dim, pnt2->dim), goto error);
+
+	if (isl_point_is_void(pnt1) && isl_point_is_void(pnt2)) {
+		isl_space *dim = isl_space_copy(pnt1->dim);
+		isl_point_free(pnt1);
+		isl_point_free(pnt2);
+		isl_int_clear(t);
+		return isl_basic_set_empty(dim);
+	}
+	if (isl_point_is_void(pnt1)) {
+		isl_point_free(pnt1);
+		isl_int_clear(t);
+		return isl_basic_set_from_point(pnt2);
+	}
+	if (isl_point_is_void(pnt2)) {
+		isl_point_free(pnt2);
+		isl_int_clear(t);
+		return isl_basic_set_from_point(pnt1);
+	}
+
+	total = isl_space_dim(pnt1->dim, isl_dim_all);
+	bset = isl_basic_set_alloc_space(isl_space_copy(pnt1->dim), 0, 0, 2 * total);
+
+	for (i = 0; i < total; ++i) {
+		isl_int_mul(t, pnt1->vec->el[1 + i], pnt2->vec->el[0]);
+		isl_int_submul(t, pnt2->vec->el[1 + i], pnt1->vec->el[0]);
+
+		k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k] + 1, total);
+		if (isl_int_is_pos(t)) {
+			isl_int_set_si(bset->ineq[k][1 + i], -1);
+			isl_int_set(bset->ineq[k][0], pnt1->vec->el[1 + i]);
+		} else {
+			isl_int_set_si(bset->ineq[k][1 + i], 1);
+			isl_int_neg(bset->ineq[k][0], pnt1->vec->el[1 + i]);
+		}
+		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt1->vec->el[0]);
+
+		k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k] + 1, total);
+		if (isl_int_is_pos(t)) {
+			isl_int_set_si(bset->ineq[k][1 + i], 1);
+			isl_int_neg(bset->ineq[k][0], pnt2->vec->el[1 + i]);
+		} else {
+			isl_int_set_si(bset->ineq[k][1 + i], -1);
+			isl_int_set(bset->ineq[k][0], pnt2->vec->el[1 + i]);
+		}
+		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt2->vec->el[0]);
+	}
+
+	bset = isl_basic_set_finalize(bset);
+
+	isl_point_free(pnt1);
+	isl_point_free(pnt2);
+
+	isl_int_clear(t);
+
+	return bset;
+error:
+	isl_point_free(pnt1);
+	isl_point_free(pnt2);
+	isl_int_clear(t);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1,
+	__isl_take isl_point *pnt2)
+{
+	isl_basic_set *bset;
+	bset = isl_basic_set_box_from_points(pnt1, pnt2);
+	return isl_set_from_basic_set(bset);
+}
+
+__isl_give isl_printer *isl_printer_print_point(
+	__isl_take isl_printer *p, __isl_keep isl_point *pnt)
+{
+	int i;
+	unsigned nparam;
+	unsigned dim;
+
+	if (!pnt)
+		return p;
+	if (isl_point_is_void(pnt)) {
+		p = isl_printer_print_str(p, "void");
+		return p;
+	}
+
+	nparam = isl_space_dim(pnt->dim, isl_dim_param);
+	dim = isl_space_dim(pnt->dim, isl_dim_set);
+	if (nparam > 0) {
+		p = isl_printer_print_str(p, "[");
+		for (i = 0; i < nparam; ++i) {
+			const char *name;
+			if (i)
+				p = isl_printer_print_str(p, ", ");
+			name = isl_space_get_dim_name(pnt->dim, isl_dim_param, i);
+			if (name) {
+				p = isl_printer_print_str(p, name);
+				p = isl_printer_print_str(p, " = ");
+			}
+			p = isl_printer_print_isl_int(p, pnt->vec->el[1 + i]);
+			if (!isl_int_is_one(pnt->vec->el[0])) {
+				p = isl_printer_print_str(p, "/");
+				p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
+			}
+		}
+		p = isl_printer_print_str(p, "]");
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "[");
+	for (i = 0; i < dim; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, pnt->vec->el[1 + nparam + i]);
+		if (!isl_int_is_one(pnt->vec->el[0])) {
+			p = isl_printer_print_str(p, "/");
+			p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
+		}
+	}
+	p = isl_printer_print_str(p, "]");
+	return p;
+}

Added: polly/trunk/lib/External/isl/isl_point_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_point_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_point_private.h (added)
+++ polly/trunk/lib/External/isl/isl_point_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,12 @@
+#include <isl/space.h>
+#include <isl/point.h>
+#include <isl/vec.h>
+
+struct isl_point {
+	int		ref;
+	isl_space	*dim;
+	struct isl_vec	*vec;
+};
+
+__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim,
+	__isl_take isl_vec *vec);

Added: polly/trunk/lib/External/isl/isl_polynomial.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_polynomial.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_polynomial.c (added)
+++ polly/trunk/lib/External/isl/isl_polynomial.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,4866 @@
+/*
+ * 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 <stdlib.h>
+#define ISL_DIM_H
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_factorization.h>
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl_union_map_private.h>
+#include <isl_constraint_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_point_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_range.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_val_private.h>
+#include <isl_config.h>
+#include <isl/deprecated/polynomial_int.h>
+
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 0;
+	case isl_dim_in:	return dim->nparam;
+	case isl_dim_out:	return dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+int isl_upoly_is_cst(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return -1;
+
+	return up->var < 0;
+}
+
+__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	isl_assert(up->ctx, up->var < 0, return NULL);
+
+	return (struct isl_upoly_cst *)up;
+}
+
+__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	isl_assert(up->ctx, up->var >= 0, return NULL);
+
+	return (struct isl_upoly_rec *)up;
+}
+
+int isl_upoly_is_equal(__isl_keep struct isl_upoly *up1,
+	__isl_keep struct isl_upoly *up2)
+{
+	int i;
+	struct isl_upoly_rec *rec1, *rec2;
+
+	if (!up1 || !up2)
+		return -1;
+	if (up1 == up2)
+		return 1;
+	if (up1->var != up2->var)
+		return 0;
+	if (isl_upoly_is_cst(up1)) {
+		struct isl_upoly_cst *cst1, *cst2;
+		cst1 = isl_upoly_as_cst(up1);
+		cst2 = isl_upoly_as_cst(up2);
+		if (!cst1 || !cst2)
+			return -1;
+		return isl_int_eq(cst1->n, cst2->n) &&
+		       isl_int_eq(cst1->d, cst2->d);
+	}
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		return -1;
+
+	if (rec1->n != rec2->n)
+		return 0;
+
+	for (i = 0; i < rec1->n; ++i) {
+		int eq = isl_upoly_is_equal(rec1->p[i], rec2->p[i]);
+		if (eq < 0 || !eq)
+			return eq;
+	}
+
+	return 1;
+}
+
+int isl_upoly_is_zero(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_zero(cst->n) && isl_int_is_pos(cst->d);
+}
+
+int isl_upoly_sgn(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return 0;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return 0;
+
+	return isl_int_sgn(cst->n);
+}
+
+int isl_upoly_is_nan(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_zero(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_infty(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_pos(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_neginfty(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_neg(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_one(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_eq(cst->n, cst->d) && isl_int_is_pos(cst->d);
+}
+
+int isl_upoly_is_negone(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_negone(cst->n) && isl_int_is_one(cst->d);
+}
+
+__isl_give struct isl_upoly_cst *isl_upoly_cst_alloc(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_alloc_type(ctx, struct isl_upoly_cst);
+	if (!cst)
+		return NULL;
+
+	cst->up.ref = 1;
+	cst->up.ctx = ctx;
+	isl_ctx_ref(ctx);
+	cst->up.var = -1;
+
+	isl_int_init(cst->n);
+	isl_int_init(cst->d);
+
+	return cst;
+}
+
+__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 0);
+	isl_int_set_si(cst->d, 1);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_one(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 1);
+	isl_int_set_si(cst->d, 1);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_infty(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 1);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_neginfty(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, -1);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_nan(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 0);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_rat_cst(struct isl_ctx *ctx,
+	isl_int n, isl_int d)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set(cst->n, n);
+	isl_int_set(cst->d, d);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly_rec *isl_upoly_alloc_rec(struct isl_ctx *ctx,
+	int var, int size)
+{
+	struct isl_upoly_rec *rec;
+
+	isl_assert(ctx, var >= 0, return NULL);
+	isl_assert(ctx, size >= 0, return NULL);
+	rec = isl_calloc(ctx, struct isl_upoly_rec,
+			sizeof(struct isl_upoly_rec) +
+			size * sizeof(struct isl_upoly *));
+	if (!rec)
+		return NULL;
+
+	rec->up.ref = 1;
+	rec->up.ctx = ctx;
+	isl_ctx_ref(ctx);
+	rec->up.var = var;
+
+	rec->n = 0;
+	rec->size = size;
+
+	return rec;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *dim)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp || !dim)
+		goto error;
+
+	isl_space_free(qp->dim);
+	qp->dim = dim;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reset the space of "qp".  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 *isl_qpolynomial_reset_space_and_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	isl_space_free(space);
+	return isl_qpolynomial_reset_domain_space(qp, domain);
+}
+
+isl_ctx *isl_qpolynomial_get_ctx(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? qp->dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_get_domain_space(
+	__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_space_copy(qp->dim) : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_get_space(__isl_keep isl_qpolynomial *qp)
+{
+	isl_space *space;
+	if (!qp)
+		return NULL;
+	space = isl_space_copy(qp->dim);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	return space;
+}
+
+/* Externally, an isl_qpolynomial has a map space, but internally, the
+ * ls field corresponds to the domain of that space.
+ */
+unsigned isl_qpolynomial_dim(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type)
+{
+	if (!qp)
+		return 0;
+	if (type == isl_dim_out)
+		return 1;
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	return isl_space_dim(qp->dim, type);
+}
+
+int isl_qpolynomial_is_zero(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_zero(qp->upoly) : -1;
+}
+
+int isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_one(qp->upoly) : -1;
+}
+
+int isl_qpolynomial_is_nan(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_nan(qp->upoly) : -1;
+}
+
+int isl_qpolynomial_is_infty(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_infty(qp->upoly) : -1;
+}
+
+int isl_qpolynomial_is_neginfty(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_neginfty(qp->upoly) : -1;
+}
+
+int isl_qpolynomial_sgn(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_sgn(qp->upoly) : 0;
+}
+
+static void upoly_free_cst(__isl_take struct isl_upoly_cst *cst)
+{
+	isl_int_clear(cst->n);
+	isl_int_clear(cst->d);
+}
+
+static void upoly_free_rec(__isl_take struct isl_upoly_rec *rec)
+{
+	int i;
+
+	for (i = 0; i < rec->n; ++i)
+		isl_upoly_free(rec->p[i]);
+}
+
+__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	up->ref++;
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup_cst(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+	struct isl_upoly_cst *dup;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return NULL;
+
+	dup = isl_upoly_as_cst(isl_upoly_zero(up->ctx));
+	if (!dup)
+		return NULL;
+	isl_int_set(dup->n, cst->n);
+	isl_int_set(dup->d, cst->d);
+
+	return &dup->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup_rec(__isl_keep struct isl_upoly *up)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly_rec *dup;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return NULL;
+
+	dup = isl_upoly_alloc_rec(up->ctx, up->var, rec->n);
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < rec->n; ++i) {
+		dup->p[i] = isl_upoly_copy(rec->p[i]);
+		if (!dup->p[i])
+			goto error;
+		dup->n++;
+	}
+
+	return &dup->up;
+error:
+	isl_upoly_free(&dup->up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_dup_cst(up);
+	else
+		return isl_upoly_dup_rec(up);
+}
+
+__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	if (up->ref == 1)
+		return up;
+	up->ref--;
+	return isl_upoly_dup(up);
+}
+
+void isl_upoly_free(__isl_take struct isl_upoly *up)
+{
+	if (!up)
+		return;
+
+	if (--up->ref > 0)
+		return;
+
+	if (up->var < 0)
+		upoly_free_cst((struct isl_upoly_cst *)up);
+	else
+		upoly_free_rec((struct isl_upoly_rec *)up);
+
+	isl_ctx_deref(up->ctx);
+	free(up);
+}
+
+static void isl_upoly_cst_reduce(__isl_keep struct isl_upoly_cst *cst)
+{
+	isl_int gcd;
+
+	isl_int_init(gcd);
+	isl_int_gcd(gcd, cst->n, cst->d);
+	if (!isl_int_is_zero(gcd) && !isl_int_is_one(gcd)) {
+		isl_int_divexact(cst->n, cst->n, gcd);
+		isl_int_divexact(cst->d, cst->d, gcd);
+	}
+	isl_int_clear(gcd);
+}
+
+__isl_give struct isl_upoly *isl_upoly_sum_cst(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_cst *cst1;
+	struct isl_upoly_cst *cst2;
+
+	up1 = isl_upoly_cow(up1);
+	if (!up1 || !up2)
+		goto error;
+
+	cst1 = isl_upoly_as_cst(up1);
+	cst2 = isl_upoly_as_cst(up2);
+
+	if (isl_int_eq(cst1->d, cst2->d))
+		isl_int_add(cst1->n, cst1->n, cst2->n);
+	else {
+		isl_int_mul(cst1->n, cst1->n, cst2->d);
+		isl_int_addmul(cst1->n, cst2->n, cst1->d);
+		isl_int_mul(cst1->d, cst1->d, cst2->d);
+	}
+
+	isl_upoly_cst_reduce(cst1);
+
+	isl_upoly_free(up2);
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+static __isl_give struct isl_upoly *replace_by_zero(
+	__isl_take struct isl_upoly *up)
+{
+	struct isl_ctx *ctx;
+
+	if (!up)
+		return NULL;
+	ctx = up->ctx;
+	isl_upoly_free(up);
+	return isl_upoly_zero(ctx);
+}
+
+static __isl_give struct isl_upoly *replace_by_constant_term(
+	__isl_take struct isl_upoly *up)
+{
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *cst;
+
+	if (!up)
+		return NULL;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+	cst = isl_upoly_copy(rec->p[0]);
+	isl_upoly_free(up);
+	return cst;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	int i;
+	struct isl_upoly_rec *rec1, *rec2;
+
+	if (!up1 || !up2)
+		goto error;
+
+	if (isl_upoly_is_nan(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_nan(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up1)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up2)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (up1->var < up2->var)
+		return isl_upoly_sum(up2, up1);
+
+	if (up2->var < up1->var) {
+		struct isl_upoly_rec *rec;
+		if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) {
+			isl_upoly_free(up1);
+			return up2;
+		}
+		up1 = isl_upoly_cow(up1);
+		rec = isl_upoly_as_rec(up1);
+		if (!rec)
+			goto error;
+		rec->p[0] = isl_upoly_sum(rec->p[0], up2);
+		if (rec->n == 1)
+			up1 = replace_by_constant_term(up1);
+		return up1;
+	}
+
+	if (isl_upoly_is_cst(up1))
+		return isl_upoly_sum_cst(up1, up2);
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		goto error;
+
+	if (rec1->n < rec2->n)
+		return isl_upoly_sum(up2, up1);
+
+	up1 = isl_upoly_cow(up1);
+	rec1 = isl_upoly_as_rec(up1);
+	if (!rec1)
+		goto error;
+
+	for (i = rec2->n - 1; i >= 0; --i) {
+		rec1->p[i] = isl_upoly_sum(rec1->p[i],
+					    isl_upoly_copy(rec2->p[i]));
+		if (!rec1->p[i])
+			goto error;
+		if (i == rec1->n - 1 && isl_upoly_is_zero(rec1->p[i])) {
+			isl_upoly_free(rec1->p[i]);
+			rec1->n--;
+		}
+	}
+
+	if (rec1->n == 0)
+		up1 = replace_by_zero(up1);
+	else if (rec1->n == 1)
+		up1 = replace_by_constant_term(up1);
+
+	isl_upoly_free(up2);
+
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_cst_add_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_cst *cst;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_addmul(cst->n, cst->d, v);
+
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_add_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_add_isl_int(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	rec->p[0] = isl_upoly_add_isl_int(rec->p[0], v);
+	if (!rec->p[0])
+		goto error;
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_cst_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_cst *cst;
+
+	if (isl_upoly_is_zero(up))
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_mul(cst->n, cst->n, v);
+
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_mul_isl_int(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_mul_isl_int(rec->p[i], v);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Multiply the constant polynomial "up" by "v".
+ */
+static __isl_give struct isl_upoly *isl_upoly_cst_scale_val(
+	__isl_take struct isl_upoly *up, __isl_keep isl_val *v)
+{
+	struct isl_upoly_cst *cst;
+
+	if (isl_upoly_is_zero(up))
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_mul(cst->n, cst->n, v->n);
+	isl_int_mul(cst->d, cst->d, v->d);
+	isl_upoly_cst_reduce(cst);
+
+	return up;
+}
+
+/* Multiply the polynomial "up" by "v".
+ */
+static __isl_give struct isl_upoly *isl_upoly_scale_val(
+	__isl_take struct isl_upoly *up, __isl_keep isl_val *v)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_scale_val(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_scale_val(rec->p[i], v);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_cst(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_cst *cst1;
+	struct isl_upoly_cst *cst2;
+
+	up1 = isl_upoly_cow(up1);
+	if (!up1 || !up2)
+		goto error;
+
+	cst1 = isl_upoly_as_cst(up1);
+	cst2 = isl_upoly_as_cst(up2);
+
+	isl_int_mul(cst1->n, cst1->n, cst2->n);
+	isl_int_mul(cst1->d, cst1->d, cst2->d);
+
+	isl_upoly_cst_reduce(cst1);
+
+	isl_upoly_free(up2);
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_rec(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_rec *rec1;
+	struct isl_upoly_rec *rec2;
+	struct isl_upoly_rec *res = NULL;
+	int i, j;
+	int size;
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		goto error;
+	size = rec1->n + rec2->n - 1;
+	res = isl_upoly_alloc_rec(up1->ctx, up1->var, size);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < rec1->n; ++i) {
+		res->p[i] = isl_upoly_mul(isl_upoly_copy(rec2->p[0]),
+					    isl_upoly_copy(rec1->p[i]));
+		if (!res->p[i])
+			goto error;
+		res->n++;
+	}
+	for (; i < size; ++i) {
+		res->p[i] = isl_upoly_zero(up1->ctx);
+		if (!res->p[i])
+			goto error;
+		res->n++;
+	}
+	for (i = 0; i < rec1->n; ++i) {
+		for (j = 1; j < rec2->n; ++j) {
+			struct isl_upoly *up;
+			up = isl_upoly_mul(isl_upoly_copy(rec2->p[j]),
+					    isl_upoly_copy(rec1->p[i]));
+			res->p[i + j] = isl_upoly_sum(res->p[i + j], up);
+			if (!res->p[i + j])
+				goto error;
+		}
+	}
+
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+
+	return &res->up;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	isl_upoly_free(&res->up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	if (!up1 || !up2)
+		goto error;
+
+	if (isl_upoly_is_nan(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_nan(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_zero(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_one(up1)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_one(up2)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (up1->var < up2->var)
+		return isl_upoly_mul(up2, up1);
+
+	if (up2->var < up1->var) {
+		int i;
+		struct isl_upoly_rec *rec;
+		if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) {
+			isl_ctx *ctx = up1->ctx;
+			isl_upoly_free(up1);
+			isl_upoly_free(up2);
+			return isl_upoly_nan(ctx);
+		}
+		up1 = isl_upoly_cow(up1);
+		rec = isl_upoly_as_rec(up1);
+		if (!rec)
+			goto error;
+
+		for (i = 0; i < rec->n; ++i) {
+			rec->p[i] = isl_upoly_mul(rec->p[i],
+						    isl_upoly_copy(up2));
+			if (!rec->p[i])
+				goto error;
+		}
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_cst(up1))
+		return isl_upoly_mul_cst(up1, up2);
+
+	return isl_upoly_mul_rec(up1, up2);
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_pow(__isl_take struct isl_upoly *up,
+	unsigned power)
+{
+	struct isl_upoly *res;
+
+	if (!up)
+		return NULL;
+	if (power == 1)
+		return up;
+
+	if (power % 2)
+		res = isl_upoly_copy(up);
+	else
+		res = isl_upoly_one(up->ctx);
+
+	while (power >>= 1) {
+		up = isl_upoly_mul(up, isl_upoly_copy(up));
+		if (power % 2)
+			res = isl_upoly_mul(res, isl_upoly_copy(up));
+	}
+
+	isl_upoly_free(up);
+	return res;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim,
+	unsigned n_div, __isl_take struct isl_upoly *up)
+{
+	struct isl_qpolynomial *qp = NULL;
+	unsigned total;
+
+	if (!dim || !up)
+		goto error;
+
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"domain of polynomial should be a set", goto error);
+
+	total = isl_space_dim(dim, isl_dim_all);
+
+	qp = isl_calloc_type(dim->ctx, struct isl_qpolynomial);
+	if (!qp)
+		goto error;
+
+	qp->ref = 1;
+	qp->div = isl_mat_alloc(dim->ctx, n_div, 1 + 1 + total + n_div);
+	if (!qp->div)
+		goto error;
+
+	qp->dim = dim;
+	qp->upoly = up;
+
+	return qp;
+error:
+	isl_space_free(dim);
+	isl_upoly_free(up);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_copy(__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	qp->ref++;
+	return qp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_qpolynomial *dup;
+
+	if (!qp)
+		return NULL;
+
+	dup = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row,
+				    isl_upoly_copy(qp->upoly));
+	if (!dup)
+		return NULL;
+	isl_mat_free(dup->div);
+	dup->div = isl_mat_copy(qp->div);
+	if (!dup->div)
+		goto error;
+
+	return dup;
+error:
+	isl_qpolynomial_free(dup);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	if (qp->ref == 1)
+		return qp;
+	qp->ref--;
+	return isl_qpolynomial_dup(qp);
+}
+
+__isl_null isl_qpolynomial *isl_qpolynomial_free(
+	__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	if (--qp->ref > 0)
+		return NULL;
+
+	isl_space_free(qp->dim);
+	isl_mat_free(qp->div);
+	isl_upoly_free(qp->upoly);
+
+	free(qp);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_var_pow(isl_ctx *ctx, int pos, int power)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly_cst *cst;
+
+	rec = isl_upoly_alloc_rec(ctx, pos, 1 + power);
+	if (!rec)
+		return NULL;
+	for (i = 0; i < 1 + power; ++i) {
+		rec->p[i] = isl_upoly_zero(ctx);
+		if (!rec->p[i])
+			goto error;
+		rec->n++;
+	}
+	cst = isl_upoly_as_cst(rec->p[power]);
+	isl_int_set_si(cst->n, 1);
+
+	return &rec->up;
+error:
+	isl_upoly_free(&rec->up);
+	return NULL;
+}
+
+/* r array maps original positions to new positions.
+ */
+static __isl_give struct isl_upoly *reorder(__isl_take struct isl_upoly *up,
+	int *r)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *base;
+	struct isl_upoly *res;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	base = isl_upoly_var_pow(up->ctx, r[up->var], 1);
+	res = reorder(isl_upoly_copy(rec->p[rec->n - 1]), r);
+
+	for (i = rec->n - 2; i >= 0; --i) {
+		res = isl_upoly_mul(res, isl_upoly_copy(base));
+		res = isl_upoly_sum(res, reorder(isl_upoly_copy(rec->p[i]), r));
+	}
+
+	isl_upoly_free(base);
+	isl_upoly_free(up);
+
+	return res;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+static int compatible_divs(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2)
+{
+	int n_row, n_col;
+	int equal;
+
+	isl_assert(div1->ctx, div1->n_row >= div2->n_row &&
+				div1->n_col >= div2->n_col, return -1);
+
+	if (div1->n_row == div2->n_row)
+		return isl_mat_is_equal(div1, div2);
+
+	n_row = div1->n_row;
+	n_col = div1->n_col;
+	div1->n_row = div2->n_row;
+	div1->n_col = div2->n_col;
+
+	equal = isl_mat_is_equal(div1, div2);
+
+	div1->n_row = n_row;
+	div1->n_col = n_col;
+
+	return equal;
+}
+
+static int cmp_row(__isl_keep isl_mat *div, int i, int j)
+{
+	int li, lj;
+
+	li = isl_seq_last_non_zero(div->row[i], div->n_col);
+	lj = isl_seq_last_non_zero(div->row[j], div->n_col);
+
+	if (li != lj)
+		return li - lj;
+
+	return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
+}
+
+struct isl_div_sort_info {
+	isl_mat	*div;
+	int	 row;
+};
+
+static int div_sort_cmp(const void *p1, const void *p2)
+{
+	const struct isl_div_sort_info *i1, *i2;
+	i1 = (const struct isl_div_sort_info *) p1;
+	i2 = (const struct isl_div_sort_info *) p2;
+
+	return cmp_row(i1->div, i1->row, i2->row);
+}
+
+/* Sort divs and remove duplicates.
+ */
+static __isl_give isl_qpolynomial *sort_divs(__isl_take isl_qpolynomial *qp)
+{
+	int i;
+	int skip;
+	int len;
+	struct isl_div_sort_info *array = NULL;
+	int *pos = NULL, *at = NULL;
+	int *reordering = NULL;
+	unsigned div_pos;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row <= 1)
+		return qp;
+
+	div_pos = isl_space_dim(qp->dim, isl_dim_all);
+
+	array = isl_alloc_array(qp->div->ctx, struct isl_div_sort_info,
+				qp->div->n_row);
+	pos = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+	at = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+	len = qp->div->n_col - 2;
+	reordering = isl_alloc_array(qp->div->ctx, int, len);
+	if (!array || !pos || !at || !reordering)
+		goto error;
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		array[i].div = qp->div;
+		array[i].row = i;
+		pos[i] = i;
+		at[i] = i;
+	}
+
+	qsort(array, qp->div->n_row, sizeof(struct isl_div_sort_info),
+		div_sort_cmp);
+
+	for (i = 0; i < div_pos; ++i)
+		reordering[i] = i;
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		if (pos[array[i].row] == i)
+			continue;
+		qp->div = isl_mat_swap_rows(qp->div, i, pos[array[i].row]);
+		pos[at[i]] = pos[array[i].row];
+		at[pos[array[i].row]] = at[i];
+		at[i] = array[i].row;
+		pos[array[i].row] = i;
+	}
+
+	skip = 0;
+	for (i = 0; i < len - div_pos; ++i) {
+		if (i > 0 &&
+		    isl_seq_eq(qp->div->row[i - skip - 1],
+			       qp->div->row[i - skip], qp->div->n_col)) {
+			qp->div = isl_mat_drop_rows(qp->div, i - skip, 1);
+			isl_mat_col_add(qp->div, 2 + div_pos + i - skip - 1,
+						 2 + div_pos + i - skip);
+			qp->div = isl_mat_drop_cols(qp->div,
+						    2 + div_pos + i - skip, 1);
+			skip++;
+		}
+		reordering[div_pos + array[i].row] = div_pos + i - skip;
+	}
+
+	qp->upoly = reorder(qp->upoly, reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	free(at);
+	free(pos);
+	free(array);
+	free(reordering);
+
+	return qp;
+error:
+	free(at);
+	free(pos);
+	free(array);
+	free(reordering);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+static __isl_give struct isl_upoly *expand(__isl_take struct isl_upoly *up,
+	int *exp, int first)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	if (up->var < first)
+		return up;
+
+	if (exp[up->var - first] == up->var - first)
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		goto error;
+
+	up->var = exp[up->var - first] + first;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = expand(rec->p[i], exp, first);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+static __isl_give isl_qpolynomial *with_merged_divs(
+	__isl_give isl_qpolynomial *(*fn)(__isl_take isl_qpolynomial *qp1,
+					  __isl_take isl_qpolynomial *qp2),
+	__isl_take isl_qpolynomial *qp1, __isl_take isl_qpolynomial *qp2)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div = NULL;
+	int n_div1, n_div2;
+
+	qp1 = isl_qpolynomial_cow(qp1);
+	qp2 = isl_qpolynomial_cow(qp2);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	isl_assert(qp1->div->ctx, qp1->div->n_row >= qp2->div->n_row &&
+				qp1->div->n_col >= qp2->div->n_col, goto error);
+
+	n_div1 = qp1->div->n_row;
+	n_div2 = qp2->div->n_row;
+	exp1 = isl_alloc_array(qp1->div->ctx, int, n_div1);
+	exp2 = isl_alloc_array(qp2->div->ctx, int, n_div2);
+	if ((n_div1 && !exp1) || (n_div2 && !exp2))
+		goto error;
+
+	div = isl_merge_divs(qp1->div, qp2->div, exp1, exp2);
+	if (!div)
+		goto error;
+
+	isl_mat_free(qp1->div);
+	qp1->div = isl_mat_copy(div);
+	isl_mat_free(qp2->div);
+	qp2->div = isl_mat_copy(div);
+
+	qp1->upoly = expand(qp1->upoly, exp1, div->n_col - div->n_row - 2);
+	qp2->upoly = expand(qp2->upoly, exp2, div->n_col - div->n_row - 2);
+
+	if (!qp1->upoly || !qp2->upoly)
+		goto error;
+
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+
+	return fn(qp1, qp2);
+error:
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	qp1 = isl_qpolynomial_cow(qp1);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	if (qp1->div->n_row < qp2->div->n_row)
+		return isl_qpolynomial_add(qp2, qp1);
+
+	isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error);
+	if (!compatible_divs(qp1->div, qp2->div))
+		return with_merged_divs(isl_qpolynomial_add, qp1, qp2);
+
+	qp1->upoly = isl_upoly_sum(qp1->upoly, isl_upoly_copy(qp2->upoly));
+	if (!qp1->upoly)
+		goto error;
+
+	isl_qpolynomial_free(qp2);
+
+	return qp1;
+error:
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	qp1 = isl_qpolynomial_add(qp1, qp2);
+	qp1 = isl_qpolynomial_gist(qp1, isl_set_copy(dom));
+	return qp1;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_sub(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	return isl_qpolynomial_add(qp1, isl_qpolynomial_neg(qp2));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	if (isl_int_is_zero(v))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_add_isl_int(qp->upoly, v);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_neg(__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	return isl_qpolynomial_mul_isl_int(qp, qp->dim->ctx->negone);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	if (isl_int_is_one(v))
+		return qp;
+
+	if (qp && isl_int_is_zero(v)) {
+		isl_qpolynomial *zero;
+		zero = isl_qpolynomial_zero_on_domain(isl_space_copy(qp->dim));
+		isl_qpolynomial_free(qp);
+		return zero;
+	}
+	
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_mul_isl_int(qp->upoly, v);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_scale(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	return isl_qpolynomial_mul_isl_int(qp, v);
+}
+
+/* Multiply "qp" by "v".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v)
+{
+	if (!qp || !v)
+		goto error;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return qp;
+	}
+
+	if (isl_val_is_zero(v)) {
+		isl_space *space;
+
+		space = isl_qpolynomial_get_domain_space(qp);
+		isl_qpolynomial_free(qp);
+		isl_val_free(v);
+		return isl_qpolynomial_zero_on_domain(space);
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	qp->upoly = isl_upoly_scale_val(qp->upoly, v);
+	if (!qp->upoly)
+		qp = isl_qpolynomial_free(qp);
+
+	isl_val_free(v);
+	return qp;
+error:
+	isl_val_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Divide "qp" by "v".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_down_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v)
+{
+	if (!qp || !v)
+		goto error;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_get_ctx(qp), 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_scale_val(qp, isl_val_inv(v));
+error:
+	isl_val_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_mul(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	qp1 = isl_qpolynomial_cow(qp1);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	if (qp1->div->n_row < qp2->div->n_row)
+		return isl_qpolynomial_mul(qp2, qp1);
+
+	isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error);
+	if (!compatible_divs(qp1->div, qp2->div))
+		return with_merged_divs(isl_qpolynomial_mul, qp1, qp2);
+
+	qp1->upoly = isl_upoly_mul(qp1->upoly, isl_upoly_copy(qp2->upoly));
+	if (!qp1->upoly)
+		goto error;
+
+	isl_qpolynomial_free(qp2);
+
+	return qp1;
+error:
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_pow(__isl_take isl_qpolynomial *qp,
+	unsigned power)
+{
+	qp = isl_qpolynomial_cow(qp);
+
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_pow(qp->upoly, power);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow(
+	__isl_take isl_pw_qpolynomial *pwqp, unsigned power)
+{
+	int i;
+
+	if (power == 1)
+		return pwqp;
+
+	pwqp = isl_pw_qpolynomial_cow(pwqp);
+	if (!pwqp)
+		return NULL;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		pwqp->p[i].qp = isl_qpolynomial_pow(pwqp->p[i].qp, power);
+		if (!pwqp->p[i].qp)
+			return isl_pw_qpolynomial_free(pwqp);
+	}
+
+	return pwqp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_one(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_infty(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_neginfty(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_nan(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain(
+	__isl_take isl_space *dim,
+	isl_int v)
+{
+	struct isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!dim)
+		return NULL;
+
+	qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+	if (!qp)
+		return NULL;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, v);
+
+	return qp;
+}
+
+int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp,
+	isl_int *n, isl_int *d)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!qp)
+		return -1;
+
+	if (!isl_upoly_is_cst(qp->upoly))
+		return 0;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	if (!cst)
+		return -1;
+
+	if (n)
+		isl_int_set(*n, cst->n);
+	if (d)
+		isl_int_set(*d, cst->d);
+
+	return 1;
+}
+
+/* Return the constant term of "up".
+ */
+static __isl_give isl_val *isl_upoly_get_constant_val(
+	__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return NULL;
+
+	while (!isl_upoly_is_cst(up)) {
+		struct isl_upoly_rec *rec;
+
+		rec = isl_upoly_as_rec(up);
+		if (!rec)
+			return NULL;
+		up = rec->p[0];
+	}
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return NULL;
+	return isl_val_rat_from_isl_int(cst->up.ctx, cst->n, cst->d);
+}
+
+/* Return the constant term of "qp".
+ */
+__isl_give isl_val *isl_qpolynomial_get_constant_val(
+	__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	return isl_upoly_get_constant_val(qp->upoly);
+}
+
+int isl_upoly_is_affine(__isl_keep struct isl_upoly *up)
+{
+	int is_cst;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return -1;
+
+	if (up->var < 0)
+		return 1;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -1;
+
+	if (rec->n > 2)
+		return 0;
+
+	isl_assert(up->ctx, rec->n > 1, return -1);
+
+	is_cst = isl_upoly_is_cst(rec->p[1]);
+	if (is_cst < 0)
+		return -1;
+	if (!is_cst)
+		return 0;
+
+	return isl_upoly_is_affine(rec->p[0]);
+}
+
+int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return -1;
+
+	if (qp->div->n_row > 0)
+		return 0;
+
+	return isl_upoly_is_affine(qp->upoly);
+}
+
+static void update_coeff(__isl_keep isl_vec *aff,
+	__isl_keep struct isl_upoly_cst *cst, int pos)
+{
+	isl_int gcd;
+	isl_int f;
+
+	if (isl_int_is_zero(cst->n))
+		return;
+
+	isl_int_init(gcd);
+	isl_int_init(f);
+	isl_int_gcd(gcd, cst->d, aff->el[0]);
+	isl_int_divexact(f, cst->d, gcd);
+	isl_int_divexact(gcd, aff->el[0], gcd);
+	isl_seq_scale(aff->el, aff->el, f, aff->size);
+	isl_int_mul(aff->el[1 + pos], gcd, cst->n);
+	isl_int_clear(gcd);
+	isl_int_clear(f);
+}
+
+int isl_upoly_update_affine(__isl_keep struct isl_upoly *up,
+	__isl_keep isl_vec *aff)
+{
+	struct isl_upoly_cst *cst;
+	struct isl_upoly_rec *rec;
+
+	if (!up || !aff)
+		return -1;
+
+	if (up->var < 0) {
+		struct isl_upoly_cst *cst;
+
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			return -1;
+		update_coeff(aff, cst, 0);
+		return 0;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -1;
+	isl_assert(up->ctx, rec->n == 2, return -1);
+
+	cst = isl_upoly_as_cst(rec->p[1]);
+	if (!cst)
+		return -1;
+	update_coeff(aff, cst, 1 + up->var);
+
+	return isl_upoly_update_affine(rec->p[0], aff);
+}
+
+__isl_give isl_vec *isl_qpolynomial_extract_affine(
+	__isl_keep isl_qpolynomial *qp)
+{
+	isl_vec *aff;
+	unsigned d;
+
+	if (!qp)
+		return NULL;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	aff = isl_vec_alloc(qp->div->ctx, 2 + d + qp->div->n_row);
+	if (!aff)
+		return NULL;
+
+	isl_seq_clr(aff->el + 1, 1 + d + qp->div->n_row);
+	isl_int_set_si(aff->el[0], 1);
+
+	if (isl_upoly_update_affine(qp->upoly, aff) < 0)
+		goto error;
+
+	return aff;
+error:
+	isl_vec_free(aff);
+	return NULL;
+}
+
+int isl_qpolynomial_plain_is_equal(__isl_keep isl_qpolynomial *qp1,
+	__isl_keep isl_qpolynomial *qp2)
+{
+	int equal;
+
+	if (!qp1 || !qp2)
+		return -1;
+
+	equal = isl_space_is_equal(qp1->dim, qp2->dim);
+	if (equal < 0 || !equal)
+		return equal;
+
+	equal = isl_mat_is_equal(qp1->div, qp2->div);
+	if (equal < 0 || !equal)
+		return equal;
+
+	return isl_upoly_is_equal(qp1->upoly, qp2->upoly);
+}
+
+static void upoly_update_den(__isl_keep struct isl_upoly *up, isl_int *d)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (isl_upoly_is_cst(up)) {
+		struct isl_upoly_cst *cst;
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			return;
+		isl_int_lcm(*d, *d, cst->d);
+		return;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return;
+
+	for (i = 0; i < rec->n; ++i)
+		upoly_update_den(rec->p[i], d);
+}
+
+void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d)
+{
+	isl_int_set_si(*d, 1);
+	if (!qp)
+		return;
+	upoly_update_den(qp->upoly, d);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain(
+	__isl_take isl_space *dim, int pos, int power)
+{
+	struct isl_ctx *ctx;
+
+	if (!dim)
+		return NULL;
+
+	ctx = dim->ctx;
+
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_var_pow(ctx, pos, power));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+
+	isl_assert(dim->ctx, isl_space_dim(dim, isl_dim_in) == 0, goto error);
+	isl_assert(dim->ctx, pos < isl_space_dim(dim, type), goto error);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(dim, isl_dim_param);
+
+	return isl_qpolynomial_var_pow_on_domain(dim, pos, 1);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_subs(__isl_take struct isl_upoly *up,
+	unsigned first, unsigned n, __isl_keep struct isl_upoly **subs)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *base, *res;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	if (up->var < first)
+		return up;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	if (up->var >= first + n)
+		base = isl_upoly_var_pow(up->ctx, up->var, 1);
+	else
+		base = isl_upoly_copy(subs[up->var - first]);
+
+	res = isl_upoly_subs(isl_upoly_copy(rec->p[rec->n - 1]), first, n, subs);
+	for (i = rec->n - 2; i >= 0; --i) {
+		struct isl_upoly *t;
+		t = isl_upoly_subs(isl_upoly_copy(rec->p[i]), first, n, subs);
+		res = isl_upoly_mul(res, isl_upoly_copy(base));
+		res = isl_upoly_sum(res, t);
+	}
+
+	isl_upoly_free(base);
+	isl_upoly_free(up);
+				
+	return res;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}	
+
+__isl_give struct isl_upoly *isl_upoly_from_affine(isl_ctx *ctx, isl_int *f,
+	isl_int denom, unsigned len)
+{
+	int i;
+	struct isl_upoly *up;
+
+	isl_assert(ctx, len >= 1, return NULL);
+
+	up = isl_upoly_rat_cst(ctx, f[0], denom);
+	for (i = 0; i < len - 1; ++i) {
+		struct isl_upoly *t;
+		struct isl_upoly *c;
+
+		if (isl_int_is_zero(f[1 + i]))
+			continue;
+
+		c = isl_upoly_rat_cst(ctx, f[1 + i], denom);
+		t = isl_upoly_var_pow(ctx, i, 1);
+		t = isl_upoly_mul(c, t);
+		up = isl_upoly_sum(up, t);
+	}
+
+	return up;
+}
+
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_qpolynomial *qp, int div)
+{
+	isl_ctx *ctx = qp->div->ctx;
+	unsigned total = qp->div->n_col - 2;
+
+	isl_seq_gcd(qp->div->row[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd,
+		    ctx->normalize_gcd, qp->div->row[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+
+	isl_seq_scale_down(qp->div->row[div] + 2, qp->div->row[div] + 2,
+			    ctx->normalize_gcd, total);
+	isl_int_divexact(qp->div->row[div][0], qp->div->row[div][0],
+			    ctx->normalize_gcd);
+	isl_int_fdiv_q(qp->div->row[div][1], qp->div->row[div][1],
+			    ctx->normalize_gcd);
+}
+
+/* Replace the integer division identified by "div" by the polynomial "s".
+ * The integer division is assumed not to appear in the definition
+ * of any other integer divisions.
+ */
+static __isl_give isl_qpolynomial *substitute_div(
+	__isl_take isl_qpolynomial *qp,
+	int div, __isl_take struct isl_upoly *s)
+{
+	int i;
+	int total;
+	int *reordering;
+
+	if (!qp || !s)
+		goto error;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	qp->upoly = isl_upoly_subs(qp->upoly, total + div, 1, &s);
+	if (!qp->upoly)
+		goto error;
+
+	reordering = isl_alloc_array(qp->dim->ctx, int, total + qp->div->n_row);
+	if (!reordering)
+		goto error;
+	for (i = 0; i < total + div; ++i)
+		reordering[i] = i;
+	for (i = total + div + 1; i < total + qp->div->n_row; ++i)
+		reordering[i] = i - 1;
+	qp->div = isl_mat_drop_rows(qp->div, div, 1);
+	qp->div = isl_mat_drop_cols(qp->div, 2 + total + div, 1);
+	qp->upoly = reorder(qp->upoly, reordering);
+	free(reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	isl_upoly_free(s);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_upoly_free(s);
+	return NULL;
+}
+
+/* Replace all integer divisions [e/d] that turn out to not actually be integer
+ * divisions because d is equal to 1 by their definition, i.e., e.
+ */
+static __isl_give isl_qpolynomial *substitute_non_divs(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, j;
+	int total;
+	struct isl_upoly *s;
+
+	if (!qp)
+		return NULL;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	for (i = 0; qp && i < qp->div->n_row; ++i) {
+		if (!isl_int_is_one(qp->div->row[i][0]))
+			continue;
+		for (j = i + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + i]))
+				continue;
+			isl_seq_combine(qp->div->row[j] + 1,
+				qp->div->ctx->one, qp->div->row[j] + 1,
+				qp->div->row[j][2 + total + i],
+				qp->div->row[i] + 1, 1 + total + i);
+			isl_int_set_si(qp->div->row[j][2 + total + i], 0);
+			normalize_div(qp, j);
+		}
+		s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1,
+					qp->div->row[i][0], qp->div->n_col - 1);
+		qp = substitute_div(qp, i, s);
+		--i;
+	}
+
+	return qp;
+}
+
+/* Reduce the coefficients of div "div" to lie in the interval [0, d-1],
+ * with d the denominator.  When replacing the coefficient e of x by
+ * d * frac(e/d) = e - d * floor(e/d), we are subtracting d * floor(e/d) * x
+ * inside the division, so we need to add floor(e/d) * x outside.
+ * That is, we replace q by q' + floor(e/d) * x and we therefore need
+ * to adjust the coefficient of x in each later div that depends on the
+ * current div "div" and also in the affine expression "aff"
+ * (if it too depends on "div").
+ */
+static void reduce_div(__isl_keep isl_qpolynomial *qp, int div,
+	__isl_keep isl_vec *aff)
+{
+	int i, j;
+	isl_int v;
+	unsigned total = qp->div->n_col - qp->div->n_row - 2;
+
+	isl_int_init(v);
+	for (i = 0; i < 1 + total + div; ++i) {
+		if (isl_int_is_nonneg(qp->div->row[div][1 + i]) &&
+		    isl_int_lt(qp->div->row[div][1 + i], qp->div->row[div][0]))
+			continue;
+		isl_int_fdiv_q(v, qp->div->row[div][1 + i], qp->div->row[div][0]);
+		isl_int_fdiv_r(qp->div->row[div][1 + i],
+				qp->div->row[div][1 + i], qp->div->row[div][0]);
+		if (!isl_int_is_zero(aff->el[1 + total + div]))
+			isl_int_addmul(aff->el[i], v, aff->el[1 + total + div]);
+		for (j = div + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + div]))
+				continue;
+			isl_int_addmul(qp->div->row[j][1 + i],
+					v, qp->div->row[j][2 + total + div]);
+		}
+	}
+	isl_int_clear(v);
+}
+
+/* Check if the last non-zero coefficient is bigger that half of the
+ * denominator.  If so, we will invert the div to further reduce the number
+ * of distinct divs that may appear.
+ * If the last non-zero coefficient is exactly half the denominator,
+ * then we continue looking for earlier coefficients that are bigger
+ * than half the denominator.
+ */
+static int needs_invert(__isl_keep isl_mat *div, int row)
+{
+	int i;
+	int cmp;
+
+	for (i = div->n_col - 1; i >= 1; --i) {
+		if (isl_int_is_zero(div->row[row][i]))
+			continue;
+		isl_int_mul_ui(div->row[row][i], div->row[row][i], 2);
+		cmp = isl_int_cmp(div->row[row][i], div->row[row][0]);
+		isl_int_divexact_ui(div->row[row][i], div->row[row][i], 2);
+		if (cmp)
+			return cmp > 0;
+		if (i == 1)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Replace div "div" q = [e/d] by -[(-e+(d-1))/d].
+ * We only invert the coefficients of e (and the coefficient of q in
+ * later divs and in "aff").  After calling this function, the
+ * coefficients of e should be reduced again.
+ */
+static void invert_div(__isl_keep isl_qpolynomial *qp, int div,
+	__isl_keep isl_vec *aff)
+{
+	unsigned total = qp->div->n_col - qp->div->n_row - 2;
+
+	isl_seq_neg(qp->div->row[div] + 1,
+		    qp->div->row[div] + 1, qp->div->n_col - 1);
+	isl_int_sub_ui(qp->div->row[div][1], qp->div->row[div][1], 1);
+	isl_int_add(qp->div->row[div][1],
+		    qp->div->row[div][1], qp->div->row[div][0]);
+	if (!isl_int_is_zero(aff->el[1 + total + div]))
+		isl_int_neg(aff->el[1 + total + div], aff->el[1 + total + div]);
+	isl_mat_col_mul(qp->div, 2 + total + div,
+			qp->div->ctx->negone, 2 + total + div);
+}
+
+/* Assuming "qp" is a monomial, reduce all its divs to have coefficients
+ * in the interval [0, d-1], with d the denominator and such that the
+ * last non-zero coefficient that is not equal to d/2 is smaller than d/2.
+ *
+ * After the reduction, some divs may have become redundant or identical,
+ * so we call substitute_non_divs and sort_divs.  If these functions
+ * eliminate divs or merge two or more divs into one, the coefficients
+ * of the enclosing divs may have to be reduced again, so we call
+ * ourselves recursively if the number of divs decreases.
+ */
+static __isl_give isl_qpolynomial *reduce_divs(__isl_take isl_qpolynomial *qp)
+{
+	int i;
+	isl_vec *aff = NULL;
+	struct isl_upoly *s;
+	unsigned n_div;
+
+	if (!qp)
+		return NULL;
+
+	aff = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1);
+	aff = isl_vec_clr(aff);
+	if (!aff)
+		goto error;
+
+	isl_int_set_si(aff->el[1 + qp->upoly->var], 1);
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		normalize_div(qp, i);
+		reduce_div(qp, i, aff);
+		if (needs_invert(qp->div, i)) {
+			invert_div(qp, i, aff);
+			reduce_div(qp, i, aff);
+		}
+	}
+
+	s = isl_upoly_from_affine(qp->div->ctx, aff->el,
+				  qp->div->ctx->one, aff->size);
+	qp->upoly = isl_upoly_subs(qp->upoly, qp->upoly->var, 1, &s);
+	isl_upoly_free(s);
+	if (!qp->upoly)
+		goto error;
+
+	isl_vec_free(aff);
+
+	n_div = qp->div->n_row;
+	qp = substitute_non_divs(qp);
+	qp = sort_divs(qp);
+	if (qp && qp->div->n_row < n_div)
+		return reduce_divs(qp);
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_vec_free(aff);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain(
+	__isl_take isl_space *dim, const isl_int n, const isl_int d)
+{
+	struct isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!dim)
+		return NULL;
+
+	qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+	if (!qp)
+		return NULL;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, n);
+	isl_int_set(cst->d, d);
+
+	return qp;
+}
+
+/* Return an isl_qpolynomial that is equal to "val" on domain space "domain".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain(
+	__isl_take isl_space *domain, __isl_take isl_val *val)
+{
+	isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!domain || !val)
+		goto error;
+
+	qp = isl_qpolynomial_alloc(isl_space_copy(domain), 0,
+					isl_upoly_zero(domain->ctx));
+	if (!qp)
+		goto error;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, val->n);
+	isl_int_set(cst->d, val->d);
+
+	isl_space_free(domain);
+	isl_val_free(val);
+	return qp;
+error:
+	isl_space_free(domain);
+	isl_val_free(val);
+	return NULL;
+}
+
+static int up_set_active(__isl_keep struct isl_upoly *up, int *active, int d)
+{
+	struct isl_upoly_rec *rec;
+	int i;
+
+	if (!up)
+		return -1;
+
+	if (isl_upoly_is_cst(up))
+		return 0;
+
+	if (up->var < d)
+		active[up->var] = 1;
+
+	rec = isl_upoly_as_rec(up);
+	for (i = 0; i < rec->n; ++i)
+		if (up_set_active(rec->p[i], active, d) < 0)
+			return -1;
+
+	return 0;
+}
+
+static int set_active(__isl_keep isl_qpolynomial *qp, int *active)
+{
+	int i, j;
+	int d = isl_space_dim(qp->dim, isl_dim_all);
+
+	if (!qp || !active)
+		return -1;
+
+	for (i = 0; i < d; ++i)
+		for (j = 0; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + i]))
+				continue;
+			active[i] = 1;
+			break;
+		}
+
+	return up_set_active(qp->upoly, active, d);
+}
+
+int isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	int *active = NULL;
+	int involves = 0;
+
+	if (!qp)
+		return -1;
+	if (n == 0)
+		return 0;
+
+	isl_assert(qp->dim->ctx,
+		    first + n <= isl_qpolynomial_dim(qp, type), return -1);
+	isl_assert(qp->dim->ctx, type == isl_dim_param ||
+				 type == isl_dim_in, return -1);
+
+	active = isl_calloc_array(qp->dim->ctx, int,
+					isl_space_dim(qp->dim, isl_dim_all));
+	if (set_active(qp, active) < 0)
+		goto error;
+
+	if (type == isl_dim_in)
+		first += isl_space_dim(qp->dim, isl_dim_param);
+	for (i = 0; i < n; ++i)
+		if (active[first + i]) {
+			involves = 1;
+			break;
+		}
+
+	free(active);
+
+	return involves;
+error:
+	free(active);
+	return -1;
+}
+
+/* Remove divs that do not appear in the quasi-polynomial, nor in any
+ * of the divs that do appear in the quasi-polynomial.
+ */
+static __isl_give isl_qpolynomial *remove_redundant_divs(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, j;
+	int d;
+	int len;
+	int skip;
+	int *active = NULL;
+	int *reordering = NULL;
+	int redundant = 0;
+	int n_div;
+	isl_ctx *ctx;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row == 0)
+		return qp;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	len = qp->div->n_col - 2;
+	ctx = isl_qpolynomial_get_ctx(qp);
+	active = isl_calloc_array(ctx, int, len);
+	if (!active)
+		goto error;
+
+	if (up_set_active(qp->upoly, active, len) < 0)
+		goto error;
+
+	for (i = qp->div->n_row - 1; i >= 0; --i) {
+		if (!active[d + i]) {
+			redundant = 1;
+			continue;
+		}
+		for (j = 0; j < i; ++j) {
+			if (isl_int_is_zero(qp->div->row[i][2 + d + j]))
+				continue;
+			active[d + j] = 1;
+			break;
+		}
+	}
+
+	if (!redundant) {
+		free(active);
+		return qp;
+	}
+
+	reordering = isl_alloc_array(qp->div->ctx, int, len);
+	if (!reordering)
+		goto error;
+
+	for (i = 0; i < d; ++i)
+		reordering[i] = i;
+
+	skip = 0;
+	n_div = qp->div->n_row;
+	for (i = 0; i < n_div; ++i) {
+		if (!active[d + i]) {
+			qp->div = isl_mat_drop_rows(qp->div, i - skip, 1);
+			qp->div = isl_mat_drop_cols(qp->div,
+						    2 + d + i - skip, 1);
+			skip++;
+		}
+		reordering[d + i] = d + i - skip;
+	}
+
+	qp->upoly = reorder(qp->upoly, reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	free(active);
+	free(reordering);
+
+	return qp;
+error:
+	free(active);
+	free(reordering);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_drop(__isl_take struct isl_upoly *up,
+	unsigned first, unsigned n)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+	if (n == 0 || up->var < 0 || up->var < first)
+		return up;
+	if (up->var < first + n) {
+		up = replace_by_constant_term(up);
+		return isl_upoly_drop(up, first, n);
+	}
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+	up->var -= n;
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_drop(rec->p[i], first, n);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+	qp->dim = isl_space_set_dim_name(qp->dim, type, pos, s);
+	if (!qp->dim)
+		goto error;
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (!qp)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot drop output/set dimension",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type),
+			goto error);
+	isl_assert(qp->dim->ctx, type == isl_dim_param ||
+				 type == isl_dim_set, goto error);
+
+	qp->dim = isl_space_drop_dims(qp->dim, type, first, n);
+	if (!qp->dim)
+		goto error;
+
+	if (type == isl_dim_set)
+		first += isl_space_dim(qp->dim, isl_dim_param);
+
+	qp->div = isl_mat_drop_cols(qp->div, 2 + first, n);
+	if (!qp->div)
+		goto error;
+
+	qp->upoly = isl_upoly_drop(qp->upoly, first, n);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Project the domain of the quasi-polynomial onto its parameter space.
+ * The quasi-polynomial may not involve any of the domain dimensions.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_project_domain_on_params(
+	__isl_take isl_qpolynomial *qp)
+{
+	isl_space *space;
+	unsigned n;
+	int involves;
+
+	n = isl_qpolynomial_dim(qp, isl_dim_in);
+	involves = isl_qpolynomial_involves_dims(qp, isl_dim_in, 0, n);
+	if (involves < 0)
+		return isl_qpolynomial_free(qp);
+	if (involves)
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"polynomial involves some of the domain dimensions",
+			return isl_qpolynomial_free(qp));
+	qp = isl_qpolynomial_drop_dims(qp, isl_dim_in, 0, n);
+	space = isl_qpolynomial_get_domain_space(qp);
+	space = isl_space_params(space);
+	qp = isl_qpolynomial_reset_domain_space(qp, space);
+	return qp;
+}
+
+static __isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities_lifted(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq)
+{
+	int i, j, k;
+	isl_int denom;
+	unsigned total;
+	unsigned n_div;
+	struct isl_upoly *up;
+
+	if (!eq)
+		goto error;
+	if (eq->n_eq == 0) {
+		isl_basic_set_free(eq);
+		return qp;
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	total = 1 + isl_space_dim(eq->dim, isl_dim_all);
+	n_div = eq->n_div;
+	isl_int_init(denom);
+	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 < qp->div->n_row; ++k) {
+			if (isl_int_is_zero(qp->div->row[k][1 + j]))
+				continue;
+			isl_seq_elim(qp->div->row[k] + 1, eq->eq[i], j, total,
+					&qp->div->row[k][0]);
+			normalize_div(qp, k);
+		}
+
+		if (isl_int_is_pos(eq->eq[i][j]))
+			isl_seq_neg(eq->eq[i], eq->eq[i], total);
+		isl_int_abs(denom, eq->eq[i][j]);
+		isl_int_set_si(eq->eq[i][j], 0);
+
+		up = isl_upoly_from_affine(qp->dim->ctx,
+						   eq->eq[i], denom, total);
+		qp->upoly = isl_upoly_subs(qp->upoly, j - 1, 1, &up);
+		isl_upoly_free(up);
+	}
+	isl_int_clear(denom);
+
+	if (!qp->upoly)
+		goto error;
+
+	isl_basic_set_free(eq);
+
+	qp = substitute_non_divs(qp);
+	qp = sort_divs(qp);
+
+	return qp;
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Exploit the equalities in "eq" to simplify the quasi-polynomial.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq)
+{
+	if (!qp || !eq)
+		goto error;
+	if (qp->div->n_row > 0)
+		eq = isl_basic_set_add_dims(eq, isl_dim_set, qp->div->n_row);
+	return isl_qpolynomial_substitute_equalities_lifted(qp, eq);
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *add_div_constraints(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div)
+{
+	int i;
+	unsigned total;
+
+	if (!bset || !div)
+		goto error;
+
+	bset = isl_basic_set_extend_constraints(bset, 0, 2 * div->n_row);
+	if (!bset)
+		goto error;
+	total = isl_basic_set_total_dim(bset);
+	for (i = 0; i < div->n_row; ++i)
+		if (isl_basic_set_add_div_constraints_var(bset,
+				    total - div->n_row + i, div->row[i]) < 0)
+			goto error;
+
+	isl_mat_free(div);
+	return bset;
+error:
+	isl_mat_free(div);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Look for equalities among the variables shared by context and qp
+ * and the integer divisions of qp, if any.
+ * The equalities are then used to eliminate variables and/or integer
+ * divisions from qp.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_gist(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context)
+{
+	isl_basic_set *aff;
+
+	if (!qp)
+		goto error;
+	if (qp->div->n_row > 0) {
+		isl_basic_set *bset;
+		context = isl_set_add_dims(context, isl_dim_set,
+					    qp->div->n_row);
+		bset = isl_basic_set_universe(isl_set_get_space(context));
+		bset = add_div_constraints(bset, isl_mat_copy(qp->div));
+		context = isl_set_intersect(context,
+					    isl_set_from_basic_set(bset));
+	}
+
+	aff = isl_set_affine_hull(context);
+	return isl_qpolynomial_substitute_equalities_lifted(qp, aff);
+error:
+	isl_qpolynomial_free(qp);
+	isl_set_free(context);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_gist_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context)
+{
+	isl_space *space = isl_qpolynomial_get_domain_space(qp);
+	isl_set *dom_context = isl_set_universe(space);
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return isl_qpolynomial_gist(qp, dom_context);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp)
+{
+	isl_set *dom;
+
+	if (!qp)
+		return NULL;
+	if (isl_qpolynomial_is_zero(qp)) {
+		isl_space *dim = isl_qpolynomial_get_space(qp);
+		isl_qpolynomial_free(qp);
+		return isl_pw_qpolynomial_zero(dim);
+	}
+
+	dom = isl_set_universe(isl_qpolynomial_get_domain_space(qp));
+	return isl_pw_qpolynomial_alloc(dom, qp);
+}
+
+#undef PW
+#define PW isl_pw_qpolynomial
+#undef EL
+#define EL isl_qpolynomial
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_zero
+#undef ZERO
+#define ZERO zero
+#undef IS_ZERO
+#define IS_ZERO is_zero
+#undef FIELD
+#define FIELD qp
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 1
+
+#define NO_PULLBACK
+
+#include <isl_pw_templ.c>
+
+#undef UNION
+#define UNION isl_union_pw_qpolynomial
+#undef PART
+#define PART isl_pw_qpolynomial
+#undef PARTS
+#define PARTS pw_qpolynomial
+#define ALIGN_DOMAIN
+
+#include <isl_union_templ.c>
+
+int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp)
+{
+	if (!pwqp)
+		return -1;
+
+	if (pwqp->n != -1)
+		return 0;
+
+	if (!isl_set_plain_is_universe(pwqp->p[0].set))
+		return 0;
+
+	return isl_qpolynomial_is_one(pwqp->p[0].qp);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2)
+{
+	return isl_pw_qpolynomial_union_add_(pwqp1, pwqp2);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2)
+{
+	int i, j, n;
+	struct isl_pw_qpolynomial *res;
+
+	if (!pwqp1 || !pwqp2)
+		goto error;
+
+	isl_assert(pwqp1->dim->ctx, isl_space_is_equal(pwqp1->dim, pwqp2->dim),
+			goto error);
+
+	if (isl_pw_qpolynomial_is_zero(pwqp1)) {
+		isl_pw_qpolynomial_free(pwqp2);
+		return pwqp1;
+	}
+
+	if (isl_pw_qpolynomial_is_zero(pwqp2)) {
+		isl_pw_qpolynomial_free(pwqp1);
+		return pwqp2;
+	}
+
+	if (isl_pw_qpolynomial_is_one(pwqp1)) {
+		isl_pw_qpolynomial_free(pwqp1);
+		return pwqp2;
+	}
+
+	if (isl_pw_qpolynomial_is_one(pwqp2)) {
+		isl_pw_qpolynomial_free(pwqp2);
+		return pwqp1;
+	}
+
+	n = pwqp1->n * pwqp2->n;
+	res = isl_pw_qpolynomial_alloc_size(isl_space_copy(pwqp1->dim), n);
+
+	for (i = 0; i < pwqp1->n; ++i) {
+		for (j = 0; j < pwqp2->n; ++j) {
+			struct isl_set *common;
+			struct isl_qpolynomial *prod;
+			common = isl_set_intersect(isl_set_copy(pwqp1->p[i].set),
+						isl_set_copy(pwqp2->p[j].set));
+			if (isl_set_plain_is_empty(common)) {
+				isl_set_free(common);
+				continue;
+			}
+
+			prod = isl_qpolynomial_mul(
+				isl_qpolynomial_copy(pwqp1->p[i].qp),
+				isl_qpolynomial_copy(pwqp2->p[j].qp));
+
+			res = isl_pw_qpolynomial_add_piece(res, common, prod);
+		}
+	}
+
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+
+	return res;
+error:
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+	return NULL;
+}
+
+__isl_give isl_val *isl_upoly_eval(__isl_take struct isl_upoly *up,
+	__isl_take isl_vec *vec)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	isl_val *res;
+	isl_val *base;
+
+	if (isl_upoly_is_cst(up)) {
+		isl_vec_free(vec);
+		res = isl_upoly_get_constant_val(up);
+		isl_upoly_free(up);
+		return res;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	base = isl_val_rat_from_isl_int(up->ctx,
+					vec->el[1 + up->var], vec->el[0]);
+
+	res = isl_upoly_eval(isl_upoly_copy(rec->p[rec->n - 1]),
+				isl_vec_copy(vec));
+
+	for (i = rec->n - 2; i >= 0; --i) {
+		res = isl_val_mul(res, isl_val_copy(base));
+		res = isl_val_add(res,
+			    isl_upoly_eval(isl_upoly_copy(rec->p[i]),
+							    isl_vec_copy(vec)));
+	}
+
+	isl_val_free(base);
+	isl_upoly_free(up);
+	isl_vec_free(vec);
+	return res;
+error:
+	isl_upoly_free(up);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_point *pnt)
+{
+	isl_vec *ext;
+	isl_val *v;
+
+	if (!qp || !pnt)
+		goto error;
+	isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, qp->dim), goto error);
+
+	if (qp->div->n_row == 0)
+		ext = isl_vec_copy(pnt->vec);
+	else {
+		int i;
+		unsigned dim = isl_space_dim(qp->dim, isl_dim_all);
+		ext = isl_vec_alloc(qp->dim->ctx, 1 + dim + qp->div->n_row);
+		if (!ext)
+			goto error;
+
+		isl_seq_cpy(ext->el, pnt->vec->el, pnt->vec->size);
+		for (i = 0; i < qp->div->n_row; ++i) {
+			isl_seq_inner_product(qp->div->row[i] + 1, ext->el,
+						1 + dim + i, &ext->el[1+dim+i]);
+			isl_int_fdiv_q(ext->el[1+dim+i], ext->el[1+dim+i],
+					qp->div->row[i][0]);
+		}
+	}
+
+	v = isl_upoly_eval(isl_upoly_copy(qp->upoly), ext);
+
+	isl_qpolynomial_free(qp);
+	isl_point_free(pnt);
+
+	return v;
+error:
+	isl_qpolynomial_free(qp);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+int isl_upoly_cmp(__isl_keep struct isl_upoly_cst *cst1,
+	__isl_keep struct isl_upoly_cst *cst2)
+{
+	int cmp;
+	isl_int t;
+	isl_int_init(t);
+	isl_int_mul(t, cst1->n, cst2->d);
+	isl_int_submul(t, cst2->n, cst1->d);
+	cmp = isl_int_sgn(t);
+	isl_int_clear(t);
+	return cmp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_insert_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	unsigned total;
+	unsigned g_pos;
+	int *exp;
+
+	if (!qp)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(qp->div->ctx, isl_error_invalid,
+			"cannot insert output/set dimensions",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	isl_assert(qp->div->ctx, first <= isl_space_dim(qp->dim, type),
+		    goto error);
+
+	g_pos = pos(qp->dim, type) + first;
+
+	qp->div = isl_mat_insert_zero_cols(qp->div, 2 + g_pos, n);
+	if (!qp->div)
+		goto error;
+
+	total = qp->div->n_col - 2;
+	if (total > g_pos) {
+		int i;
+		exp = isl_alloc_array(qp->div->ctx, int, total - g_pos);
+		if (!exp)
+			goto error;
+		for (i = 0; i < total - g_pos; ++i)
+			exp[i] = i + n;
+		qp->upoly = expand(qp->upoly, exp, g_pos);
+		free(exp);
+		if (!qp->upoly)
+			goto error;
+	}
+
+	qp->dim = isl_space_insert_dims(qp->dim, type, first, n);
+	if (!qp->dim)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_qpolynomial_dim(qp, type);
+
+	return isl_qpolynomial_insert_dims(qp, type, pos, n);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_pw_qpolynomial_dim(pwqp, type);
+
+	return isl_pw_qpolynomial_insert_dims(pwqp, type, pos, n);
+}
+
+static int *reordering_move(isl_ctx *ctx,
+	unsigned len, unsigned dst, unsigned src, unsigned n)
+{
+	int i;
+	int *reordering;
+
+	reordering = isl_alloc_array(ctx, int, len);
+	if (!reordering)
+		return NULL;
+
+	if (dst <= src) {
+		for (i = 0; i < dst; ++i)
+			reordering[i] = i;
+		for (i = 0; i < n; ++i)
+			reordering[src + i] = dst + i;
+		for (i = 0; i < src - dst; ++i)
+			reordering[dst + i] = dst + n + i;
+		for (i = 0; i < len - src - n; ++i)
+			reordering[src + n + i] = src + n + i;
+	} else {
+		for (i = 0; i < src; ++i)
+			reordering[i] = i;
+		for (i = 0; i < n; ++i)
+			reordering[src + i] = dst + i;
+		for (i = 0; i < dst - src; ++i)
+			reordering[src + n + i] = src + i;
+		for (i = 0; i < len - dst - n; ++i)
+			reordering[dst + n + i] = dst + n + i;
+	}
+
+	return reordering;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_move_dims(
+	__isl_take isl_qpolynomial *qp,
+	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;
+	int *reordering;
+
+	if (n == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	if (dst_type == isl_dim_out || src_type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot move output/set dimension",
+			goto error);
+	if (dst_type == isl_dim_in)
+		dst_type = isl_dim_set;
+	if (src_type == isl_dim_in)
+		src_type = isl_dim_set;
+
+	isl_assert(qp->dim->ctx, src_pos + n <= isl_space_dim(qp->dim, src_type),
+		goto error);
+
+	g_dst_pos = pos(qp->dim, dst_type) + dst_pos;
+	g_src_pos = pos(qp->dim, src_type) + src_pos;
+	if (dst_type > src_type)
+		g_dst_pos -= n;
+
+	qp->div = isl_mat_move_cols(qp->div, 2 + g_dst_pos, 2 + g_src_pos, n);
+	if (!qp->div)
+		goto error;
+	qp = sort_divs(qp);
+	if (!qp)
+		goto error;
+
+	reordering = reordering_move(qp->dim->ctx,
+				qp->div->n_col - 2, g_dst_pos, g_src_pos, n);
+	if (!reordering)
+		goto error;
+
+	qp->upoly = reorder(qp->upoly, reordering);
+	free(reordering);
+	if (!qp->upoly)
+		goto error;
+
+	qp->dim = isl_space_move_dims(qp->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!qp->dim)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim,
+	isl_int *f, isl_int denom)
+{
+	struct isl_upoly *up;
+
+	dim = isl_space_domain(dim);
+	if (!dim)
+		return NULL;
+
+	up = isl_upoly_from_affine(dim->ctx, f, denom,
+					1 + isl_space_dim(dim, isl_dim_all));
+
+	return isl_qpolynomial_alloc(dim, 0, up);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(__isl_take isl_aff *aff)
+{
+	isl_ctx *ctx;
+	struct isl_upoly *up;
+	isl_qpolynomial *qp;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	up = isl_upoly_from_affine(ctx, aff->v->el + 1, aff->v->el[0],
+				    aff->v->size - 1);
+
+	qp = isl_qpolynomial_alloc(isl_aff_get_domain_space(aff),
+				    aff->ls->div->n_row, up);
+	if (!qp)
+		goto error;
+
+	isl_mat_free(qp->div);
+	qp->div = isl_mat_copy(aff->ls->div);
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	isl_aff_free(aff);
+	qp = reduce_divs(qp);
+	qp = remove_redundant_divs(qp);
+	return qp;
+error:
+	isl_aff_free(aff);
+	return isl_qpolynomial_free(qp);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_pw_aff(
+	__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+	isl_pw_qpolynomial *pwqp;
+
+	if (!pwaff)
+		return NULL;
+
+	pwqp = isl_pw_qpolynomial_alloc_size(isl_pw_aff_get_space(pwaff),
+						pwaff->n);
+
+	for (i = 0; i < pwaff->n; ++i) {
+		isl_set *dom;
+		isl_qpolynomial *qp;
+
+		dom = isl_set_copy(pwaff->p[i].set);
+		qp = isl_qpolynomial_from_aff(isl_aff_copy(pwaff->p[i].aff));
+		pwqp = isl_pw_qpolynomial_add_piece(pwqp,  dom, qp);
+	}
+
+	isl_pw_aff_free(pwaff);
+	return pwqp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_constraint(
+	__isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos)
+{
+	isl_aff *aff;
+
+	aff = isl_constraint_get_bound(c, type, pos);
+	isl_constraint_free(c);
+	return isl_qpolynomial_from_aff(aff);
+}
+
+/* For each 0 <= i < "n", replace variable "first" + i of type "type"
+ * in "qp" by subs[i].
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs)
+{
+	int i;
+	struct isl_upoly **ups;
+
+	if (n == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot substitute output/set dimension",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	for (i = 0; i < n; ++i)
+		if (!subs[i])
+			goto error;
+
+	isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type),
+			goto error);
+
+	for (i = 0; i < n; ++i)
+		isl_assert(qp->dim->ctx, isl_space_is_equal(qp->dim, subs[i]->dim),
+				goto error);
+
+	isl_assert(qp->dim->ctx, qp->div->n_row == 0, goto error);
+	for (i = 0; i < n; ++i)
+		isl_assert(qp->dim->ctx, subs[i]->div->n_row == 0, goto error);
+
+	first += pos(qp->dim, type);
+
+	ups = isl_alloc_array(qp->dim->ctx, struct isl_upoly *, n);
+	if (!ups)
+		goto error;
+	for (i = 0; i < n; ++i)
+		ups[i] = subs[i]->upoly;
+
+	qp->upoly = isl_upoly_subs(qp->upoly, first, n, ups);
+
+	free(ups);
+
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Extend "bset" with extra set dimensions for each integer division
+ * in "qp" and then call "fn" with the extended bset and the polynomial
+ * that results from replacing each of the integer divisions by the
+ * corresponding extra set dimension.
+ */
+int isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
+	__isl_keep isl_basic_set *bset,
+	int (*fn)(__isl_take isl_basic_set *bset,
+		  __isl_take isl_qpolynomial *poly, void *user), void *user)
+{
+	isl_space *dim;
+	isl_mat *div;
+	isl_qpolynomial *poly;
+
+	if (!qp || !bset)
+		goto error;
+	if (qp->div->n_row == 0)
+		return fn(isl_basic_set_copy(bset), isl_qpolynomial_copy(qp),
+			  user);
+
+	div = isl_mat_copy(qp->div);
+	dim = isl_space_copy(qp->dim);
+	dim = isl_space_add_dims(dim, isl_dim_set, qp->div->n_row);
+	poly = isl_qpolynomial_alloc(dim, 0, isl_upoly_copy(qp->upoly));
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_add_dims(bset, isl_dim_set, qp->div->n_row);
+	bset = add_div_constraints(bset, div);
+
+	return fn(bset, poly, user);
+error:
+	return -1;
+}
+
+/* Return total degree in variables first (inclusive) up to last (exclusive).
+ */
+int isl_upoly_degree(__isl_keep struct isl_upoly *up, int first, int last)
+{
+	int deg = -1;
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return -2;
+	if (isl_upoly_is_zero(up))
+		return -1;
+	if (isl_upoly_is_cst(up) || up->var < first)
+		return 0;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -2;
+
+	for (i = 0; i < rec->n; ++i) {
+		int d;
+
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		d = isl_upoly_degree(rec->p[i], first, last);
+		if (up->var < last)
+			d += i;
+		if (d > deg)
+			deg = d;
+	}
+
+	return deg;
+}
+
+/* Return total degree in set variables.
+ */
+int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly)
+{
+	unsigned ovar;
+	unsigned nvar;
+
+	if (!poly)
+		return -2;
+
+	ovar = isl_space_offset(poly->dim, isl_dim_set);
+	nvar = isl_space_dim(poly->dim, isl_dim_set);
+	return isl_upoly_degree(poly->upoly, ovar, ovar + nvar);
+}
+
+__isl_give struct isl_upoly *isl_upoly_coeff(__isl_keep struct isl_upoly *up,
+	unsigned pos, int deg)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up) || up->var < pos) {
+		if (deg == 0)
+			return isl_upoly_copy(up);
+		else
+			return isl_upoly_zero(up->ctx);
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return NULL;
+
+	if (up->var == pos) {
+		if (deg < rec->n)
+			return isl_upoly_copy(rec->p[deg]);
+		else
+			return isl_upoly_zero(up->ctx);
+	}
+
+	up = isl_upoly_copy(up);
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		struct isl_upoly *t;
+		t = isl_upoly_coeff(rec->p[i], pos, deg);
+		if (!t)
+			goto error;
+		isl_upoly_free(rec->p[i]);
+		rec->p[i] = t;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Return coefficient of power "deg" of variable "t_pos" of type "type".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_coeff(
+	__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned t_pos, int deg)
+{
+	unsigned g_pos;
+	struct isl_upoly *up;
+	isl_qpolynomial *c;
+
+	if (!qp)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(qp->div->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return NULL);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	isl_assert(qp->div->ctx, t_pos < isl_space_dim(qp->dim, type),
+			return NULL);
+
+	g_pos = pos(qp->dim, type) + t_pos;
+	up = isl_upoly_coeff(qp->upoly, g_pos, deg);
+
+	c = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row, up);
+	if (!c)
+		return NULL;
+	isl_mat_free(c->div);
+	c->div = isl_mat_copy(qp->div);
+	if (!c->div)
+		goto error;
+	return c;
+error:
+	isl_qpolynomial_free(c);
+	return NULL;
+}
+
+/* Homogenize the polynomial in the variables first (inclusive) up to
+ * last (exclusive) by inserting powers of variable first.
+ * Variable first is assumed not to appear in the input.
+ */
+__isl_give struct isl_upoly *isl_upoly_homogenize(
+	__isl_take struct isl_upoly *up, int deg, int target,
+	int first, int last)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+	if (isl_upoly_is_zero(up))
+		return up;
+	if (deg == target)
+		return up;
+	if (isl_upoly_is_cst(up) || up->var < first) {
+		struct isl_upoly *hom;
+
+		hom = isl_upoly_var_pow(up->ctx, first, target - deg);
+		if (!hom)
+			goto error;
+		rec = isl_upoly_as_rec(hom);
+		rec->p[target - deg] = isl_upoly_mul(rec->p[target - deg], up);
+
+		return hom;
+	}
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		rec->p[i] = isl_upoly_homogenize(rec->p[i],
+				up->var < last ? deg + i : i, target,
+				first, last);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Homogenize the polynomial in the set variables by introducing
+ * powers of an extra set variable at position 0.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_homogenize(
+	__isl_take isl_qpolynomial *poly)
+{
+	unsigned ovar;
+	unsigned nvar;
+	int deg = isl_qpolynomial_degree(poly);
+
+	if (deg < -1)
+		goto error;
+
+	poly = isl_qpolynomial_insert_dims(poly, isl_dim_in, 0, 1);
+	poly = isl_qpolynomial_cow(poly);
+	if (!poly)
+		goto error;
+
+	ovar = isl_space_offset(poly->dim, isl_dim_set);
+	nvar = isl_space_dim(poly->dim, isl_dim_set);
+	poly->upoly = isl_upoly_homogenize(poly->upoly, 0, deg,
+						ovar, ovar + nvar);
+	if (!poly->upoly)
+		goto error;
+
+	return poly;
+error:
+	isl_qpolynomial_free(poly);
+	return NULL;
+}
+
+__isl_give isl_term *isl_term_alloc(__isl_take isl_space *dim,
+	__isl_take isl_mat *div)
+{
+	isl_term *term;
+	int n;
+
+	if (!dim || !div)
+		goto error;
+
+	n = isl_space_dim(dim, isl_dim_all) + div->n_row;
+
+	term = isl_calloc(dim->ctx, struct isl_term,
+			sizeof(struct isl_term) + (n - 1) * sizeof(int));
+	if (!term)
+		goto error;
+
+	term->ref = 1;
+	term->dim = dim;
+	term->div = div;
+	isl_int_init(term->n);
+	isl_int_init(term->d);
+	
+	return term;
+error:
+	isl_space_free(dim);
+	isl_mat_free(div);
+	return NULL;
+}
+
+__isl_give isl_term *isl_term_copy(__isl_keep isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	term->ref++;
+	return term;
+}
+
+__isl_give isl_term *isl_term_dup(__isl_keep isl_term *term)
+{
+	int i;
+	isl_term *dup;
+	unsigned total;
+
+	if (!term)
+		return NULL;
+
+	total = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row;
+
+	dup = isl_term_alloc(isl_space_copy(term->dim), isl_mat_copy(term->div));
+	if (!dup)
+		return NULL;
+
+	isl_int_set(dup->n, term->n);
+	isl_int_set(dup->d, term->d);
+
+	for (i = 0; i < total; ++i)
+		dup->pow[i] = term->pow[i];
+
+	return dup;
+}
+
+__isl_give isl_term *isl_term_cow(__isl_take isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	if (term->ref == 1)
+		return term;
+	term->ref--;
+	return isl_term_dup(term);
+}
+
+void isl_term_free(__isl_take isl_term *term)
+{
+	if (!term)
+		return;
+
+	if (--term->ref > 0)
+		return;
+
+	isl_space_free(term->dim);
+	isl_mat_free(term->div);
+	isl_int_clear(term->n);
+	isl_int_clear(term->d);
+	free(term);
+}
+
+unsigned isl_term_dim(__isl_keep isl_term *term, enum isl_dim_type type)
+{
+	if (!term)
+		return 0;
+
+	switch (type) {
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:	return isl_space_dim(term->dim, type);
+	case isl_dim_div:	return term->div->n_row;
+	case isl_dim_all:	return isl_space_dim(term->dim, isl_dim_all) +
+								term->div->n_row;
+	default:		return 0;
+	}
+}
+
+isl_ctx *isl_term_get_ctx(__isl_keep isl_term *term)
+{
+	return term ? term->dim->ctx : NULL;
+}
+
+void isl_term_get_num(__isl_keep isl_term *term, isl_int *n)
+{
+	if (!term)
+		return;
+	isl_int_set(*n, term->n);
+}
+
+void isl_term_get_den(__isl_keep isl_term *term, isl_int *d)
+{
+	if (!term)
+		return;
+	isl_int_set(*d, term->d);
+}
+
+/* Return the coefficient of the term "term".
+ */
+__isl_give isl_val *isl_term_get_coefficient_val(__isl_keep isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	return isl_val_rat_from_isl_int(isl_term_get_ctx(term),
+					term->n, term->d);
+}
+
+int isl_term_get_exp(__isl_keep isl_term *term,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!term)
+		return -1;
+
+	isl_assert(term->dim->ctx, pos < isl_term_dim(term, type), return -1);
+
+	if (type >= isl_dim_set)
+		pos += isl_space_dim(term->dim, isl_dim_param);
+	if (type >= isl_dim_div)
+		pos += isl_space_dim(term->dim, isl_dim_set);
+
+	return term->pow[pos];
+}
+
+__isl_give isl_aff *isl_term_get_div(__isl_keep isl_term *term, unsigned pos)
+{
+	isl_local_space *ls;
+	isl_aff *aff;
+
+	if (!term)
+		return NULL;
+
+	isl_assert(term->dim->ctx, pos < isl_term_dim(term, isl_dim_div),
+			return NULL);
+
+	ls = isl_local_space_alloc_div(isl_space_copy(term->dim),
+					isl_mat_copy(term->div));
+	aff = isl_aff_alloc(ls);
+	if (!aff)
+		return NULL;
+
+	isl_seq_cpy(aff->v->el, term->div->row[pos], aff->v->size);
+
+	aff = isl_aff_normalize(aff);
+
+	return aff;
+}
+
+__isl_give isl_term *isl_upoly_foreach_term(__isl_keep struct isl_upoly *up,
+	int (*fn)(__isl_take isl_term *term, void *user),
+	__isl_take isl_term *term, void *user)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up || !term)
+		goto error;
+
+	if (isl_upoly_is_zero(up))
+		return term;
+
+	isl_assert(up->ctx, !isl_upoly_is_nan(up), goto error);
+	isl_assert(up->ctx, !isl_upoly_is_infty(up), goto error);
+	isl_assert(up->ctx, !isl_upoly_is_neginfty(up), goto error);
+
+	if (isl_upoly_is_cst(up)) {
+		struct isl_upoly_cst *cst;
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			goto error;
+		term = isl_term_cow(term);
+		if (!term)
+			goto error;
+		isl_int_set(term->n, cst->n);
+		isl_int_set(term->d, cst->d);
+		if (fn(isl_term_copy(term), user) < 0)
+			goto error;
+		return term;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		term = isl_term_cow(term);
+		if (!term)
+			goto error;
+		term->pow[up->var] = i;
+		term = isl_upoly_foreach_term(rec->p[i], fn, term, user);
+		if (!term)
+			goto error;
+	}
+	term->pow[up->var] = 0;
+
+	return term;
+error:
+	isl_term_free(term);
+	return NULL;
+}
+
+int isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp,
+	int (*fn)(__isl_take isl_term *term, void *user), void *user)
+{
+	isl_term *term;
+
+	if (!qp)
+		return -1;
+
+	term = isl_term_alloc(isl_space_copy(qp->dim), isl_mat_copy(qp->div));
+	if (!term)
+		return -1;
+
+	term = isl_upoly_foreach_term(qp->upoly, fn, term, user);
+
+	isl_term_free(term);
+
+	return term ? 0 : -1;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_term(__isl_take isl_term *term)
+{
+	struct isl_upoly *up;
+	isl_qpolynomial *qp;
+	int i, n;
+
+	if (!term)
+		return NULL;
+
+	n = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row;
+
+	up = isl_upoly_rat_cst(term->dim->ctx, term->n, term->d);
+	for (i = 0; i < n; ++i) {
+		if (!term->pow[i])
+			continue;
+		up = isl_upoly_mul(up,
+			isl_upoly_var_pow(term->dim->ctx, i, term->pow[i]));
+	}
+
+	qp = isl_qpolynomial_alloc(isl_space_copy(term->dim), term->div->n_row, up);
+	if (!qp)
+		goto error;
+	isl_mat_free(qp->div);
+	qp->div = isl_mat_copy(term->div);
+	if (!qp->div)
+		goto error;
+
+	isl_term_free(term);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_term_free(term);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_space *dim)
+{
+	int i;
+	int extra;
+	unsigned total;
+
+	if (!qp || !dim)
+		goto error;
+
+	if (isl_space_is_equal(qp->dim, dim)) {
+		isl_space_free(dim);
+		return qp;
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	extra = isl_space_dim(dim, isl_dim_set) -
+			isl_space_dim(qp->dim, isl_dim_set);
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	if (qp->div->n_row) {
+		int *exp;
+
+		exp = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+		if (!exp)
+			goto error;
+		for (i = 0; i < qp->div->n_row; ++i)
+			exp[i] = extra + i;
+		qp->upoly = expand(qp->upoly, exp, total);
+		free(exp);
+		if (!qp->upoly)
+			goto error;
+	}
+	qp->div = isl_mat_insert_cols(qp->div, 2 + total, extra);
+	if (!qp->div)
+		goto error;
+	for (i = 0; i < qp->div->n_row; ++i)
+		isl_seq_clr(qp->div->row[i] + 2 + total, extra);
+
+	isl_space_free(qp->dim);
+	qp->dim = dim;
+
+	return qp;
+error:
+	isl_space_free(dim);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* For each parameter or variable that does not appear in qp,
+ * first eliminate the variable from all constraints and then set it to zero.
+ */
+static __isl_give isl_set *fix_inactive(__isl_take isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	int *active = NULL;
+	int i;
+	int d;
+	unsigned nparam;
+	unsigned nvar;
+
+	if (!set || !qp)
+		goto error;
+
+	d = isl_space_dim(set->dim, isl_dim_all);
+	active = isl_calloc_array(set->ctx, int, d);
+	if (set_active(qp, active) < 0)
+		goto error;
+
+	for (i = 0; i < d; ++i)
+		if (!active[i])
+			break;
+
+	if (i == d) {
+		free(active);
+		return set;
+	}
+
+	nparam = isl_space_dim(set->dim, isl_dim_param);
+	nvar = isl_space_dim(set->dim, isl_dim_set);
+	for (i = 0; i < nparam; ++i) {
+		if (active[i])
+			continue;
+		set = isl_set_eliminate(set, isl_dim_param, i, 1);
+		set = isl_set_fix_si(set, isl_dim_param, i, 0);
+	}
+	for (i = 0; i < nvar; ++i) {
+		if (active[nparam + i])
+			continue;
+		set = isl_set_eliminate(set, isl_dim_set, i, 1);
+		set = isl_set_fix_si(set, isl_dim_set, i, 0);
+	}
+
+	free(active);
+
+	return set;
+error:
+	free(active);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_opt_data {
+	isl_qpolynomial *qp;
+	int first;
+	isl_val *opt;
+	int max;
+};
+
+static int opt_fn(__isl_take isl_point *pnt, void *user)
+{
+	struct isl_opt_data *data = (struct isl_opt_data *)user;
+	isl_val *val;
+
+	val = isl_qpolynomial_eval(isl_qpolynomial_copy(data->qp), pnt);
+	if (data->first) {
+		data->first = 0;
+		data->opt = val;
+	} else if (data->max) {
+		data->opt = isl_val_max(data->opt, val);
+	} else {
+		data->opt = isl_val_min(data->opt, val);
+	}
+
+	return 0;
+}
+
+__isl_give isl_val *isl_qpolynomial_opt_on_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max)
+{
+	struct isl_opt_data data = { NULL, 1, NULL, max };
+
+	if (!set || !qp)
+		goto error;
+
+	if (isl_upoly_is_cst(qp->upoly)) {
+		isl_set_free(set);
+		data.opt = isl_qpolynomial_get_constant_val(qp);
+		isl_qpolynomial_free(qp);
+		return data.opt;
+	}
+
+	set = fix_inactive(set, qp);
+
+	data.qp = qp;
+	if (isl_set_foreach_point(set, opt_fn, &data) < 0)
+		goto error;
+
+	if (data.first)
+		data.opt = isl_val_zero(isl_set_get_ctx(set));
+
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return data.opt;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	isl_val_free(data.opt);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph)
+{
+	int i;
+	int n_sub;
+	isl_ctx *ctx;
+	struct isl_upoly **subs;
+	isl_mat *mat, *diag;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp || !morph)
+		goto error;
+
+	ctx = qp->dim->ctx;
+	isl_assert(ctx, isl_space_is_equal(qp->dim, morph->dom->dim), goto error);
+
+	n_sub = morph->inv->n_row - 1;
+	if (morph->inv->n_row != morph->inv->n_col)
+		n_sub += qp->div->n_row;
+	subs = isl_calloc_array(ctx, struct isl_upoly *, n_sub);
+	if (n_sub && !subs)
+		goto error;
+
+	for (i = 0; 1 + i < morph->inv->n_row; ++i)
+		subs[i] = isl_upoly_from_affine(ctx, morph->inv->row[1 + i],
+					morph->inv->row[0][0], morph->inv->n_col);
+	if (morph->inv->n_row != morph->inv->n_col)
+		for (i = 0; i < qp->div->n_row; ++i)
+			subs[morph->inv->n_row - 1 + i] =
+			    isl_upoly_var_pow(ctx, morph->inv->n_col - 1 + i, 1);
+
+	qp->upoly = isl_upoly_subs(qp->upoly, 0, n_sub, subs);
+
+	for (i = 0; i < n_sub; ++i)
+		isl_upoly_free(subs[i]);
+	free(subs);
+
+	diag = isl_mat_diag(ctx, 1, morph->inv->row[0][0]);
+	mat = isl_mat_diagonal(diag, isl_mat_copy(morph->inv));
+	diag = isl_mat_diag(ctx, qp->div->n_row, morph->inv->row[0][0]);
+	mat = isl_mat_diagonal(mat, diag);
+	qp->div = isl_mat_product(qp->div, mat);
+	isl_space_free(qp->dim);
+	qp->dim = isl_space_copy(morph->ran->dim);
+
+	if (!qp->upoly || !qp->div || !qp->dim)
+		goto error;
+
+	isl_morph_free(morph);
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+static int neg_entry(void **entry, void *user)
+{
+	isl_pw_qpolynomial **pwqp = (isl_pw_qpolynomial **)entry;
+
+	*pwqp = isl_pw_qpolynomial_neg(*pwqp);
+
+	return *pwqp ? 0 : -1;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_neg(
+	__isl_take isl_union_pw_qpolynomial *upwqp)
+{
+	upwqp = isl_union_pw_qpolynomial_cow(upwqp);
+	if (!upwqp)
+		return NULL;
+
+	if (isl_hash_table_foreach(upwqp->space->ctx, &upwqp->table,
+				   &neg_entry, NULL) < 0)
+		goto error;
+
+	return upwqp;
+error:
+	isl_union_pw_qpolynomial_free(upwqp);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul(
+	__isl_take isl_union_pw_qpolynomial *upwqp1,
+	__isl_take isl_union_pw_qpolynomial *upwqp2)
+{
+	return match_bin_op(upwqp1, upwqp2, &isl_pw_qpolynomial_mul);
+}
+
+/* Reorder the columns of the given div definitions according to the
+ * given reordering.
+ */
+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 dimension of "qp" according to the given reordering.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	r = isl_reordering_extend(r, qp->div->n_row);
+	if (!r)
+		goto error;
+
+	qp->div = reorder_divs(qp->div, isl_reordering_copy(r));
+	if (!qp->div)
+		goto error;
+
+	qp->upoly = reorder(qp->upoly, r->pos);
+	if (!qp->upoly)
+		goto error;
+
+	qp = isl_qpolynomial_reset_domain_space(qp, isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *model)
+{
+	if (!qp || !model)
+		goto error;
+
+	if (!isl_space_match(qp->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(qp->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					isl_qpolynomial_get_domain_space(qp));
+		qp = isl_qpolynomial_realign_domain(qp, exp);
+	}
+
+	isl_space_free(model);
+	return qp;
+error:
+	isl_space_free(model);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+struct isl_split_periods_data {
+	int max_periods;
+	isl_pw_qpolynomial *res;
+};
+
+/* Create a slice where the integer division "div" has the fixed value "v".
+ * In particular, if "div" refers to floor(f/m), then create a slice
+ *
+ *	m v <= f <= m v + (m - 1)
+ *
+ * or
+ *
+ *	f - m v >= 0
+ *	-f + m v + (m - 1) >= 0
+ */
+static __isl_give isl_set *set_div_slice(__isl_take isl_space *dim,
+	__isl_keep isl_qpolynomial *qp, int div, isl_int v)
+{
+	int total;
+	isl_basic_set *bset = NULL;
+	int k;
+
+	if (!dim || !qp)
+		goto error;
+
+	total = isl_space_dim(dim, isl_dim_all);
+	bset = isl_basic_set_alloc_space(isl_space_copy(dim), 0, 0, 2);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bset->ineq[k], qp->div->row[div] + 1, 1 + total);
+	isl_int_submul(bset->ineq[k][0], v, qp->div->row[div][0]);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_neg(bset->ineq[k], qp->div->row[div] + 1, 1 + total);
+	isl_int_addmul(bset->ineq[k][0], v, qp->div->row[div][0]);
+	isl_int_add(bset->ineq[k][0], bset->ineq[k][0], qp->div->row[div][0]);
+	isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+
+	isl_space_free(dim);
+	return isl_set_from_basic_set(bset);
+error:
+	isl_basic_set_free(bset);
+	isl_space_free(dim);
+	return NULL;
+}
+
+static int split_periods(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, void *user);
+
+/* Create a slice of the domain "set" such that integer division "div"
+ * has the fixed value "v" and add the results to data->res,
+ * replacing the integer division by "v" in "qp".
+ */
+static int set_div(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, int div, isl_int v,
+	struct isl_split_periods_data *data)
+{
+	int i;
+	int total;
+	isl_set *slice;
+	struct isl_upoly *cst;
+
+	slice = set_div_slice(isl_set_get_space(set), qp, div, v);
+	set = isl_set_intersect(set, slice);
+
+	if (!qp)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+
+	for (i = div + 1; i < qp->div->n_row; ++i) {
+		if (isl_int_is_zero(qp->div->row[i][2 + total + div]))
+			continue;
+		isl_int_addmul(qp->div->row[i][1],
+				qp->div->row[i][2 + total + div], v);
+		isl_int_set_si(qp->div->row[i][2 + total + div], 0);
+	}
+
+	cst = isl_upoly_rat_cst(qp->dim->ctx, v, qp->dim->ctx->one);
+	qp = substitute_div(qp, div, cst);
+
+	return split_periods(set, qp, data);
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return -1;
+}
+
+/* Split the domain "set" such that integer division "div"
+ * has a fixed value (ranging from "min" to "max") on each slice
+ * and add the results to data->res.
+ */
+static int split_div(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, int div, isl_int min, isl_int max,
+	struct isl_split_periods_data *data)
+{
+	for (; isl_int_le(min, max); isl_int_add_ui(min, min, 1)) {
+		isl_set *set_i = isl_set_copy(set);
+		isl_qpolynomial *qp_i = isl_qpolynomial_copy(qp);
+
+		if (set_div(set_i, qp_i, div, min, data) < 0)
+			goto error;
+	}
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return 0;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return -1;
+}
+
+/* If "qp" refers to any integer division
+ * that can only attain "max_periods" distinct values on "set"
+ * then split the domain along those distinct values.
+ * Add the results (or the original if no splitting occurs)
+ * to data->res.
+ */
+static int split_periods(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, void *user)
+{
+	int i;
+	isl_pw_qpolynomial *pwqp;
+	struct isl_split_periods_data *data;
+	isl_int min, max;
+	int total;
+	int r = 0;
+
+	data = (struct isl_split_periods_data *)user;
+
+	if (!set || !qp)
+		goto error;
+
+	if (qp->div->n_row == 0) {
+		pwqp = isl_pw_qpolynomial_alloc(set, qp);
+		data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp);
+		return 0;
+	}
+
+	isl_int_init(min);
+	isl_int_init(max);
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	for (i = 0; i < qp->div->n_row; ++i) {
+		enum isl_lp_result lp_res;
+
+		if (isl_seq_first_non_zero(qp->div->row[i] + 2 + total,
+						qp->div->n_row) != -1)
+			continue;
+
+		lp_res = isl_set_solve_lp(set, 0, qp->div->row[i] + 1,
+					  set->ctx->one, &min, NULL, NULL);
+		if (lp_res == isl_lp_error)
+			goto error2;
+		if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+			continue;
+		isl_int_fdiv_q(min, min, qp->div->row[i][0]);
+
+		lp_res = isl_set_solve_lp(set, 1, qp->div->row[i] + 1,
+					  set->ctx->one, &max, NULL, NULL);
+		if (lp_res == isl_lp_error)
+			goto error2;
+		if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+			continue;
+		isl_int_fdiv_q(max, max, qp->div->row[i][0]);
+
+		isl_int_sub(max, max, min);
+		if (isl_int_cmp_si(max, data->max_periods) < 0) {
+			isl_int_add(max, max, min);
+			break;
+		}
+	}
+
+	if (i < qp->div->n_row) {
+		r = split_div(set, qp, i, min, max, data);
+	} else {
+		pwqp = isl_pw_qpolynomial_alloc(set, qp);
+		data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp);
+	}
+
+	isl_int_clear(max);
+	isl_int_clear(min);
+
+	return r;
+error2:
+	isl_int_clear(max);
+	isl_int_clear(min);
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return -1;
+}
+
+/* If any quasi-polynomial in pwqp refers to any integer division
+ * that can only attain "max_periods" distinct values on its domain
+ * then split the domain along those distinct values.
+ */
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods(
+	__isl_take isl_pw_qpolynomial *pwqp, int max_periods)
+{
+	struct isl_split_periods_data data;
+
+	data.max_periods = max_periods;
+	data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp));
+
+	if (isl_pw_qpolynomial_foreach_piece(pwqp, &split_periods, &data) < 0)
+		goto error;
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return data.res;
+error:
+	isl_pw_qpolynomial_free(data.res);
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+/* Construct a piecewise quasipolynomial that is constant on the given
+ * domain.  In particular, it is
+ *	0	if cst == 0
+ *	1	if cst == 1
+ *  infinity	if cst == -1
+ */
+static __isl_give isl_pw_qpolynomial *constant_on_domain(
+	__isl_take isl_basic_set *bset, int cst)
+{
+	isl_space *dim;
+	isl_qpolynomial *qp;
+
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_params(bset);
+	dim = isl_basic_set_get_space(bset);
+	if (cst < 0)
+		qp = isl_qpolynomial_infty_on_domain(dim);
+	else if (cst == 0)
+		qp = isl_qpolynomial_zero_on_domain(dim);
+	else
+		qp = isl_qpolynomial_one_on_domain(dim);
+	return isl_pw_qpolynomial_alloc(isl_set_from_basic_set(bset), qp);
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ *
+ * If no factors can be found, simply call fn on the input.
+ * Otherwise, construct the factors based on the factorizer,
+ * call fn on each factor and compute the product.
+ */
+static __isl_give isl_pw_qpolynomial *compressed_multiplicative_call(
+	__isl_take isl_basic_set *bset,
+	__isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+	int i, n;
+	isl_space *dim;
+	isl_set *set;
+	isl_factorizer *f;
+	isl_qpolynomial *qp;
+	isl_pw_qpolynomial *pwqp;
+	unsigned nparam;
+	unsigned nvar;
+
+	f = isl_basic_set_factorizer(bset);
+	if (!f)
+		goto error;
+	if (f->n_group == 0) {
+		isl_factorizer_free(f);
+		return fn(bset);
+	}
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_domain(dim);
+	set = isl_set_universe(isl_space_copy(dim));
+	qp = isl_qpolynomial_one_on_domain(dim);
+	pwqp = isl_pw_qpolynomial_alloc(set, qp);
+
+	bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset);
+
+	for (i = 0, n = 0; i < f->n_group; ++i) {
+		isl_basic_set *bset_i;
+		isl_pw_qpolynomial *pwqp_i;
+
+		bset_i = isl_basic_set_copy(bset);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam + n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam, n);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set,
+			    n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n);
+
+		pwqp_i = fn(bset_i);
+		pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp_i);
+
+		n += f->len[i];
+	}
+
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+
+	return pwqp;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ * The function is assumed to evaluate to zero on empty domains,
+ * to one on zero-dimensional domains and to infinity on unbounded domains
+ * and will not be called explicitly on zero-dimensional or unbounded domains.
+ *
+ * We first check for some special cases and remove all equalities.
+ * Then we hand over control to compressed_multiplicative_call.
+ */
+__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call(
+	__isl_take isl_basic_set *bset,
+	__isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+	int bounded;
+	isl_morph *morph;
+	isl_pw_qpolynomial *pwqp;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return constant_on_domain(bset, 0);
+
+	if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+		return constant_on_domain(bset, 1);
+
+	bounded = isl_basic_set_is_bounded(bset);
+	if (bounded < 0)
+		goto error;
+	if (!bounded)
+		return constant_on_domain(bset, -1);
+
+	if (bset->n_eq == 0)
+		return compressed_multiplicative_call(bset, fn);
+
+	morph = isl_basic_set_full_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+	pwqp = compressed_multiplicative_call(bset, fn);
+
+	morph = isl_morph_dom_params(morph);
+	morph = isl_morph_ran_params(morph);
+	morph = isl_morph_inverse(morph);
+
+	pwqp = isl_pw_qpolynomial_morph_domain(pwqp, morph);
+
+	return pwqp;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Drop all floors in "qp", turning each integer division [a/m] into
+ * a rational division a/m.  If "down" is set, then the integer division
+ * is replaced by (a-(m-1))/m instead.
+ */
+static __isl_give isl_qpolynomial *qp_drop_floors(
+	__isl_take isl_qpolynomial *qp, int down)
+{
+	int i;
+	struct isl_upoly *s;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	for (i = qp->div->n_row - 1; i >= 0; --i) {
+		if (down) {
+			isl_int_sub(qp->div->row[i][1],
+				    qp->div->row[i][1], qp->div->row[i][0]);
+			isl_int_add_ui(qp->div->row[i][1],
+				       qp->div->row[i][1], 1);
+		}
+		s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1,
+					qp->div->row[i][0], qp->div->n_col - 1);
+		qp = substitute_div(qp, i, s);
+		if (!qp)
+			return NULL;
+	}
+
+	return qp;
+}
+
+/* Drop all floors in "pwqp", turning each integer division [a/m] into
+ * a rational division a/m.
+ */
+static __isl_give isl_pw_qpolynomial *pwqp_drop_floors(
+	__isl_take isl_pw_qpolynomial *pwqp)
+{
+	int i;
+
+	if (!pwqp)
+		return NULL;
+
+	if (isl_pw_qpolynomial_is_zero(pwqp))
+		return pwqp;
+
+	pwqp = isl_pw_qpolynomial_cow(pwqp);
+	if (!pwqp)
+		return NULL;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		pwqp->p[i].qp = qp_drop_floors(pwqp->p[i].qp, 0);
+		if (!pwqp->p[i].qp)
+			goto error;
+	}
+
+	return pwqp;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+/* Adjust all the integer divisions in "qp" such that they are at least
+ * one over the given orthant (identified by "signs").  This ensures
+ * that they will still be non-negative even after subtracting (m-1)/m.
+ *
+ * In particular, f is replaced by f' + v, changing f = [a/m]
+ * to f' = [(a - m v)/m].
+ * If the constant term k in a is smaller than m,
+ * the constant term of v is set to floor(k/m) - 1.
+ * For any other term, if the coefficient c and the variable x have
+ * the same sign, then no changes are needed.
+ * Otherwise, if the variable is positive (and c is negative),
+ * then the coefficient of x in v is set to floor(c/m).
+ * If the variable is negative (and c is positive),
+ * then the coefficient of x in v is set to ceil(c/m).
+ */
+static __isl_give isl_qpolynomial *make_divs_pos(__isl_take isl_qpolynomial *qp,
+	int *signs)
+{
+	int i, j;
+	int total;
+	isl_vec *v = NULL;
+	struct isl_upoly *s;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	v = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1);
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		isl_int *row = qp->div->row[i];
+		v = isl_vec_clr(v);
+		if (!v)
+			goto error;
+		if (isl_int_lt(row[1], row[0])) {
+			isl_int_fdiv_q(v->el[0], row[1], row[0]);
+			isl_int_sub_ui(v->el[0], v->el[0], 1);
+			isl_int_submul(row[1], row[0], v->el[0]);
+		}
+		for (j = 0; j < total; ++j) {
+			if (isl_int_sgn(row[2 + j]) * signs[j] >= 0)
+				continue;
+			if (signs[j] < 0)
+				isl_int_cdiv_q(v->el[1 + j], row[2 + j], row[0]);
+			else
+				isl_int_fdiv_q(v->el[1 + j], row[2 + j], row[0]);
+			isl_int_submul(row[2 + j], row[0], v->el[1 + j]);
+		}
+		for (j = 0; j < i; ++j) {
+			if (isl_int_sgn(row[2 + total + j]) >= 0)
+				continue;
+			isl_int_fdiv_q(v->el[1 + total + j],
+					row[2 + total + j], row[0]);
+			isl_int_submul(row[2 + total + j],
+					row[0], v->el[1 + total + j]);
+		}
+		for (j = i + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + i]))
+				continue;
+			isl_seq_combine(qp->div->row[j] + 1,
+				qp->div->ctx->one, qp->div->row[j] + 1,
+				qp->div->row[j][2 + total + i], v->el, v->size);
+		}
+		isl_int_set_si(v->el[1 + total + i], 1);
+		s = isl_upoly_from_affine(qp->dim->ctx, v->el,
+					qp->div->ctx->one, v->size);
+		qp->upoly = isl_upoly_subs(qp->upoly, total + i, 1, &s);
+		isl_upoly_free(s);
+		if (!qp->upoly)
+			goto error;
+	}
+
+	isl_vec_free(v);
+	return qp;
+error:
+	isl_vec_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+struct isl_to_poly_data {
+	int sign;
+	isl_pw_qpolynomial *res;
+	isl_qpolynomial *qp;
+};
+
+/* Appoximate data->qp by a polynomial on the orthant identified by "signs".
+ * We first make all integer divisions positive and then split the
+ * quasipolynomials into terms with sign data->sign (the direction
+ * of the requested approximation) and terms with the opposite sign.
+ * In the first set of terms, each integer division [a/m] is
+ * overapproximated by a/m, while in the second it is underapproximated
+ * by (a-(m-1))/m.
+ */
+static int to_polynomial_on_orthant(__isl_take isl_set *orthant, int *signs,
+	void *user)
+{
+	struct isl_to_poly_data *data = user;
+	isl_pw_qpolynomial *t;
+	isl_qpolynomial *qp, *up, *down;
+
+	qp = isl_qpolynomial_copy(data->qp);
+	qp = make_divs_pos(qp, signs);
+
+	up = isl_qpolynomial_terms_of_sign(qp, signs, data->sign);
+	up = qp_drop_floors(up, 0);
+	down = isl_qpolynomial_terms_of_sign(qp, signs, -data->sign);
+	down = qp_drop_floors(down, 1);
+
+	isl_qpolynomial_free(qp);
+	qp = isl_qpolynomial_add(up, down);
+
+	t = isl_pw_qpolynomial_alloc(orthant, qp);
+	data->res = isl_pw_qpolynomial_add_disjoint(data->res, t);
+
+	return 0;
+}
+
+/* Approximate each quasipolynomial by a polynomial.  If "sign" is positive,
+ * the polynomial will be an overapproximation.  If "sign" is negative,
+ * it will be an underapproximation.  If "sign" is zero, the approximation
+ * will lie somewhere in between.
+ *
+ * In particular, is sign == 0, we simply drop the floors, turning
+ * the integer divisions into rational divisions.
+ * Otherwise, we split the domains into orthants, make all integer divisions
+ * positive and then approximate each [a/m] by either a/m or (a-(m-1))/m,
+ * depending on the requested sign and the sign of the term in which
+ * the integer division appears.
+ */
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial(
+	__isl_take isl_pw_qpolynomial *pwqp, int sign)
+{
+	int i;
+	struct isl_to_poly_data data;
+
+	if (sign == 0)
+		return pwqp_drop_floors(pwqp);
+
+	if (!pwqp)
+		return NULL;
+
+	data.sign = sign;
+	data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp));
+
+	for (i = 0; i < pwqp->n; ++i) {
+		if (pwqp->p[i].qp->div->n_row == 0) {
+			isl_pw_qpolynomial *t;
+			t = isl_pw_qpolynomial_alloc(
+					isl_set_copy(pwqp->p[i].set),
+					isl_qpolynomial_copy(pwqp->p[i].qp));
+			data.res = isl_pw_qpolynomial_add_disjoint(data.res, t);
+			continue;
+		}
+		data.qp = pwqp->p[i].qp;
+		if (isl_set_foreach_orthant(pwqp->p[i].set,
+					&to_polynomial_on_orthant, &data) < 0)
+			goto error;
+	}
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return data.res;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	isl_pw_qpolynomial_free(data.res);
+	return NULL;
+}
+
+static int poly_entry(void **entry, void *user)
+{
+	int *sign = user;
+	isl_pw_qpolynomial **pwqp = (isl_pw_qpolynomial **)entry;
+
+	*pwqp = isl_pw_qpolynomial_to_polynomial(*pwqp, *sign);
+
+	return *pwqp ? 0 : -1;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial(
+	__isl_take isl_union_pw_qpolynomial *upwqp, int sign)
+{
+	upwqp = isl_union_pw_qpolynomial_cow(upwqp);
+	if (!upwqp)
+		return NULL;
+
+	if (isl_hash_table_foreach(upwqp->space->ctx, &upwqp->table,
+				   &poly_entry, &sign) < 0)
+		goto error;
+
+	return upwqp;
+error:
+	isl_union_pw_qpolynomial_free(upwqp);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, k;
+	isl_space *dim;
+	isl_vec *aff = NULL;
+	isl_basic_map *bmap = NULL;
+	unsigned pos;
+	unsigned n_div;
+
+	if (!qp)
+		return NULL;
+	if (!isl_upoly_is_affine(qp->upoly))
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"input quasi-polynomial not affine", goto error);
+	aff = isl_qpolynomial_extract_affine(qp);
+	if (!aff)
+		goto error;
+	dim = isl_qpolynomial_get_space(qp);
+	pos = 1 + isl_space_offset(dim, isl_dim_out);
+	n_div = qp->div->n_row;
+	bmap = isl_basic_map_alloc_space(dim, n_div, 1, 2 * n_div);
+
+	for (i = 0; i < n_div; ++i) {
+		k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->div[k], qp->div->row[i], qp->div->n_col);
+		isl_int_set_si(bmap->div[k][qp->div->n_col], 0);
+		if (isl_basic_map_add_div_constraints(bmap, k) < 0)
+			goto error;
+	}
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_int_neg(bmap->eq[k][pos], aff->el[0]);
+	isl_seq_cpy(bmap->eq[k], aff->el + 1, pos);
+	isl_seq_cpy(bmap->eq[k] + pos + 1, aff->el + 1 + pos, n_div);
+
+	isl_vec_free(aff);
+	isl_qpolynomial_free(qp);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_vec_free(aff);
+	isl_qpolynomial_free(qp);
+	isl_basic_map_free(bmap);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_polynomial_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_polynomial_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_polynomial_private.h (added)
+++ polly/trunk/lib/External/isl/isl_polynomial_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,253 @@
+#include <stdio.h>
+#include <isl_int.h>
+#include <isl/map.h>
+#include <isl/mat.h>
+#include <isl_morph.h>
+#include <isl/polynomial.h>
+#include <isl_reordering.h>
+
+struct isl_upoly {
+	int ref;
+	struct isl_ctx *ctx;
+
+	int var;
+};
+
+struct isl_upoly_cst {
+	struct isl_upoly up;
+	isl_int n;
+	isl_int d;
+};
+
+struct isl_upoly_rec {
+	struct isl_upoly up;
+	int n;
+
+	size_t size;
+	struct isl_upoly *p[];
+};
+
+/* dim represents the domain space.
+ */
+struct isl_qpolynomial {
+	int ref;
+
+	isl_space *dim;
+	struct isl_mat *div;
+	struct isl_upoly *upoly;
+};
+
+struct isl_term {
+	int ref;
+
+	isl_int n;
+	isl_int d;
+
+	isl_space *dim;
+	struct isl_mat *div;
+
+	int pow[1];
+};
+
+struct isl_pw_qpolynomial_piece {
+	struct isl_set *set;
+	struct isl_qpolynomial *qp;
+};
+
+struct isl_pw_qpolynomial {
+	int ref;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_qpolynomial_piece p[1];
+};
+
+/* dim represents the domain space.
+ */
+struct isl_qpolynomial_fold {
+	int ref;
+
+	enum isl_fold type;
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_qpolynomial *qp[1];
+};
+
+struct isl_pw_qpolynomial_fold_piece {
+	struct isl_set *set;
+	struct isl_qpolynomial_fold *fold;
+};
+
+struct isl_pw_qpolynomial_fold {
+	int ref;
+
+	enum isl_fold type;
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_qpolynomial_fold_piece p[1];
+};
+
+void isl_term_get_num(__isl_keep isl_term *term, isl_int *n);
+
+__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx);
+__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up);
+void isl_upoly_free(__isl_take struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2);
+
+int isl_upoly_is_cst(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_zero(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_one(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_negone(__isl_keep struct isl_upoly *up);
+__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up);
+__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up);
+
+__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2);
+__isl_give struct isl_upoly *isl_upoly_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim,
+	unsigned n_div, __isl_take struct isl_upoly *up);
+__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain(__isl_take isl_space *dim,
+	isl_int v);
+__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain(
+	__isl_take isl_space *space, const isl_int n, const isl_int d);
+__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain(__isl_take isl_space *dim,
+	int pos, int power);
+int isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp);
+int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp);
+int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp,
+	isl_int *n, isl_int *d);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2);
+
+int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly);
+__isl_give isl_qpolynomial *isl_qpolynomial_coeff(
+	__isl_keep isl_qpolynomial *poly,
+	enum isl_dim_type type, unsigned pos, int deg);
+
+__isl_give isl_vec *isl_qpolynomial_extract_affine(
+	__isl_keep isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim,
+	isl_int *f, isl_int denom);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_cow(
+	__isl_take isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_piece(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	__isl_take isl_set *set, __isl_take isl_qpolynomial *qp);
+int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_out(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_val *isl_qpolynomial_opt_on_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max);
+
+enum isl_fold isl_fold_type_negate(enum isl_fold type);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
+	__isl_take isl_qpolynomial_fold *fold);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
+	__isl_keep isl_qpolynomial_fold *fold);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_cow(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
+	__isl_keep isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2);
+__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);
+
+__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max);
+
+int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_morph_domain(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_morph *morph);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_morph_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_morph *morph);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_space *dim);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_realign_domain(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_reordering *r);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_realign_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_reordering *r);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_space(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *space);
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_space_and_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *space,
+	__isl_take isl_space *domain);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim);
+__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_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_space *dim);
+
+void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d);
+__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v);
+__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul_isl_int(
+	__isl_take isl_pw_qpolynomial *pwqp, isl_int v);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_pw_qpolynomial_fold *pwf, isl_int v);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul_isl_int(
+	__isl_take isl_union_pw_qpolynomial *upwqp, isl_int v);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, isl_int v);

Added: polly/trunk/lib/External/isl/isl_power_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_power_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_power_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_power_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,81 @@
+#include <isl_val_private.h>
+
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+
+/* Compute the given non-zero power of "map" and return the result.
+ * If the exponent "exp" is negative, then the -exp th power of the inverse
+ * relation is computed.
+ */
+__isl_give TYPE *FN(TYPE,fixed_power)(__isl_take TYPE *map, isl_int exp)
+{
+	isl_ctx *ctx;
+	TYPE *res = NULL;
+	isl_int r;
+
+	if (!map)
+		return NULL;
+
+	ctx = FN(TYPE,get_ctx)(map);
+	if (isl_int_is_zero(exp))
+		isl_die(ctx, isl_error_invalid,
+			"expecting non-zero exponent", goto error);
+
+	if (isl_int_is_neg(exp)) {
+		isl_int_neg(exp, exp);
+		map = FN(TYPE,reverse)(map);
+		return FN(TYPE,fixed_power)(map, exp);
+	}
+
+	isl_int_init(r);
+	for (;;) {
+		isl_int_fdiv_r(r, exp, ctx->two);
+
+		if (!isl_int_is_zero(r)) {
+			if (!res)
+				res = FN(TYPE,copy)(map);
+			else {
+				res = FN(TYPE,apply_range)(res,
+							  FN(TYPE,copy)(map));
+				res = FN(TYPE,coalesce)(res);
+			}
+			if (!res)
+				break;
+		}
+
+		isl_int_fdiv_q(exp, exp, ctx->two);
+		if (isl_int_is_zero(exp))
+			break;
+
+		map = FN(TYPE,apply_range)(map, FN(TYPE,copy)(map));
+		map = FN(TYPE,coalesce)(map);
+	}
+	isl_int_clear(r);
+
+	FN(TYPE,free)(map);
+	return res;
+error:
+	FN(TYPE,free)(map);
+	return NULL;
+}
+
+/* Compute the given non-zero power of "map" and return the result.
+ * If the exponent "exp" is negative, then the -exp th power of the inverse
+ * relation is computed.
+ */
+__isl_give TYPE *FN(TYPE,fixed_power_val)(__isl_take TYPE *map,
+	__isl_take isl_val *exp)
+{
+	if (!map || !exp)
+		goto error;
+	if (!isl_val_is_int(exp))
+		isl_die(FN(TYPE,get_ctx)(map), isl_error_invalid,
+			"expecting integer exponent", goto error);
+	map = FN(TYPE,fixed_power)(map, exp->n);
+	isl_val_free(exp);
+	return map;
+error:
+	FN(TYPE,free)(map);
+	isl_val_free(exp);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_printer.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_printer.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_printer.c (added)
+++ polly/trunk/lib/External/isl/isl_printer.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,449 @@
+#include <string.h>
+#include <isl_int.h>
+#include <isl_printer_private.h>
+
+static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
+{
+	fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
+				    p->indent, "", p->prefix ? p->prefix : "");
+	return p;
+}
+
+static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
+{
+	fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
+	return p;
+}
+
+static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
+{
+	fflush(p->file);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	fprintf(p->file, "%s", s);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	fprintf(p->file, "%g", d);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
+{
+	fprintf(p->file, "%d", i);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
+{
+	isl_int_print(p->file, i, p->width);
+	return p;
+}
+
+static int grow_buf(__isl_keep isl_printer *p, int extra)
+{
+	int new_size;
+	char *new_buf;
+
+	if (p->buf_size == 0)
+		return -1;
+
+	new_size = ((p->buf_n + extra + 1) * 3) / 2;
+	new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
+	if (!new_buf) {
+		p->buf_size = 0;
+		return -1;
+	}
+	p->buf = new_buf;
+	p->buf_size = new_size;
+
+	return 0;
+}
+
+static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
+	const char *s, int len)
+{
+	if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
+		goto error;
+	memcpy(p->buf + p->buf_n, s, len);
+	p->buf_n += len;
+
+	p->buf[p->buf_n] = '\0';
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	int i;
+
+	if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
+		goto error;
+	for (i = 0; i < indent; ++i)
+		p->buf[p->buf_n++] = ' ';
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
+{
+	if (p->indent_prefix)
+		p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
+	p = str_print_indent(p, p->indent);
+	if (p->prefix)
+		p = str_print(p, p->prefix, strlen(p->prefix));
+	return p;
+}
+
+static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
+{
+	if (p->suffix)
+		p = str_print(p, p->suffix, strlen(p->suffix));
+	p = str_print(p, "\n", strlen("\n"));
+	return p;
+}
+
+static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
+{
+	p->buf_n = 0;
+	return p;
+}
+
+static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	return str_print(p, s, strlen(s));
+}
+
+static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	int left = p->buf_size - p->buf_n;
+	int need = snprintf(p->buf + p->buf_n, left, "%g", d);
+	if (need >= left) {
+		if (grow_buf(p, need))
+			goto error;
+		left = p->buf_size - p->buf_n;
+		need = snprintf(p->buf + p->buf_n, left, "%g", d);
+	}
+	p->buf_n += need;
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
+{
+	int left = p->buf_size - p->buf_n;
+	int need = snprintf(p->buf + p->buf_n, left, "%d", i);
+	if (need >= left) {
+		if (grow_buf(p, need))
+			goto error;
+		left = p->buf_size - p->buf_n;
+		need = snprintf(p->buf + p->buf_n, left, "%d", i);
+	}
+	p->buf_n += need;
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
+	isl_int i)
+{
+	char *s;
+	int len;
+
+	s = isl_int_get_str(i);
+	len = strlen(s);
+	if (len < p->width)
+		p = str_print_indent(p, p->width - len);
+	p = str_print(p, s, len);
+	isl_int_free_str(s);
+	return p;
+}
+
+struct isl_printer_ops {
+	__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
+	__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
+	__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
+		double d);
+	__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
+	__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
+						isl_int i);
+	__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
+						const char *s);
+	__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
+};
+
+static struct isl_printer_ops file_ops = {
+	file_start_line,
+	file_end_line,
+	file_print_double,
+	file_print_int,
+	file_print_isl_int,
+	file_print_str,
+	file_flush
+};
+
+static struct isl_printer_ops str_ops = {
+	str_start_line,
+	str_end_line,
+	str_print_double,
+	str_print_int,
+	str_print_isl_int,
+	str_print_str,
+	str_flush
+};
+
+__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
+{
+	struct isl_printer *p = isl_alloc_type(ctx, struct isl_printer);
+	if (!p)
+		return NULL;
+	p->ctx = ctx;
+	isl_ctx_ref(p->ctx);
+	p->ops = &file_ops;
+	p->file = file;
+	p->buf = NULL;
+	p->buf_n = 0;
+	p->buf_size = 0;
+	p->indent = 0;
+	p->output_format = ISL_FORMAT_ISL;
+	p->indent_prefix = NULL;
+	p->prefix = NULL;
+	p->suffix = NULL;
+	p->width = 0;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
+{
+	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
+	if (!p)
+		return NULL;
+	p->ctx = ctx;
+	isl_ctx_ref(p->ctx);
+	p->ops = &str_ops;
+	p->file = NULL;
+	p->buf = isl_alloc_array(ctx, char, 256);
+	if (!p->buf)
+		goto error;
+	p->buf_n = 0;
+	p->buf[0] = '\0';
+	p->buf_size = 256;
+	p->indent = 0;
+	p->output_format = ISL_FORMAT_ISL;
+	p->indent_prefix = NULL;
+	p->prefix = NULL;
+	p->suffix = NULL;
+	p->width = 0;
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+	free(p->buf);
+	free(p->indent_prefix);
+	free(p->prefix);
+	free(p->suffix);
+	isl_ctx_deref(p->ctx);
+	free(p);
+
+	return NULL;
+}
+
+isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
+{
+	return printer ? printer->ctx : NULL;
+}
+
+FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
+{
+	if (!printer)
+		return NULL;
+	if (!printer->file)
+		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
+			"not a file printer", return NULL);
+	return printer->file;
+}
+
+__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
+	int width)
+{
+	if (!p)
+		return NULL;
+
+	p->width = width;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	if (!p)
+		return NULL;
+
+	p->indent = indent;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	if (!p)
+		return NULL;
+
+	p->indent += indent;
+	if (p->indent < 0)
+		p->indent = 0;
+
+	return p;
+}
+
+/* Replace the indent prefix of "p" by "prefix".
+ */
+__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
+	const char *prefix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->indent_prefix);
+	p->indent_prefix = prefix ? strdup(prefix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
+	const char *prefix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->prefix);
+	p->prefix = prefix ? strdup(prefix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
+	const char *suffix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->suffix);
+	p->suffix = suffix ? strdup(suffix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
+	int output_format)
+{
+	if (!p)
+		return NULL;
+
+	p->output_format = output_format;
+
+	return p;
+}
+
+int isl_printer_get_output_format(__isl_keep isl_printer *p)
+{
+	if (!p)
+		return -1;
+	return p->output_format;
+}
+
+__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	if (!p)
+		return NULL;
+	if (!s)
+		return isl_printer_free(p);
+
+	return p->ops->print_str(p, s);
+}
+
+__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->print_double(p, d);
+}
+
+__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->print_int(p, i);
+}
+
+__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
+	isl_int i)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->print_isl_int(p, i);
+}
+
+__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->start_line(p);
+}
+
+__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->end_line(p);
+}
+
+char *isl_printer_get_str(__isl_keep isl_printer *printer)
+{
+	if (!printer || !printer->buf)
+		return NULL;
+	return strdup(printer->buf);
+}
+
+__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->flush(p);
+}

Added: polly/trunk/lib/External/isl/isl_printer_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_printer_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_printer_private.h (added)
+++ polly/trunk/lib/External/isl/isl_printer_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,18 @@
+#include <isl/printer.h>
+
+struct isl_printer_ops;
+
+struct isl_printer {
+	struct isl_ctx	*ctx;
+	struct isl_printer_ops *ops;
+	FILE        	*file;
+	int		buf_n;
+	int		buf_size;
+	char		*buf;
+	int		indent;
+	int		output_format;
+	char		*indent_prefix;
+	char		*prefix;
+	char		*suffix;
+	int		width;
+};

Added: polly/trunk/lib/External/isl/isl_pw_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_pw_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_pw_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_pw_templ.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,2100 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2011      Sven Verdoolaege
+ * 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/aff.h>
+#include <isl_val_private.h>
+
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim,
+	enum isl_fold type, int n)
+#else
+__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n)
+#endif
+{
+	isl_ctx *ctx;
+	struct PW *pw;
+
+	if (!dim)
+		return NULL;
+	ctx = isl_space_get_ctx(dim);
+	isl_assert(ctx, n >= 0, goto error);
+	pw = isl_alloc(ctx, struct PW,
+			sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
+	if (!pw)
+		goto error;
+
+	pw->ref = 1;
+#ifdef HAS_TYPE
+	pw->type = type;
+#endif
+	pw->size = n;
+	pw->n = 0;
+	pw->dim = dim;
+	return pw;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
+{
+	return FN(PW,alloc_size)(dim, type, 0);
+}
+#else
+__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim)
+{
+	return FN(PW,alloc_size)(dim, 0);
+}
+#endif
+
+__isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
+	__isl_take isl_set *set, __isl_take EL *el)
+{
+	isl_ctx *ctx;
+	isl_space *el_dim = NULL;
+
+	if (!pw || !set || !el)
+		goto error;
+
+	if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
+		isl_set_free(set);
+		FN(EL,free)(el);
+		return pw;
+	}
+
+	ctx = isl_set_get_ctx(set);
+#ifdef HAS_TYPE
+	if (pw->type != el->type)
+		isl_die(ctx, isl_error_invalid, "fold types don't match",
+			goto error);
+#endif
+	el_dim = FN(EL,get_space(el));
+	isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
+	isl_assert(ctx, pw->n < pw->size, goto error);
+
+	pw->p[pw->n].set = set;
+	pw->p[pw->n].FIELD = el;
+	pw->n++;
+	
+	isl_space_free(el_dim);
+	return pw;
+error:
+	isl_space_free(el_dim);
+	FN(PW,free)(pw);
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,alloc)(enum isl_fold type,
+	__isl_take isl_set *set, __isl_take EL *el)
+#else
+__isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el)
+#endif
+{
+	PW *pw;
+
+	if (!set || !el)
+		goto error;
+
+#ifdef HAS_TYPE
+	pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1);
+#else
+	pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1);
+#endif
+
+	return FN(PW,add_piece)(pw, set, el);
+error:
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
+{
+	int i;
+	PW *dup;
+
+	if (!pw)
+		return NULL;
+
+#ifdef HAS_TYPE
+	dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n);
+#else
+	dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n);
+#endif
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i)
+		dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
+					    FN(EL,copy)(pw->p[i].FIELD));
+
+	return dup;
+}
+
+__isl_give PW *FN(PW,cow)(__isl_take PW *pw)
+{
+	if (!pw)
+		return NULL;
+
+	if (pw->ref == 1)
+		return pw;
+	pw->ref--;
+	return FN(PW,dup)(pw);
+}
+
+__isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
+{
+	if (!pw)
+		return NULL;
+
+	pw->ref++;
+	return pw;
+}
+
+__isl_null PW *FN(PW,free)(__isl_take PW *pw)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+	if (--pw->ref > 0)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+	}
+	isl_space_free(pw->dim);
+	free(pw);
+
+	return NULL;
+}
+
+const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned pos)
+{
+	return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
+}
+
+int FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type, unsigned pos)
+{
+	return pw ? isl_space_has_dim_id(pw->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned pos)
+{
+	return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
+}
+
+int FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_has_tuple_name(pw->dim, type) : -1;
+}
+
+const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
+}
+
+int FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_has_tuple_id(pw->dim, type) : -1;
+}
+
+__isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
+}
+
+int FN(PW,IS_ZERO)(__isl_keep PW *pw)
+{
+	if (!pw)
+		return -1;
+
+	return pw->n == 0;
+}
+
+#ifndef NO_REALIGN
+__isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
+	__isl_take isl_reordering *exp)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw || !exp)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_realign(pw->p[i].set,
+						    isl_reordering_copy(exp));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
+						    isl_reordering_copy(exp));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	pw = FN(PW,reset_domain_space)(pw, isl_space_copy(exp->dim));
+
+	isl_reordering_free(exp);
+	return pw;
+error:
+	isl_reordering_free(exp);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Align the parameters of "pw" to those of "model".
+ */
+__isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+
+	if (!pw || !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(pw->dim))
+		isl_die(ctx, isl_error_invalid,
+			"input has unnamed parameters", goto error);
+	if (!isl_space_match(pw->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(pw->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					FN(PW,get_domain_space)(pw));
+		pw = FN(PW,realign_domain)(pw, exp);
+	}
+
+	isl_space_free(model);
+	return pw;
+error:
+	isl_space_free(model);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
+{
+	isl_ctx *ctx;
+
+	if (!pw1 || !pw2)
+		goto error;
+	if (isl_space_match(pw1->dim, isl_dim_param, pw2->dim, isl_dim_param))
+		return fn(pw1, pw2);
+	ctx = FN(PW,get_ctx)(pw1);
+	if (!isl_space_has_named_params(pw1->dim) ||
+	    !isl_space_has_named_params(pw2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
+	pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
+	return fn(pw1, pw2);
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
+	__isl_take isl_set *set,
+	__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
+{
+	isl_ctx *ctx;
+
+	if (!pw || !set)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, set->dim, isl_dim_param))
+		return fn(pw, set);
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(set->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, isl_set_get_space(set));
+	set = isl_set_align_params(set, FN(PW,get_space)(pw));
+	return fn(pw, set);
+error:
+	FN(PW,free)(pw);
+	isl_set_free(set);
+	return NULL;
+}
+#endif
+
+static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
+	__isl_take PW *pw2)
+{
+	int i, j, n;
+	struct PW *res;
+	isl_ctx *ctx;
+	isl_set *set;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	ctx = isl_space_get_ctx(pw1->dim);
+#ifdef HAS_TYPE
+	if (pw1->type != pw2->type)
+		isl_die(ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+#endif
+	isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (FN(PW,IS_ZERO)(pw1)) {
+		FN(PW,free)(pw1);
+		return pw2;
+	}
+
+	if (FN(PW,IS_ZERO)(pw2)) {
+		FN(PW,free)(pw2);
+		return pw1;
+	}
+
+	n = (pw1->n + 1) * (pw2->n + 1);
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
+#endif
+
+	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;
+			EL *sum;
+			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;
+			}
+			set = isl_set_subtract(set,
+					isl_set_copy(pw2->p[j].set));
+
+			sum = FN(EL,add_on_domain)(common,
+						   FN(EL,copy)(pw1->p[i].FIELD),
+						   FN(EL,copy)(pw2->p[j].FIELD));
+
+			res = FN(PW,add_piece)(res, common, sum);
+		}
+		res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
+	}
+
+	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 = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
+	}
+
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+
+	return res;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+/* Private version of "union_add".  For isl_pw_qpolynomial and
+ * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
+ */
+static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,align_params_pw_pw_and)(pw1, pw2,
+						&FN(PW,union_add_aligned));
+}
+
+/* Make sure "pw" has room for at least "n" more pieces.
+ *
+ * If there is only one reference to pw, we extend it in place.
+ * Otherwise, we create a new PW and copy the pieces.
+ */
+static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
+{
+	int i;
+	isl_ctx *ctx;
+	PW *res;
+
+	if (!pw)
+		return NULL;
+	if (pw->n + n <= pw->size)
+		return pw;
+	ctx = FN(PW,get_ctx)(pw);
+	n += pw->n;
+	if (pw->ref == 1) {
+		res = isl_realloc(ctx, pw, struct PW,
+			    sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
+		if (!res)
+			return FN(PW,free)(pw);
+		res->size = n;
+		return res;
+	}
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
+#endif
+	if (!res)
+		return FN(PW,free)(pw);
+	for (i = 0; i < pw->n; ++i)
+		res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
+					    FN(EL,copy)(pw->p[i].FIELD));
+	FN(PW,free)(pw);
+	return res;
+}
+
+static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
+	__isl_take PW *pw2)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
+		return FN(PW,add_disjoint_aligned)(pw2, pw1);
+
+	ctx = isl_space_get_ctx(pw1->dim);
+#ifdef HAS_TYPE
+	if (pw1->type != pw2->type)
+		isl_die(ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+#endif
+	isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (FN(PW,IS_ZERO)(pw1)) {
+		FN(PW,free)(pw1);
+		return pw2;
+	}
+
+	if (FN(PW,IS_ZERO)(pw2)) {
+		FN(PW,free)(pw2);
+		return pw1;
+	}
+
+	pw1 = FN(PW,grow)(pw1, pw2->n);
+	if (!pw1)
+		goto error;
+
+	for (i = 0; i < pw2->n; ++i)
+		pw1 = FN(PW,add_piece)(pw1,
+				isl_set_copy(pw2->p[i].set),
+				FN(EL,copy)(pw2->p[i].FIELD));
+
+	FN(PW,free)(pw2);
+
+	return pw1;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,align_params_pw_pw_and)(pw1, pw2,
+						&FN(PW,add_disjoint_aligned));
+}
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
+	__isl_take PW *pw2, __isl_take isl_space *space,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+	__attribute__ ((unused));
+
+/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
+ * The result of "fn" (and therefore also of this function) lives in "space".
+ */
+static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
+	__isl_take PW *pw2, __isl_take isl_space *space,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	int i, j, n;
+	PW *res = NULL;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	n = pw1->n * pw2->n;
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(space), n);
+#endif
+
+	for (i = 0; i < pw1->n; ++i) {
+		for (j = 0; j < pw2->n; ++j) {
+			isl_set *common;
+			EL *res_ij;
+			int empty;
+
+			common = isl_set_intersect(
+					isl_set_copy(pw1->p[i].set),
+					isl_set_copy(pw2->p[j].set));
+			empty = isl_set_plain_is_empty(common);
+			if (empty < 0 || empty) {
+				isl_set_free(common);
+				if (empty < 0)
+					goto error;
+				continue;
+			}
+
+			res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
+				    FN(EL,copy)(pw2->p[j].FIELD));
+			res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
+
+			res = FN(PW,add_piece)(res, common, res_ij);
+		}
+	}
+
+	isl_space_free(space);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return res;
+error:
+	isl_space_free(space);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	FN(PW,free)(res);
+	return NULL;
+}
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+	__attribute__ ((unused));
+
+/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
+ * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
+ */
+static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	isl_space *space;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	space = isl_space_copy(pw1->dim);
+	return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+#ifndef NO_NEG
+__isl_give PW *FN(PW,neg)(__isl_take PW *pw)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (FN(PW,IS_ZERO)(pw))
+		return pw;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
+		if (!pw->p[i].FIELD)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+
+__isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,add)(pw1, FN(PW,neg)(pw2));
+}
+#endif
+
+#ifndef NO_EVAL
+__isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt)
+{
+	int i;
+	int found = 0;
+	isl_ctx *ctx;
+	isl_space *pnt_dim = NULL;
+	isl_val *v;
+
+	if (!pw || !pnt)
+		goto error;
+	ctx = isl_point_get_ctx(pnt);
+	pnt_dim = isl_point_get_space(pnt);
+	isl_assert(ctx, isl_space_is_domain_internal(pnt_dim, pw->dim),
+		    goto error);
+
+	for (i = 0; i < pw->n; ++i) {
+		found = isl_set_contains_point(pw->p[i].set, pnt);
+		if (found < 0)
+			goto error;
+		if (found)
+			break;
+	}
+	if (found)
+		v = FN(EL,eval)(FN(EL,copy)(pw->p[i].FIELD),
+					    isl_point_copy(pnt));
+	else
+		v = isl_val_zero(ctx);
+	FN(PW,free)(pw);
+	isl_space_free(pnt_dim);
+	isl_point_free(pnt);
+	return v;
+error:
+	FN(PW,free)(pw);
+	isl_space_free(pnt_dim);
+	isl_point_free(pnt);
+	return NULL;
+}
+#endif
+
+/* Return the parameter domain of "pw".
+ */
+__isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
+{
+	return isl_set_params(FN(PW,domain)(pw));
+}
+
+__isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
+{
+	int i;
+	isl_set *dom;
+
+	if (!pw)
+		return NULL;
+
+	dom = isl_set_empty(FN(PW,get_domain_space)(pw));
+	for (i = 0; i < pw->n; ++i)
+		dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
+
+	FN(PW,free)(pw);
+
+	return dom;
+}
+
+/* Exploit the equalities in the domain of piece "i" of "pw"
+ * to simplify the associated function.
+ * If the domain of piece "i" is empty, then remove it entirely,
+ * replacing it with the final piece.
+ */
+static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
+	int i)
+{
+	isl_basic_set *aff;
+	int empty = isl_set_plain_is_empty(pw->p[i].set);
+
+	if (empty < 0)
+		return -1;
+	if (empty) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+		if (i != pw->n - 1)
+			pw->p[i] = pw->p[pw->n - 1];
+		pw->n--;
+
+		return 0;
+	}
+
+	aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
+	pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
+	if (!pw->p[i].FIELD)
+		return -1;
+
+	return 0;
+}
+
+/* Convert a piecewise expression defined over a parameter domain
+ * into one that is defined over a zero-dimensional set.
+ */
+__isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
+{
+	isl_space *space;
+
+	if (!pw)
+		return NULL;
+	if (!isl_space_is_set(pw->dim))
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"not living in a set space", return FN(PW,free)(pw));
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_from_range(space);
+	pw = FN(PW,reset_space)(pw, space);
+
+	return pw;
+}
+
+/* Fix the value of the given parameter or domain dimension of "pw"
+ * to be equal to "value".
+ */
+__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
+	unsigned pos, int value)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"cannot fix output dimension", return FN(PW,free)(pw));
+
+	if (pw->n == 0)
+		return pw;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return FN(PW,free)(pw);
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+
+/* Restrict the domain of "pw" by combining each cell
+ * with "set" through a call to "fn", where "fn" may be
+ * isl_set_intersect or isl_set_intersect_params.
+ */
+static __isl_give PW *FN(PW,intersect_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set,
+	__isl_give isl_set *(*fn)(__isl_take isl_set *set1,
+				    __isl_take isl_set *set2))
+{
+	int i;
+
+	if (!pw || !set)
+		goto error;
+
+	if (pw->n == 0) {
+		isl_set_free(set);
+		return pw;
+	}
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			goto error;
+	}
+	
+	isl_set_free(set);
+	return pw;
+error:
+	isl_set_free(set);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,intersect_aligned)(pw, set, &isl_set_intersect);
+}
+
+__isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+					&FN(PW,intersect_domain_aligned));
+}
+
+static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,intersect_aligned)(pw, set, &isl_set_intersect_params);
+}
+
+/* Intersect the domain of "pw" with the parameter domain "context".
+ */
+__isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+					&FN(PW,intersect_params_aligned));
+}
+
+/* Compute the gist of "pw" with respect to the domain constraints
+ * of "context" for the case where the domain of the last element
+ * of "pw" is equal to "context".
+ * Call "fn_el" to compute the gist of this element, replace
+ * its domain by the universe and drop all other elements
+ * as their domains are necessarily disjoint from "context".
+ */
+static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
+	__isl_take isl_set *context,
+	__isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
+{
+	int i;
+	isl_space *space;
+
+	for (i = 0; i < pw->n - 1; ++i) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+	}
+	pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
+	pw->p[0].set = pw->p[pw->n - 1].set;
+	pw->n = 1;
+
+	space = isl_set_get_space(context);
+	pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
+	context = isl_set_universe(space);
+	isl_set_free(pw->p[0].set);
+	pw->p[0].set = context;
+
+	if (!pw->p[0].FIELD || !pw->p[0].set)
+		return FN(PW,free)(pw);
+
+	return pw;
+}
+
+/* Compute the gist of "pw" with respect to the domain constraints
+ * of "context".  Call "fn_el" to compute the gist of the elements
+ * and "fn_dom" to compute the gist of the domains.
+ *
+ * If the piecewise expression is empty or the context is the universe,
+ * then nothing can be simplified.
+ */
+static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *context,
+	__isl_give EL *(*fn_el)(__isl_take EL *el,
+				    __isl_take isl_set *set),
+	__isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
+				    __isl_take isl_basic_set *bset))
+{
+	int i;
+	int is_universe;
+	isl_basic_set *hull = NULL;
+
+	if (!pw || !context)
+		goto error;
+
+	if (pw->n == 0) {
+		isl_set_free(context);
+		return pw;
+	}
+
+	is_universe = isl_set_plain_is_universe(context);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_set_free(context);
+		return pw;
+	}
+
+	if (!isl_space_match(pw->dim, isl_dim_param,
+				context->dim, isl_dim_param)) {
+		pw = FN(PW,align_params)(pw, isl_set_get_space(context));
+		context = isl_set_align_params(context, FN(PW,get_space)(pw));
+	}
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	if (pw->n == 1) {
+		int equal;
+
+		equal = isl_set_plain_is_equal(pw->p[0].set, context);
+		if (equal < 0)
+			goto error;
+		if (equal)
+			return FN(PW,gist_last)(pw, context, fn_el);
+	}
+
+	context = isl_set_compute_divs(context);
+	hull = isl_set_simple_hull(isl_set_copy(context));
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		isl_set *set_i;
+		int empty;
+
+		if (i == pw->n - 1) {
+			int equal;
+			equal = isl_set_plain_is_equal(pw->p[i].set, context);
+			if (equal < 0)
+				goto error;
+			if (equal) {
+				isl_basic_set_free(hull);
+				return FN(PW,gist_last)(pw, context, fn_el);
+			}
+		}
+		set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
+						 isl_set_copy(context));
+		empty = isl_set_plain_is_empty(set_i);
+		pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
+		pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
+		if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
+			goto error;
+		if (empty) {
+			isl_set_free(pw->p[i].set);
+			FN(EL,free)(pw->p[i].FIELD);
+			if (i != pw->n - 1)
+				pw->p[i] = pw->p[pw->n - 1];
+			pw->n--;
+		}
+	}
+
+	isl_basic_set_free(hull);
+	isl_set_free(context);
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	isl_basic_set_free(hull);
+	isl_set_free(context);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
+					&isl_set_gist_basic_set);
+}
+
+__isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+						&FN(PW,gist_domain_aligned));
+}
+
+static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
+					&isl_set_gist_params_basic_set);
+}
+
+__isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+						&FN(PW,gist_params_aligned));
+}
+
+__isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
+{
+	int i, j;
+
+	if (!pw)
+		return NULL;
+	if (pw->n == 0)
+		return pw;
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		for (j = i - 1; j >= 0; --j) {
+			if (!FN(EL,plain_is_equal)(pw->p[i].FIELD,
+							pw->p[j].FIELD))
+				continue;
+			pw->p[j].set = isl_set_union(pw->p[j].set,
+							pw->p[i].set);
+			FN(EL,free)(pw->p[i].FIELD);
+			if (i != pw->n - 1)
+				pw->p[i] = pw->p[pw->n - 1];
+			pw->n--;
+			break;
+		}
+		if (j >= 0)
+			continue;
+		pw->p[i].set = isl_set_coalesce(pw->p[i].set);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_get_ctx(pw->dim) : NULL;
+}
+
+#ifndef NO_INVOLVES_DIMS
+int FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return -1;
+	if (pw->n == 0 || n == 0)
+		return 0;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	for (i = 0; i < pw->n; ++i) {
+		int involves = FN(EL,involves_dims)(pw->p[i].FIELD,
+							type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+		involves = isl_set_involves_dims(pw->p[i].set,
+							set_type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+	return 0;
+}
+#endif
+
+__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
+							set_type, pos, s);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+#ifndef NO_DROP_DIMS
+__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+		if (type == isl_dim_out)
+			continue;
+		pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* This function is very similar to drop_dims.
+ * The only difference is that the cells may still involve
+ * the specified dimensions.  They are removed using
+ * isl_set_project_out instead of isl_set_drop.
+ */
+__isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_project_out(pw->p[i].set,
+							set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Project the domain of pw onto its parameter space.
+ */
+__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
+{
+	isl_space *space;
+	unsigned n;
+
+	n = FN(PW,dim)(pw, isl_dim_in);
+	pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
+	space = FN(PW,get_domain_space)(pw);
+	space = isl_space_params(space);
+	pw = FN(PW,reset_domain_space)(pw, space);
+	return pw;
+}
+#endif
+
+#ifndef NO_INSERT_DIMS
+__isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
+							    set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
+								type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+#endif
+
+__isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, isl_int v)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "pw"
+ * to be equal to "v".
+ */
+__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	if (!v)
+		return FN(PW,free)(pw);
+	if (!isl_val_is_int(v))
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"expecting integer value", goto error);
+
+	pw = FN(PW,fix_dim)(pw, type, pos, v->n);
+	isl_val_free(v);
+
+	return pw;
+error:
+	isl_val_free(v);
+	return FN(PW,free)(pw);
+}
+
+unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_dim(pw->dim, type) : 0;
+}
+
+__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+	if (n == 0)
+		return pw;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+#ifndef NO_OPT
+/* Compute the maximal value attained by the piecewise quasipolynomial
+ * on its domain or zero if the domain is empty.
+ * In the worst case, the domain is scanned completely,
+ * so the domain is assumed to be bounded.
+ */
+__isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
+{
+	int i;
+	isl_val *opt;
+
+	if (!pw)
+		return NULL;
+
+	if (pw->n == 0) {
+		opt = isl_val_zero(FN(PW,get_ctx)(pw));
+		FN(PW,free)(pw);
+		return opt;
+	}
+
+	opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
+					isl_set_copy(pw->p[0].set), max);
+	for (i = 1; i < pw->n; ++i) {
+		isl_val *opt_i;
+		opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
+						isl_set_copy(pw->p[i].set), max);
+		if (max)
+			opt = isl_val_max(opt, opt_i);
+		else
+			opt = isl_val_min(opt, opt_i);
+	}
+
+	FN(PW,free)(pw);
+	return opt;
+}
+
+__isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
+{
+	return FN(PW,opt)(pw, 1);
+}
+
+__isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
+{
+	return FN(PW,opt)(pw, 0);
+}
+#endif
+
+__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_copy(pw->dim) : NULL;
+}
+
+__isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "pw".
+ * Return -1 if no such dimension can be found.
+ */
+int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
+	enum isl_dim_type type, const char *name)
+{
+	if (!pw)
+		return -1;
+	return isl_space_find_dim_by_name(pw->dim, type, name);
+}
+
+#ifndef NO_RESET_DIM
+/* Reset the space of "pw".  Since we don't know if the elements
+ * represent the spaces themselves or their domains, we pass along
+ * both when we call their reset_space_and_domain.
+ */
+static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
+	__isl_take isl_space *space, __isl_take isl_space *domain)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw || !space || !domain)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_reset_space(pw->p[i].set,
+						 isl_space_copy(domain));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
+			      isl_space_copy(space), isl_space_copy(domain));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_space_free(domain);
+
+	isl_space_free(pw->dim);
+	pw->dim = space;
+
+	return pw;
+error:
+	isl_space_free(domain);
+	isl_space_free(space);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
+	__isl_take isl_space *domain)
+{
+	isl_space *space;
+
+	space = isl_space_extend_domain_with_range(isl_space_copy(domain),
+						   FN(PW,get_space)(pw));
+	return FN(PW,reset_space_and_domain)(pw, space, domain);
+}
+
+__isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
+{
+	isl_space *domain;
+
+	domain = isl_space_domain(isl_space_copy(dim));
+	return FN(PW,reset_space_and_domain)(pw, dim, domain);
+}
+
+__isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
+	__isl_take isl_id *id)
+{
+	isl_space *space;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_set_tuple_id(space, type, id);
+
+	return FN(PW,reset_space)(pw, space);
+error:
+	isl_id_free(id);
+	return FN(PW,free)(pw);
+}
+
+/* Drop the id on the specified tuple.
+ */
+__isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!pw)
+		return NULL;
+	if (!FN(PW,has_tuple_id)(pw, type))
+		return pw;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_reset_tuple_id(space, type);
+
+	return FN(PW,reset_space)(pw, space);
+}
+
+__isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+	pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
+	return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
+error:
+	isl_id_free(id);
+	return FN(PW,free)(pw);
+}
+#endif
+
+int FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	if (!pw1 || !pw2)
+		return -1;
+
+	return isl_space_is_equal(pw1->dim, pw2->dim);
+}
+
+#ifndef NO_MORPH
+__isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
+	__isl_take isl_morph *morph)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!pw || !morph)
+		goto error;
+
+	ctx = isl_space_get_ctx(pw->dim);
+	isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
+		goto error);
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+	pw->dim = isl_space_extend_domain_with_range(
+			isl_space_copy(morph->ran->dim), pw->dim);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
+						isl_morph_copy(morph));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	isl_morph_free(morph);
+	return NULL;
+}
+#endif
+
+int FN(PW,n_piece)(__isl_keep PW *pw)
+{
+	return pw ? pw->n : 0;
+}
+
+int FN(PW,foreach_piece)(__isl_keep PW *pw,
+	int (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
+	void *user)
+{
+	int i;
+
+	if (!pw)
+		return -1;
+
+	for (i = 0; i < pw->n; ++i)
+		if (fn(isl_set_copy(pw->p[i].set),
+				FN(EL,copy)(pw->p[i].FIELD), user) < 0)
+			return -1;
+
+	return 0;
+}
+
+#ifndef NO_LIFT
+static int any_divs(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i)
+		if (set->p[i]->n_div > 0)
+			return 1;
+
+	return 0;
+}
+
+static int foreach_lifted_subset(__isl_take isl_set *set, __isl_take EL *el,
+	int (*fn)(__isl_take isl_set *set, __isl_take EL *el,
+		    void *user), void *user)
+{
+	int i;
+
+	if (!set || !el)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		isl_set *lift;
+		EL *copy;
+
+		lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
+		lift = isl_set_lift(lift);
+
+		copy = FN(EL,copy)(el);
+		copy = FN(EL,lift)(copy, isl_set_get_space(lift));
+
+		if (fn(lift, copy, user) < 0)
+			goto error;
+	}
+
+	isl_set_free(set);
+	FN(EL,free)(el);
+
+	return 0;
+error:
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return -1;
+}
+
+int FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
+	int (*fn)(__isl_take isl_set *set, __isl_take EL *el,
+		    void *user), void *user)
+{
+	int i;
+
+	if (!pw)
+		return -1;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_set *set;
+		EL *el;
+
+		set = isl_set_copy(pw->p[i].set);
+		el = FN(EL,copy)(pw->p[i].FIELD);
+		if (!any_divs(set)) {
+			if (fn(set, el, user) < 0)
+				return -1;
+			continue;
+		}
+		if (foreach_lifted_subset(set, el, fn, user) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+#endif
+
+#ifndef NO_MOVE_DIMS
+__isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
+					dst_type, dst_pos, src_type, src_pos, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	if (dst_type == isl_dim_in)
+		dst_type = isl_dim_set;
+	if (src_type == isl_dim_in)
+		src_type = isl_dim_set;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_move_dims(pw->p[i].set,
+						dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+#endif
+
+__isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
+{
+	int i;
+
+	if (isl_int_is_one(v))
+		return pw;
+	if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
+		PW *zero;
+		isl_space *dim = FN(PW,get_space)(pw);
+#ifdef HAS_TYPE
+		zero = FN(PW,ZERO)(dim, pw->type);
+#else
+		zero = FN(PW,ZERO)(dim);
+#endif
+		FN(PW,free)(pw);
+		return zero;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	if (pw->n == 0)
+		return pw;
+
+#ifdef HAS_TYPE
+	if (isl_int_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Multiply the pieces of "pw" by "v" and return the result.
+ */
+__isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!pw || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return pw;
+	}
+	if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
+		PW *zero;
+		isl_space *space = FN(PW,get_space)(pw);
+#ifdef HAS_TYPE
+		zero = FN(PW,ZERO)(space, pw->type);
+#else
+		zero = FN(PW,ZERO)(space);
+#endif
+		FN(PW,free)(pw);
+		isl_val_free(v);
+		return zero;
+	}
+	if (pw->n == 0) {
+		isl_val_free(v);
+		return pw;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
+						    isl_val_copy(v));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pw;
+error:
+	isl_val_free(v);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Divide the pieces of "pw" by "v" and return the result.
+ */
+__isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!pw || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return pw;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	if (pw->n == 0) {
+		isl_val_free(v);
+		return pw;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
+						    isl_val_copy(v));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pw;
+error:
+	isl_val_free(v);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
+{
+	return FN(PW,mul_isl_int)(pw, v);
+}
+
+static int FN(PW,qsort_set_cmp)(const void *p1, const void *p2)
+{
+	isl_set *set1 = *(isl_set * const *)p1;
+	isl_set *set2 = *(isl_set * const *)p2;
+
+	return isl_set_plain_cmp(set1, set2);
+}
+
+/* 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 PW *FN(PW,normalize)(__isl_take PW *pw)
+{
+	int i, j;
+	isl_set *set;
+
+	if (!pw)
+		return NULL;
+	for (i = 0; i < pw->n; ++i) {
+		set = isl_set_normalize(isl_set_copy(pw->p[i].set));
+		if (!set)
+			return FN(PW,free)(pw);
+		isl_set_free(pw->p[i].set);
+		pw->p[i].set = set;
+	}
+	qsort(pw->p, pw->n, sizeof(pw->p[0]), &FN(PW,qsort_set_cmp));
+	for (i = pw->n - 1; i >= 1; --i) {
+		if (!isl_set_plain_is_equal(pw->p[i - 1].set, pw->p[i].set))
+			continue;
+		if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
+			continue;
+		set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
+				    isl_set_copy(pw->p[i].set));
+		if (!set)
+			return FN(PW,free)(pw);
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+		isl_set_free(pw->p[i - 1].set);
+		pw->p[i - 1].set = set;
+		for (j = i + 1; j < pw->n; ++j)
+			pw->p[j - 1] = pw->p[j];
+		pw->n--;
+	}
+
+	return pw;
+}
+
+/* Is pw1 obviously equal to pw2?
+ * That is, do they have obviously identical cells and obviously identical
+ * elements on each cell?
+ */
+int FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	int i;
+	int equal;
+
+	if (!pw1 || !pw2)
+		return -1;
+
+	if (pw1 == pw2)
+		return 1;
+	if (!isl_space_is_equal(pw1->dim, pw2->dim))
+		return 0;
+
+	pw1 = FN(PW,copy)(pw1);
+	pw2 = FN(PW,copy)(pw2);
+	pw1 = FN(PW,normalize)(pw1);
+	pw2 = FN(PW,normalize)(pw2);
+	if (!pw1 || !pw2)
+		goto error;
+
+	equal = pw1->n == pw2->n;
+	for (i = 0; equal && i < pw1->n; ++i) {
+		equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
+		if (equal < 0)
+			goto error;
+		if (!equal)
+			break;
+		equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
+		if (equal < 0)
+			goto error;
+	}
+
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return equal;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return -1;
+}
+
+#ifndef NO_PULLBACK
+static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma,
+	__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
+{
+	isl_ctx *ctx;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+	if (!pw || !ma || !ma_space)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, ma_space, isl_dim_param)) {
+		isl_space_free(ma_space);
+		return fn(pw, ma);
+	}
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(ma_space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, ma_space);
+	ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
+	return fn(pw, ma);
+error:
+	isl_space_free(ma_space);
+	FN(PW,free)(pw);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma,
+	__isl_give PW *(*fn)(__isl_take PW *pw,
+		__isl_take isl_pw_multi_aff *ma))
+{
+	isl_ctx *ctx;
+	isl_space *pma_space;
+
+	pma_space = isl_pw_multi_aff_get_space(pma);
+	if (!pw || !pma || !pma_space)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, pma_space, isl_dim_param)) {
+		isl_space_free(pma_space);
+		return fn(pw, pma);
+	}
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(pma_space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, pma_space);
+	pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
+	return fn(pw, pma);
+error:
+	isl_space_free(pma_space);
+	FN(PW,free)(pw);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Compute the pullback of "pw" by the function represented by "ma".
+ * In other words, plug in "ma" in "pw".
+ */
+static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space = NULL;
+
+	ma = isl_multi_aff_align_divs(ma);
+	pw = FN(PW,cow)(pw);
+	if (!pw || !ma)
+		goto error;
+
+	space = isl_space_join(isl_multi_aff_get_space(ma),
+				FN(PW,get_space)(pw));
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
+						    isl_multi_aff_copy(ma));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
+						    isl_multi_aff_copy(ma));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	pw = FN(PW,reset_space)(pw, space);
+	isl_multi_aff_free(ma);
+	return pw;
+error:
+	isl_space_free(space);
+	isl_multi_aff_free(ma);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma)
+{
+	return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
+					&FN(PW,pullback_multi_aff_aligned));
+}
+
+/* Compute the pullback of "pw" by the function represented by "pma".
+ * In other words, plug in "pma" in "pw".
+ */
+static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	PW *res;
+
+	if (!pma)
+		goto error;
+
+	if (pma->n == 0) {
+		isl_space *space;
+		space = isl_space_join(isl_pw_multi_aff_get_space(pma),
+					FN(PW,get_space)(pw));
+		isl_pw_multi_aff_free(pma);
+		res = FN(PW,empty)(space);
+		FN(PW,free)(pw);
+		return res;
+	}
+
+	res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
+					isl_multi_aff_copy(pma->p[0].maff));
+	res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
+
+	for (i = 1; i < pma->n; ++i) {
+		PW *res_i;
+
+		res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
+					isl_multi_aff_copy(pma->p[i].maff));
+		res_i = FN(PW,intersect_domain)(res_i,
+					isl_set_copy(pma->p[i].set));
+		res = FN(PW,add_disjoint)(res, res_i);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	FN(PW,free)(pw);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
+					&FN(PW,pullback_pw_multi_aff_aligned));
+}
+#endif

Added: polly/trunk/lib/External/isl/isl_range.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_range.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_range.c (added)
+++ polly/trunk/lib/External/isl/isl_range.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,491 @@
+#include <isl_ctx_private.h>
+#include <isl_constraint_private.h>
+#include <isl/set.h>
+#include <isl_polynomial_private.h>
+#include <isl_morph.h>
+#include <isl_range.h>
+
+struct range_data {
+	struct isl_bound	*bound;
+	int 		    	*signs;
+	int			sign;
+	int			test_monotonicity;
+	int		    	monotonicity;
+	int			tight;
+	isl_qpolynomial	    	*poly;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_pw_qpolynomial_fold *pwf_tight;
+};
+
+static int propagate_on_domain(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data);
+
+/* Check whether the polynomial "poly" has sign "sign" over "bset",
+ * i.e., if sign == 1, check that the lower bound on the polynomial
+ * is non-negative and if sign == -1, check that the upper bound on
+ * the polynomial is non-positive.
+ */
+static int has_sign(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_qpolynomial *poly, int sign, int *signs)
+{
+	struct range_data data_m;
+	unsigned nvar;
+	unsigned nparam;
+	isl_space *dim;
+	isl_val *opt;
+	int r;
+	enum isl_fold type;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	bset = isl_basic_set_copy(bset);
+	poly = isl_qpolynomial_copy(poly);
+
+	bset = isl_basic_set_move_dims(bset, isl_dim_set, 0,
+					isl_dim_param, 0, nparam);
+	poly = isl_qpolynomial_move_dims(poly, isl_dim_in, 0,
+					isl_dim_param, 0, nparam);
+
+	dim = isl_qpolynomial_get_space(poly);
+	dim = isl_space_params(dim);
+	dim = isl_space_from_domain(dim);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+
+	data_m.test_monotonicity = 0;
+	data_m.signs = signs;
+	data_m.sign = -sign;
+	type = data_m.sign < 0 ? isl_fold_min : isl_fold_max;
+	data_m.pwf = isl_pw_qpolynomial_fold_zero(dim, type);
+	data_m.tight = 0;
+	data_m.pwf_tight = NULL;
+
+	if (propagate_on_domain(bset, poly, &data_m) < 0)
+		goto error;
+
+	if (sign > 0)
+		opt = isl_pw_qpolynomial_fold_min(data_m.pwf);
+	else
+		opt = isl_pw_qpolynomial_fold_max(data_m.pwf);
+
+	if (!opt)
+		r = -1;
+	else if (isl_val_is_nan(opt) ||
+		 isl_val_is_infty(opt) ||
+		 isl_val_is_neginfty(opt))
+		r = 0;
+	else
+		r = sign * isl_val_sgn(opt) >= 0;
+
+	isl_val_free(opt);
+
+	return r;
+error:
+	isl_pw_qpolynomial_fold_free(data_m.pwf);
+	return -1;
+}
+
+/* Return  1 if poly is monotonically increasing in the last set variable,
+ *        -1 if poly is monotonically decreasing in the last set variable,
+ *	   0 if no conclusion,
+ *	  -2 on error.
+ *
+ * We simply check the sign of p(x+1)-p(x)
+ */
+static int monotonicity(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_qpolynomial *poly, struct range_data *data)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	isl_qpolynomial *sub = NULL;
+	isl_qpolynomial *diff = NULL;
+	int result = 0;
+	int s;
+	unsigned nvar;
+
+	ctx = isl_qpolynomial_get_ctx(poly);
+	dim = isl_qpolynomial_get_domain_space(poly);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	sub = isl_qpolynomial_var_on_domain(isl_space_copy(dim), isl_dim_set, nvar - 1);
+	sub = isl_qpolynomial_add(sub,
+		isl_qpolynomial_rat_cst_on_domain(dim, ctx->one, ctx->one));
+
+	diff = isl_qpolynomial_substitute(isl_qpolynomial_copy(poly),
+			isl_dim_in, nvar - 1, 1, &sub);
+	diff = isl_qpolynomial_sub(diff, isl_qpolynomial_copy(poly));
+
+	s = has_sign(bset, diff, 1, data->signs);
+	if (s < 0)
+		goto error;
+	if (s)
+		result = 1;
+	else {
+		s = has_sign(bset, diff, -1, data->signs);
+		if (s < 0)
+			goto error;
+		if (s)
+			result = -1;
+	}
+
+	isl_qpolynomial_free(diff);
+	isl_qpolynomial_free(sub);
+
+	return result;
+error:
+	isl_qpolynomial_free(diff);
+	isl_qpolynomial_free(sub);
+	return -2;
+}
+
+static __isl_give isl_qpolynomial *bound2poly(__isl_take isl_constraint *bound,
+	__isl_take isl_space *dim, unsigned pos, int sign)
+{
+	if (!bound) {
+		if (sign > 0)
+			return isl_qpolynomial_infty_on_domain(dim);
+		else
+			return isl_qpolynomial_neginfty_on_domain(dim);
+	}
+	isl_space_free(dim);
+	return isl_qpolynomial_from_constraint(bound, isl_dim_set, pos);
+}
+
+static int bound_is_integer(__isl_take isl_constraint *bound, unsigned pos)
+{
+	isl_int c;
+	int is_int;
+
+	if (!bound)
+		return 1;
+
+	isl_int_init(c);
+	isl_constraint_get_coefficient(bound, isl_dim_set, pos, &c);
+	is_int = isl_int_is_one(c) || isl_int_is_negone(c);
+	isl_int_clear(c);
+
+	return is_int;
+}
+
+struct isl_fixed_sign_data {
+	int		*signs;
+	int		sign;
+	isl_qpolynomial	*poly;
+};
+
+/* Add term "term" to data->poly if it has sign data->sign.
+ * The sign is determined based on the signs of the parameters
+ * and variables in data->signs.  The integer divisions, if
+ * any, are assumed to be non-negative.
+ */
+static int collect_fixed_sign_terms(__isl_take isl_term *term, void *user)
+{
+	struct isl_fixed_sign_data *data = (struct isl_fixed_sign_data *)user;
+	isl_int n;
+	int i;
+	int sign;
+	unsigned nparam;
+	unsigned nvar;
+
+	if (!term)
+		return -1;
+
+	nparam = isl_term_dim(term, isl_dim_param);
+	nvar = isl_term_dim(term, isl_dim_set);
+
+	isl_int_init(n);
+
+	isl_term_get_num(term, &n);
+
+	sign = isl_int_sgn(n);
+	for (i = 0; i < nparam; ++i) {
+		if (data->signs[i] > 0)
+			continue;
+		if (isl_term_get_exp(term, isl_dim_param, i) % 2)
+			sign = -sign;
+	}
+	for (i = 0; i < nvar; ++i) {
+		if (data->signs[nparam + i] > 0)
+			continue;
+		if (isl_term_get_exp(term, isl_dim_set, i) % 2)
+			sign = -sign;
+	}
+
+	if (sign == data->sign) {
+		isl_qpolynomial *t = isl_qpolynomial_from_term(term);
+
+		data->poly = isl_qpolynomial_add(data->poly, t);
+	} else
+		isl_term_free(term);
+
+	isl_int_clear(n);
+
+	return 0;
+}
+
+/* Construct and return a polynomial that consists of the terms
+ * in "poly" that have sign "sign".  The integer divisions, if
+ * any, are assumed to be non-negative.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign(
+	__isl_keep isl_qpolynomial *poly, int *signs, int sign)
+{
+	isl_space *space;
+	struct isl_fixed_sign_data data = { signs, sign };
+
+	space = isl_qpolynomial_get_domain_space(poly);
+	data.poly = isl_qpolynomial_zero_on_domain(space);
+
+	if (isl_qpolynomial_foreach_term(poly, collect_fixed_sign_terms, &data) < 0)
+		goto error;
+
+	return data.poly;
+error:
+	isl_qpolynomial_free(data.poly);
+	return NULL;
+}
+
+/* Helper function to add a guarded polynomial to either pwf_tight or pwf,
+ * depending on whether the result has been determined to be tight.
+ */
+static int add_guarded_poly(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data)
+{
+	enum isl_fold type = data->sign < 0 ? isl_fold_min : isl_fold_max;
+	isl_set *set;
+	isl_qpolynomial_fold *fold;
+	isl_pw_qpolynomial_fold *pwf;
+
+	bset = isl_basic_set_params(bset);
+	poly = isl_qpolynomial_project_domain_on_params(poly);
+
+	fold = isl_qpolynomial_fold_alloc(type, poly);
+	set = isl_set_from_basic_set(bset);
+	pwf = isl_pw_qpolynomial_fold_alloc(type, set, fold);
+	if (data->tight)
+		data->pwf_tight = isl_pw_qpolynomial_fold_fold(
+						data->pwf_tight, pwf);
+	else
+		data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf);
+
+	return 0;
+}
+
+/* Given a lower and upper bound on the final variable and constraints
+ * on the remaining variables where these bounds are active,
+ * eliminate the variable from data->poly based on these bounds.
+ * If the polynomial has been determined to be monotonic
+ * in the variable, then simply plug in the appropriate bound.
+ * If the current polynomial is tight and if this bound is integer,
+ * then the result is still tight.  In all other cases, the results
+ * may not be tight.
+ * Otherwise, plug in the largest bound (in absolute value) in
+ * the positive terms (if an upper bound is wanted) or the negative terms
+ * (if a lower bounded is wanted) and the other bound in the other terms.
+ *
+ * If all variables have been eliminated, then record the result.
+ * Ohterwise, recurse on the next variable.
+ */
+static int propagate_on_bound_pair(__isl_take isl_constraint *lower,
+	__isl_take isl_constraint *upper, __isl_take isl_basic_set *bset,
+	void *user)
+{
+	struct range_data *data = (struct range_data *)user;
+	int save_tight = data->tight;
+	isl_qpolynomial *poly;
+	int r;
+	unsigned nvar;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	if (data->monotonicity) {
+		isl_qpolynomial *sub;
+		isl_space *dim = isl_qpolynomial_get_domain_space(data->poly);
+		if (data->monotonicity * data->sign > 0) {
+			if (data->tight)
+				data->tight = bound_is_integer(upper, nvar);
+			sub = bound2poly(upper, dim, nvar, 1);
+			isl_constraint_free(lower);
+		} else {
+			if (data->tight)
+				data->tight = bound_is_integer(lower, nvar);
+			sub = bound2poly(lower, dim, nvar, -1);
+			isl_constraint_free(upper);
+		}
+		poly = isl_qpolynomial_copy(data->poly);
+		poly = isl_qpolynomial_substitute(poly, isl_dim_in, nvar, 1, &sub);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1);
+
+		isl_qpolynomial_free(sub);
+	} else {
+		isl_qpolynomial *l, *u;
+		isl_qpolynomial *pos, *neg;
+		isl_space *dim = isl_qpolynomial_get_domain_space(data->poly);
+		unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+		int sign = data->sign * data->signs[nparam + nvar];
+
+		data->tight = 0;
+
+		u = bound2poly(upper, isl_space_copy(dim), nvar, 1);
+		l = bound2poly(lower, dim, nvar, -1);
+
+		pos = isl_qpolynomial_terms_of_sign(data->poly, data->signs, sign);
+		neg = isl_qpolynomial_terms_of_sign(data->poly, data->signs, -sign);
+
+		pos = isl_qpolynomial_substitute(pos, isl_dim_in, nvar, 1, &u);
+		neg = isl_qpolynomial_substitute(neg, isl_dim_in, nvar, 1, &l);
+
+		poly = isl_qpolynomial_add(pos, neg);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1);
+
+		isl_qpolynomial_free(u);
+		isl_qpolynomial_free(l);
+	}
+
+	if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+		r = add_guarded_poly(bset, poly, data);
+	else
+		r = propagate_on_domain(bset, poly, data);
+
+	data->tight = save_tight;
+
+	return r;
+}
+
+/* Recursively perform range propagation on the polynomial "poly"
+ * defined over the basic set "bset" and collect the results in "data".
+ */
+static int propagate_on_domain(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data)
+{
+	isl_ctx *ctx;
+	isl_qpolynomial *save_poly = data->poly;
+	int save_monotonicity = data->monotonicity;
+	unsigned d;
+
+	if (!bset || !poly)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	isl_assert(ctx, d >= 1, goto error);
+
+	if (isl_qpolynomial_is_cst(poly, NULL, NULL)) {
+		bset = isl_basic_set_project_out(bset, isl_dim_set, 0, d);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, d);
+		return add_guarded_poly(bset, poly, data);
+	}
+
+	if (data->test_monotonicity)
+		data->monotonicity = monotonicity(bset, poly, data);
+	else
+		data->monotonicity = 0;
+	if (data->monotonicity < -1)
+		goto error;
+
+	data->poly = poly;
+	if (isl_basic_set_foreach_bound_pair(bset, isl_dim_set, d - 1,
+					    &propagate_on_bound_pair, data) < 0)
+		goto error;
+
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	data->monotonicity = save_monotonicity;
+	data->poly = save_poly;
+
+	return 0;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	data->monotonicity = save_monotonicity;
+	data->poly = save_poly;
+	return -1;
+}
+
+static int basic_guarded_poly_bound(__isl_take isl_basic_set *bset, void *user)
+{
+	struct range_data *data = (struct range_data *)user;
+	isl_ctx *ctx;
+	unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+	unsigned dim = isl_basic_set_dim(bset, isl_dim_set);
+	int r;
+
+	data->signs = NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	data->signs = isl_alloc_array(ctx, int,
+					isl_basic_set_dim(bset, isl_dim_all));
+
+	if (isl_basic_set_dims_get_sign(bset, isl_dim_set, 0, dim,
+					data->signs + nparam) < 0)
+		goto error;
+	if (isl_basic_set_dims_get_sign(bset, isl_dim_param, 0, nparam,
+					data->signs) < 0)
+		goto error;
+
+	r = propagate_on_domain(bset, isl_qpolynomial_copy(data->poly), data);
+
+	free(data->signs);
+
+	return r;
+error:
+	free(data->signs);
+	isl_basic_set_free(bset);
+	return -1;
+}
+
+static int qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data)
+{
+	unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+	unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
+	isl_set *set = NULL;
+
+	if (!bset)
+		goto error;
+
+	if (nvar == 0)
+		return add_guarded_poly(bset, poly, data);
+
+	set = isl_set_from_basic_set(bset);
+	set = isl_set_split_dims(set, isl_dim_param, 0, nparam);
+	set = isl_set_split_dims(set, isl_dim_set, 0, nvar);
+
+	data->poly = poly;
+
+	data->test_monotonicity = 1;
+	if (isl_set_foreach_basic_set(set, &basic_guarded_poly_bound, data) < 0)
+		goto error;
+
+	isl_set_free(set);
+	isl_qpolynomial_free(poly);
+
+	return 0;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(poly);
+	return -1;
+}
+
+int isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct isl_bound *bound)
+{
+	struct range_data data;
+	int r;
+
+	data.pwf = bound->pwf;
+	data.pwf_tight = bound->pwf_tight;
+	data.tight = bound->check_tight;
+	if (bound->type == isl_fold_min)
+		data.sign = -1;
+	else
+		data.sign = 1;
+
+	r = qpolynomial_bound_on_domain_range(bset, poly, &data);
+
+	bound->pwf = data.pwf;
+	bound->pwf_tight = data.pwf_tight;
+
+	return r;
+}

Added: polly/trunk/lib/External/isl/isl_range.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_range.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_range.h (added)
+++ polly/trunk/lib/External/isl/isl_range.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,6 @@
+#include <isl_bound.h>
+
+int isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct isl_bound *bound);
+__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign(
+	__isl_keep isl_qpolynomial *poly, int *signs, int sign);

Added: polly/trunk/lib/External/isl/isl_reordering.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_reordering.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_reordering.c (added)
+++ polly/trunk/lib/External/isl/isl_reordering.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,205 @@
+/*
+ * 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_ctx_private.h>
+#include <isl_space_private.h>
+#include <isl_reordering.h>
+
+__isl_give isl_reordering *isl_reordering_alloc(isl_ctx *ctx, int len)
+{
+	isl_reordering *exp;
+
+	exp = isl_alloc(ctx, struct isl_reordering,
+			sizeof(struct isl_reordering) + (len - 1) * sizeof(int));
+	if (!exp)
+		return NULL;
+
+	exp->ref = 1;
+	exp->len = len;
+	exp->dim = NULL;
+
+	return exp;
+}
+
+__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp)
+{
+	if (!exp)
+		return NULL;
+
+	exp->ref++;
+	return exp;
+}
+
+__isl_give isl_reordering *isl_reordering_dup(__isl_keep isl_reordering *r)
+{
+	int i;
+	isl_reordering *dup;
+
+	if (!r)
+		return NULL;
+
+	dup = isl_reordering_alloc(r->dim->ctx, r->len);
+	if (!dup)
+		return NULL;
+
+	dup->dim = isl_space_copy(r->dim);
+	if (!dup->dim)
+		return isl_reordering_free(dup);
+	for (i = 0; i < dup->len; ++i)
+		dup->pos[i] = r->pos[i];
+
+	return dup;
+}
+
+__isl_give isl_reordering *isl_reordering_cow(__isl_take isl_reordering *r)
+{
+	if (!r)
+		return NULL;
+
+	if (r->ref == 1)
+		return r;
+	r->ref--;
+	return isl_reordering_dup(r);
+}
+
+void *isl_reordering_free(__isl_take isl_reordering *exp)
+{
+	if (!exp)
+		return NULL;
+
+	if (--exp->ref > 0)
+		return NULL;
+
+	isl_space_free(exp->dim);
+	free(exp);
+	return NULL;
+}
+
+/* Construct a reordering that maps the parameters of "alignee"
+ * to the corresponding parameters in a new dimension specification
+ * that has the parameters of "aligner" first, followed by
+ * any remaining parameters of "alignee" that do not occur in "aligner".
+ */
+__isl_give isl_reordering *isl_parameter_alignment_reordering(
+	__isl_keep isl_space *alignee, __isl_keep isl_space *aligner)
+{
+	int i, j;
+	isl_reordering *exp;
+
+	if (!alignee || !aligner)
+		return NULL;
+
+	exp = isl_reordering_alloc(alignee->ctx, alignee->nparam);
+	if (!exp)
+		return NULL;
+
+	exp->dim = isl_space_copy(aligner);
+
+	for (i = 0; i < alignee->nparam; ++i) {
+		isl_id *id_i;
+		id_i = isl_space_get_dim_id(alignee, isl_dim_param, i);
+		if (!id_i)
+			isl_die(alignee->ctx, isl_error_invalid,
+				"cannot align unnamed parameters", goto error);
+		for (j = 0; j < aligner->nparam; ++j) {
+			isl_id *id_j;
+			id_j = isl_space_get_dim_id(aligner, isl_dim_param, j);
+			isl_id_free(id_j);
+			if (id_i == id_j)
+				break;
+		}
+		if (j < aligner->nparam) {
+			exp->pos[i] = j;
+			isl_id_free(id_i);
+		} else {
+			int pos;
+			pos = isl_space_dim(exp->dim, isl_dim_param);
+			exp->dim = isl_space_add_dims(exp->dim, isl_dim_param, 1);
+			exp->dim = isl_space_set_dim_id(exp->dim,
+						isl_dim_param, pos, id_i);
+			exp->pos[i] = pos;
+		}
+	}
+
+	if (!exp->dim)
+		return isl_reordering_free(exp);
+	return exp;
+error:
+	isl_reordering_free(exp);
+	return NULL;
+}
+
+__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp,
+	unsigned extra)
+{
+	int i;
+	isl_reordering *res;
+	int offset;
+
+	if (!exp)
+		return NULL;
+	if (extra == 0)
+		return exp;
+
+	offset = isl_space_dim(exp->dim, isl_dim_all) - exp->len;
+	res = isl_reordering_alloc(exp->dim->ctx, exp->len + extra);
+	if (!res)
+		goto error;
+	res->dim = isl_space_copy(exp->dim);
+	for (i = 0; i < exp->len; ++i)
+		res->pos[i] = exp->pos[i];
+	for (i = exp->len; i < res->len; ++i)
+		res->pos[i] = offset + i;
+
+	isl_reordering_free(exp);
+
+	return res;
+error:
+	isl_reordering_free(exp);
+	return NULL;
+}
+
+__isl_give isl_reordering *isl_reordering_extend_space(
+	__isl_take isl_reordering *exp, __isl_take isl_space *dim)
+{
+	isl_reordering *res;
+
+	if (!exp || !dim)
+		goto error;
+
+	res = isl_reordering_extend(isl_reordering_copy(exp),
+				    isl_space_dim(dim, isl_dim_all) - exp->len);
+	res = isl_reordering_cow(res);
+	if (!res)
+		goto error;
+	isl_space_free(res->dim);
+	res->dim = isl_space_replace(dim, isl_dim_param, exp->dim);
+
+	isl_reordering_free(exp);
+
+	if (!res->dim)
+		return isl_reordering_free(res);
+
+	return res;
+error:
+	isl_reordering_free(exp);
+	isl_space_free(dim);
+	return NULL;
+}
+
+void isl_reordering_dump(__isl_keep isl_reordering *exp)
+{
+	int i;
+
+	isl_space_dump(exp->dim);
+	for (i = 0; i < exp->len; ++i)
+		fprintf(stderr, "%d -> %d; ", i, exp->pos[i]);
+	fprintf(stderr, "\n");
+}

Added: polly/trunk/lib/External/isl/isl_reordering.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_reordering.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_reordering.h (added)
+++ polly/trunk/lib/External/isl/isl_reordering.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,31 @@
+#ifndef ISL_REORDERING_H
+#define ISL_REORDERING_H
+
+#include <isl/space.h>
+
+/* pos maps original dimensions to new dimensions.
+ * The final dimension is given by dim.
+ * The number of dimensions (i.e., the range of values) in the result
+ * may be larger than the number of dimensions in the input.
+ * In particular, the possible values of the entries in pos ranges from 0 to
+ * the total dimension of dim - 1, unless isl_reordering_extend
+ * has been called.
+ */
+struct isl_reordering {
+	int ref;
+	isl_space *dim;
+	unsigned len;
+	int pos[1];
+};
+typedef struct isl_reordering isl_reordering;
+
+__isl_give isl_reordering *isl_parameter_alignment_reordering(
+	__isl_keep isl_space *alignee, __isl_keep isl_space *aligner);
+__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp);
+void *isl_reordering_free(__isl_take isl_reordering *exp);
+__isl_give isl_reordering *isl_reordering_extend_space(
+	__isl_take isl_reordering *exp, __isl_take isl_space *dim);
+__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp,
+	unsigned extra);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_sample.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_sample.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_sample.c (added)
+++ polly/trunk/lib/External/isl/isl_sample.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,1301 @@
+/*
+ * 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_sample.h"
+#include <isl/vec.h>
+#include <isl/mat.h>
+#include <isl_seq.h>
+#include "isl_equalities.h"
+#include "isl_tab.h"
+#include "isl_basis_reduction.h"
+#include <isl_factorization.h>
+#include <isl_point_private.h>
+#include <isl_options_private.h>
+#include <isl_vec_private.h>
+
+static struct isl_vec *empty_sample(struct isl_basic_set *bset)
+{
+	struct isl_vec *vec;
+
+	vec = isl_vec_alloc(bset->ctx, 0);
+	isl_basic_set_free(bset);
+	return vec;
+}
+
+/* Construct a zero sample of the same dimension as bset.
+ * As a special case, if bset is zero-dimensional, this
+ * function creates a zero-dimensional sample point.
+ */
+static struct isl_vec *zero_sample(struct isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_vec *sample;
+
+	dim = isl_basic_set_total_dim(bset);
+	sample = isl_vec_alloc(bset->ctx, 1 + dim);
+	if (sample) {
+		isl_int_set_si(sample->el[0], 1);
+		isl_seq_clr(sample->el + 1, dim);
+	}
+	isl_basic_set_free(bset);
+	return sample;
+}
+
+static struct isl_vec *interval_sample(struct isl_basic_set *bset)
+{
+	int i;
+	isl_int t;
+	struct isl_vec *sample;
+
+	bset = isl_basic_set_simplify(bset);
+	if (!bset)
+		return NULL;
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+	if (bset->n_eq == 0 && bset->n_ineq == 0)
+		return zero_sample(bset);
+
+	sample = isl_vec_alloc(bset->ctx, 2);
+	if (!sample)
+		goto error;
+	if (!bset)
+		return NULL;
+	isl_int_set_si(sample->block.data[0], 1);
+
+	if (bset->n_eq > 0) {
+		isl_assert(bset->ctx, bset->n_eq == 1, goto error);
+		isl_assert(bset->ctx, bset->n_ineq == 0, goto error);
+		if (isl_int_is_one(bset->eq[0][1]))
+			isl_int_neg(sample->el[1], bset->eq[0][0]);
+		else {
+			isl_assert(bset->ctx, isl_int_is_negone(bset->eq[0][1]),
+				   goto error);
+			isl_int_set(sample->el[1], bset->eq[0][0]);
+		}
+		isl_basic_set_free(bset);
+		return sample;
+	}
+
+	isl_int_init(t);
+	if (isl_int_is_one(bset->ineq[0][1]))
+		isl_int_neg(sample->block.data[1], bset->ineq[0][0]);
+	else
+		isl_int_set(sample->block.data[1], bset->ineq[0][0]);
+	for (i = 1; i < bset->n_ineq; ++i) {
+		isl_seq_inner_product(sample->block.data,
+					bset->ineq[i], 2, &t);
+		if (isl_int_is_neg(t))
+			break;
+	}
+	isl_int_clear(t);
+	if (i < bset->n_ineq) {
+		isl_vec_free(sample);
+		return empty_sample(bset);
+	}
+
+	isl_basic_set_free(bset);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Find a sample integer point, if any, in bset, which is known
+ * to have equalities.  If bset contains no integer points, then
+ * return a zero-length vector.
+ * We simply remove the known equalities, compute a sample
+ * in the resulting bset, using the specified recurse function,
+ * and then transform the sample back to the original space.
+ */
+static struct isl_vec *sample_eq(struct isl_basic_set *bset,
+	struct isl_vec *(*recurse)(struct isl_basic_set *))
+{
+	struct isl_mat *T;
+	struct isl_vec *sample;
+
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+	sample = recurse(bset);
+	if (!sample || sample->size == 0)
+		isl_mat_free(T);
+	else
+		sample = isl_mat_vec_product(T, sample);
+	return sample;
+}
+
+/* Return a matrix containing the equalities of the tableau
+ * in constraint form.  The tableau is assumed to have
+ * an associated bset that has been kept up-to-date.
+ */
+static struct isl_mat *tab_equalities(struct isl_tab *tab)
+{
+	int i, j;
+	int n_eq;
+	struct isl_mat *eq;
+	struct isl_basic_set *bset;
+
+	if (!tab)
+		return NULL;
+
+	bset = isl_tab_peek_bset(tab);
+	isl_assert(tab->mat->ctx, bset, return NULL);
+
+	n_eq = tab->n_var - tab->n_col + tab->n_dead;
+	if (tab->empty || n_eq == 0)
+		return isl_mat_alloc(tab->mat->ctx, 0, tab->n_var);
+	if (n_eq == tab->n_var)
+		return isl_mat_identity(tab->mat->ctx, tab->n_var);
+
+	eq = isl_mat_alloc(tab->mat->ctx, n_eq, tab->n_var);
+	if (!eq)
+		return NULL;
+	for (i = 0, j = 0; i < tab->n_con; ++i) {
+		if (tab->con[i].is_row)
+			continue;
+		if (tab->con[i].index >= 0 && tab->con[i].index >= tab->n_dead)
+			continue;
+		if (i < bset->n_eq)
+			isl_seq_cpy(eq->row[j], bset->eq[i] + 1, tab->n_var);
+		else
+			isl_seq_cpy(eq->row[j],
+				    bset->ineq[i - bset->n_eq] + 1, tab->n_var);
+		++j;
+	}
+	isl_assert(bset->ctx, j == n_eq, goto error);
+	return eq;
+error:
+	isl_mat_free(eq);
+	return NULL;
+}
+
+/* Compute and return an initial basis for the bounded tableau "tab".
+ *
+ * If the tableau is either full-dimensional or zero-dimensional,
+ * the we simply return an identity matrix.
+ * Otherwise, we construct a basis whose first directions correspond
+ * to equalities.
+ */
+static struct isl_mat *initial_basis(struct isl_tab *tab)
+{
+	int n_eq;
+	struct isl_mat *eq;
+	struct isl_mat *Q;
+
+	tab->n_unbounded = 0;
+	tab->n_zero = n_eq = tab->n_var - tab->n_col + tab->n_dead;
+	if (tab->empty || n_eq == 0 || n_eq == tab->n_var)
+		return isl_mat_identity(tab->mat->ctx, 1 + tab->n_var);
+
+	eq = tab_equalities(tab);
+	eq = isl_mat_left_hermite(eq, 0, NULL, &Q);
+	if (!eq)
+		return NULL;
+	isl_mat_free(eq);
+
+	Q = isl_mat_lin_to_aff(Q);
+	return Q;
+}
+
+/* Compute the minimum of the current ("level") basis row over "tab"
+ * and store the result in position "level" of "min".
+ */
+static enum isl_lp_result compute_min(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *min, int level)
+{
+	return isl_tab_min(tab, tab->basis->row[1 + level],
+			    ctx->one, &min->el[level], NULL, 0);
+}
+
+/* Compute the maximum of the current ("level") basis row over "tab"
+ * and store the result in position "level" of "max".
+ */
+static enum isl_lp_result compute_max(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *max, int level)
+{
+	enum isl_lp_result res;
+	unsigned dim = tab->n_var;
+
+	isl_seq_neg(tab->basis->row[1 + level] + 1,
+		    tab->basis->row[1 + level] + 1, dim);
+	res = isl_tab_min(tab, tab->basis->row[1 + level],
+		    ctx->one, &max->el[level], NULL, 0);
+	isl_seq_neg(tab->basis->row[1 + level] + 1,
+		    tab->basis->row[1 + level] + 1, dim);
+	isl_int_neg(max->el[level], max->el[level]);
+
+	return res;
+}
+
+/* Perform a greedy search for an integer point in the set represented
+ * by "tab", given that the minimal rational value (rounded up to the
+ * nearest integer) at "level" is smaller than the maximal rational
+ * value (rounded down to the nearest integer).
+ *
+ * Return 1 if we have found an integer point (if tab->n_unbounded > 0
+ * then we may have only found integer values for the bounded dimensions
+ * and it is the responsibility of the caller to extend this solution
+ * to the unbounded dimensions).
+ * Return 0 if greedy search did not result in a solution.
+ * Return -1 if some error occurred.
+ *
+ * We assign a value half-way between the minimum and the maximum
+ * to the current dimension and check if the minimal value of the
+ * next dimension is still smaller than (or equal) to the maximal value.
+ * We continue this process until either
+ * - the minimal value (rounded up) is greater than the maximal value
+ *	(rounded down).  In this case, greedy search has failed.
+ * - we have exhausted all bounded dimensions, meaning that we have
+ *	found a solution.
+ * - the sample value of the tableau is integral.
+ * - some error has occurred.
+ */
+static int greedy_search(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *min, __isl_keep isl_vec *max, int level)
+{
+	struct isl_tab_undo *snap;
+	enum isl_lp_result res;
+
+	snap = isl_tab_snap(tab);
+
+	do {
+		isl_int_add(tab->basis->row[1 + level][0],
+			    min->el[level], max->el[level]);
+		isl_int_fdiv_q_ui(tab->basis->row[1 + level][0],
+			    tab->basis->row[1 + level][0], 2);
+		isl_int_neg(tab->basis->row[1 + level][0],
+			    tab->basis->row[1 + level][0]);
+		if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0)
+			return -1;
+		isl_int_set_si(tab->basis->row[1 + level][0], 0);
+
+		if (++level >= tab->n_var - tab->n_unbounded)
+			return 1;
+		if (isl_tab_sample_is_integer(tab))
+			return 1;
+
+		res = compute_min(ctx, tab, min, level);
+		if (res == isl_lp_error)
+			return -1;
+		if (res != isl_lp_ok)
+			isl_die(ctx, isl_error_internal,
+				"expecting bounded rational solution",
+				return -1);
+		res = compute_max(ctx, tab, max, level);
+		if (res == isl_lp_error)
+			return -1;
+		if (res != isl_lp_ok)
+			isl_die(ctx, isl_error_internal,
+				"expecting bounded rational solution",
+				return -1);
+	} while (isl_int_le(min->el[level], max->el[level]));
+
+	if (isl_tab_rollback(tab, snap) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Given a tableau representing a set, find and return
+ * an integer point in the set, if there is any.
+ *
+ * We perform a depth first search
+ * for an integer point, by scanning all possible values in the range
+ * attained by a basis vector, where an initial basis may have been set
+ * by the calling function.  Otherwise an initial basis that exploits
+ * the equalities in the tableau is created.
+ * tab->n_zero is currently ignored and is clobbered by this function.
+ *
+ * The tableau is allowed to have unbounded direction, but then
+ * the calling function needs to set an initial basis, with the
+ * unbounded directions last and with tab->n_unbounded set
+ * to the number of unbounded directions.
+ * Furthermore, the calling functions needs to add shifted copies
+ * of all constraints involving unbounded directions to ensure
+ * that any feasible rational value in these directions can be rounded
+ * up to yield a feasible integer value.
+ * In particular, let B define the given basis x' = B x
+ * and let T be the inverse of B, i.e., X = T x'.
+ * Let a x + c >= 0 be a constraint of the set represented by the tableau,
+ * or a T x' + c >= 0 in terms of the given basis.  Assume that
+ * the bounded directions have an integer value, then we can safely
+ * round up the values for the unbounded directions if we make sure
+ * that x' not only satisfies the original constraint, but also
+ * the constraint "a T x' + c + s >= 0" with s the sum of all
+ * negative values in the last n_unbounded entries of "a T".
+ * The calling function therefore needs to add the constraint
+ * a x + c + s >= 0.  The current function then scans the first
+ * directions for an integer value and once those have been found,
+ * it can compute "T ceil(B x)" to yield an integer point in the set.
+ * Note that during the search, the first rows of B may be changed
+ * by a basis reduction, but the last n_unbounded rows of B remain
+ * unaltered and are also not mixed into the first rows.
+ *
+ * The search is implemented iteratively.  "level" identifies the current
+ * basis vector.  "init" is true if we want the first value at the current
+ * level and false if we want the next value.
+ *
+ * At the start of each level, we first check if we can find a solution
+ * using greedy search.  If not, we continue with the exhaustive search.
+ *
+ * The initial basis is the identity matrix.  If the range in some direction
+ * contains more than one integer value, we perform basis reduction based
+ * on the value of ctx->opt->gbr
+ *	- ISL_GBR_NEVER:	never perform basis reduction
+ *	- ISL_GBR_ONCE:		only perform basis reduction the first
+ *				time such a range is encountered
+ *	- ISL_GBR_ALWAYS:	always perform basis reduction when
+ *				such a range is encountered
+ *
+ * When ctx->opt->gbr is set to ISL_GBR_ALWAYS, then we allow the basis
+ * reduction computation to return early.  That is, as soon as it
+ * finds a reasonable first direction.
+ */ 
+struct isl_vec *isl_tab_sample(struct isl_tab *tab)
+{
+	unsigned dim;
+	unsigned gbr;
+	struct isl_ctx *ctx;
+	struct isl_vec *sample;
+	struct isl_vec *min;
+	struct isl_vec *max;
+	enum isl_lp_result res;
+	int level;
+	int init;
+	int reduced;
+	struct isl_tab_undo **snap;
+
+	if (!tab)
+		return NULL;
+	if (tab->empty)
+		return isl_vec_alloc(tab->mat->ctx, 0);
+
+	if (!tab->basis)
+		tab->basis = initial_basis(tab);
+	if (!tab->basis)
+		return NULL;
+	isl_assert(tab->mat->ctx, tab->basis->n_row == tab->n_var + 1,
+		    return NULL);
+	isl_assert(tab->mat->ctx, tab->basis->n_col == tab->n_var + 1,
+		    return NULL);
+
+	ctx = tab->mat->ctx;
+	dim = tab->n_var;
+	gbr = ctx->opt->gbr;
+
+	if (tab->n_unbounded == tab->n_var) {
+		sample = isl_tab_get_sample_value(tab);
+		sample = isl_mat_vec_product(isl_mat_copy(tab->basis), sample);
+		sample = isl_vec_ceil(sample);
+		sample = isl_mat_vec_inverse_product(isl_mat_copy(tab->basis),
+							sample);
+		return sample;
+	}
+
+	if (isl_tab_extend_cons(tab, dim + 1) < 0)
+		return NULL;
+
+	min = isl_vec_alloc(ctx, dim);
+	max = isl_vec_alloc(ctx, dim);
+	snap = isl_alloc_array(ctx, struct isl_tab_undo *, dim);
+
+	if (!min || !max || !snap)
+		goto error;
+
+	level = 0;
+	init = 1;
+	reduced = 0;
+
+	while (level >= 0) {
+		if (init) {
+			int choice;
+
+			res = compute_min(ctx, tab, min, level);
+			if (res == isl_lp_error)
+				goto error;
+			if (res != isl_lp_ok)
+				isl_die(ctx, isl_error_internal,
+					"expecting bounded rational solution",
+					goto error);
+			if (isl_tab_sample_is_integer(tab))
+				break;
+			res = compute_max(ctx, tab, max, level);
+			if (res == isl_lp_error)
+				goto error;
+			if (res != isl_lp_ok)
+				isl_die(ctx, isl_error_internal,
+					"expecting bounded rational solution",
+					goto error);
+			if (isl_tab_sample_is_integer(tab))
+				break;
+			choice = isl_int_lt(min->el[level], max->el[level]);
+			if (choice) {
+				int g;
+				g = greedy_search(ctx, tab, min, max, level);
+				if (g < 0)
+					goto error;
+				if (g)
+					break;
+			}
+			if (!reduced && choice &&
+			    ctx->opt->gbr != ISL_GBR_NEVER) {
+				unsigned gbr_only_first;
+				if (ctx->opt->gbr == ISL_GBR_ONCE)
+					ctx->opt->gbr = ISL_GBR_NEVER;
+				tab->n_zero = level;
+				gbr_only_first = ctx->opt->gbr_only_first;
+				ctx->opt->gbr_only_first =
+					ctx->opt->gbr == ISL_GBR_ALWAYS;
+				tab = isl_tab_compute_reduced_basis(tab);
+				ctx->opt->gbr_only_first = gbr_only_first;
+				if (!tab || !tab->basis)
+					goto error;
+				reduced = 1;
+				continue;
+			}
+			reduced = 0;
+			snap[level] = isl_tab_snap(tab);
+		} else
+			isl_int_add_ui(min->el[level], min->el[level], 1);
+
+		if (isl_int_gt(min->el[level], max->el[level])) {
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		isl_int_neg(tab->basis->row[1 + level][0], min->el[level]);
+		if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0)
+			goto error;
+		isl_int_set_si(tab->basis->row[1 + level][0], 0);
+		if (level + tab->n_unbounded < dim - 1) {
+			++level;
+			init = 1;
+			continue;
+		}
+		break;
+	}
+
+	if (level >= 0) {
+		sample = isl_tab_get_sample_value(tab);
+		if (!sample)
+			goto error;
+		if (tab->n_unbounded && !isl_int_is_one(sample->el[0])) {
+			sample = isl_mat_vec_product(isl_mat_copy(tab->basis),
+						     sample);
+			sample = isl_vec_ceil(sample);
+			sample = isl_mat_vec_inverse_product(
+					isl_mat_copy(tab->basis), sample);
+		}
+	} else
+		sample = isl_vec_alloc(ctx, 0);
+
+	ctx->opt->gbr = gbr;
+	isl_vec_free(min);
+	isl_vec_free(max);
+	free(snap);
+	return sample;
+error:
+	ctx->opt->gbr = gbr;
+	isl_vec_free(min);
+	isl_vec_free(max);
+	free(snap);
+	return NULL;
+}
+
+static struct isl_vec *sample_bounded(struct isl_basic_set *bset);
+
+/* Compute a sample point of the given basic set, based on the given,
+ * non-trivial factorization.
+ */
+static __isl_give isl_vec *factored_sample(__isl_take isl_basic_set *bset,
+	__isl_take isl_factorizer *f)
+{
+	int i, n;
+	isl_vec *sample = NULL;
+	isl_ctx *ctx;
+	unsigned nparam;
+	unsigned nvar;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (!ctx)
+		goto error;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	sample = isl_vec_alloc(ctx, 1 + isl_basic_set_total_dim(bset));
+	if (!sample)
+		goto error;
+	isl_int_set_si(sample->el[0], 1);
+
+	bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset);
+
+	for (i = 0, n = 0; i < f->n_group; ++i) {
+		isl_basic_set *bset_i;
+		isl_vec *sample_i;
+
+		bset_i = isl_basic_set_copy(bset);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam + n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam, n);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set,
+			    n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n);
+
+		sample_i = sample_bounded(bset_i);
+		if (!sample_i)
+			goto error;
+		if (sample_i->size == 0) {
+			isl_basic_set_free(bset);
+			isl_factorizer_free(f);
+			isl_vec_free(sample);
+			return sample_i;
+		}
+		isl_seq_cpy(sample->el + 1 + nparam + n,
+			    sample_i->el + 1, f->len[i]);
+		isl_vec_free(sample_i);
+
+		n += f->len[i];
+	}
+
+	f->morph = isl_morph_inverse(f->morph);
+	sample = isl_morph_vec(isl_morph_copy(f->morph), sample);
+
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Given a basic set that is known to be bounded, find and return
+ * an integer point in the basic set, if there is any.
+ *
+ * After handling some trivial cases, we construct a tableau
+ * and then use isl_tab_sample to find a sample, passing it
+ * the identity matrix as initial basis.
+ */ 
+static struct isl_vec *sample_bounded(struct isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_ctx *ctx;
+	struct isl_vec *sample;
+	struct isl_tab *tab = NULL;
+	isl_factorizer *f;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+
+	dim = isl_basic_set_total_dim(bset);
+	if (dim == 0)
+		return zero_sample(bset);
+	if (dim == 1)
+		return interval_sample(bset);
+	if (bset->n_eq > 0)
+		return sample_eq(bset, sample_bounded);
+
+	f = isl_basic_set_factorizer(bset);
+	if (!f)
+		goto error;
+	if (f->n_group != 0)
+		return factored_sample(bset, f);
+	isl_factorizer_free(f);
+		
+	ctx = bset->ctx;
+
+	tab = isl_tab_from_basic_set(bset, 1);
+	if (tab && tab->empty) {
+		isl_tab_free(tab);
+		ISL_F_SET(bset, ISL_BASIC_SET_EMPTY);
+		sample = isl_vec_alloc(bset->ctx, 0);
+		isl_basic_set_free(bset);
+		return sample;
+	}
+
+	if (!ISL_F_ISSET(bset, ISL_BASIC_SET_NO_IMPLICIT))
+		if (isl_tab_detect_implicit_equalities(tab) < 0)
+			goto error;
+
+	sample = isl_tab_sample(tab);
+	if (!sample)
+		goto error;
+
+	if (sample->size > 0) {
+		isl_vec_free(bset->sample);
+		bset->sample = isl_vec_copy(sample);
+	}
+
+	isl_basic_set_free(bset);
+	isl_tab_free(tab);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Given a basic set "bset" and a value "sample" for the first coordinates
+ * of bset, plug in these values and drop the corresponding coordinates.
+ *
+ * We do this by computing the preimage of the transformation
+ *
+ *	     [ 1 0 ]
+ *	x =  [ s 0 ] x'
+ *	     [ 0 I ]
+ *
+ * where [1 s] is the sample value and I is the identity matrix of the
+ * appropriate dimension.
+ */
+static struct isl_basic_set *plug_in(struct isl_basic_set *bset,
+	struct isl_vec *sample)
+{
+	int i;
+	unsigned total;
+	struct isl_mat *T;
+
+	if (!bset || !sample)
+		goto error;
+
+	total = isl_basic_set_total_dim(bset);
+	T = isl_mat_alloc(bset->ctx, 1 + total, 1 + total - (sample->size - 1));
+	if (!T)
+		goto error;
+
+	for (i = 0; i < sample->size; ++i) {
+		isl_int_set(T->row[i][0], sample->el[i]);
+		isl_seq_clr(T->row[i] + 1, T->n_col - 1);
+	}
+	for (i = 0; i < T->n_col - 1; ++i) {
+		isl_seq_clr(T->row[sample->size + i], T->n_col);
+		isl_int_set_si(T->row[sample->size + i][1 + i], 1);
+	}
+	isl_vec_free(sample);
+
+	bset = isl_basic_set_preimage(bset, T);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Given a basic set "bset", return any (possibly non-integer) point
+ * in the basic set.
+ */
+static struct isl_vec *rational_sample(struct isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	struct isl_vec *sample;
+
+	if (!bset)
+		return NULL;
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	sample = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+
+	isl_basic_set_free(bset);
+
+	return sample;
+}
+
+/* Given a linear cone "cone" and a rational point "vec",
+ * construct a polyhedron with shifted copies of the constraints in "cone",
+ * i.e., a polyhedron with "cone" as its recession cone, such that each
+ * point x in this polyhedron is such that the unit box positioned at x
+ * lies entirely inside the affine cone 'vec + cone'.
+ * Any rational point in this polyhedron may therefore be rounded up
+ * to yield an integer point that lies inside said affine cone.
+ *
+ * Denote the constraints of cone by "<a_i, x> >= 0" and the rational
+ * point "vec" by v/d.
+ * Let b_i = <a_i, v>.  Then the affine cone 'vec + cone' is given
+ * by <a_i, x> - b/d >= 0.
+ * The polyhedron <a_i, x> - ceil{b/d} >= 0 is a subset of this affine cone.
+ * We prefer this polyhedron over the actual affine cone because it doesn't
+ * require a scaling of the constraints.
+ * If each of the vertices of the unit cube positioned at x lies inside
+ * this polyhedron, then the whole unit cube at x lies inside the affine cone.
+ * We therefore impose that x' = x + \sum e_i, for any selection of unit
+ * vectors lies inside the polyhedron, i.e.,
+ *
+ *	<a_i, x'> - ceil{b/d} = <a_i, x> + sum a_i - ceil{b/d} >= 0
+ *
+ * The most stringent of these constraints is the one that selects
+ * all negative a_i, so the polyhedron we are looking for has constraints
+ *
+ *	<a_i, x> + sum_{a_i < 0} a_i - ceil{b/d} >= 0
+ *
+ * Note that if cone were known to have only non-negative rays
+ * (which can be accomplished by a unimodular transformation),
+ * then we would only have to check the points x' = x + e_i
+ * and we only have to add the smallest negative a_i (if any)
+ * instead of the sum of all negative a_i.
+ */
+static struct isl_basic_set *shift_cone(struct isl_basic_set *cone,
+	struct isl_vec *vec)
+{
+	int i, j, k;
+	unsigned total;
+
+	struct isl_basic_set *shift = NULL;
+
+	if (!cone || !vec)
+		goto error;
+
+	isl_assert(cone->ctx, cone->n_eq == 0, goto error);
+
+	total = isl_basic_set_total_dim(cone);
+
+	shift = isl_basic_set_alloc_space(isl_basic_set_get_space(cone),
+					0, 0, cone->n_ineq);
+
+	for (i = 0; i < cone->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(shift);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(shift->ineq[k] + 1, cone->ineq[i] + 1, total);
+		isl_seq_inner_product(shift->ineq[k] + 1, vec->el + 1, total,
+				      &shift->ineq[k][0]);
+		isl_int_cdiv_q(shift->ineq[k][0],
+			       shift->ineq[k][0], vec->el[0]);
+		isl_int_neg(shift->ineq[k][0], shift->ineq[k][0]);
+		for (j = 0; j < total; ++j) {
+			if (isl_int_is_nonneg(shift->ineq[k][1 + j]))
+				continue;
+			isl_int_add(shift->ineq[k][0],
+				    shift->ineq[k][0], shift->ineq[k][1 + j]);
+		}
+	}
+
+	isl_basic_set_free(cone);
+	isl_vec_free(vec);
+
+	return isl_basic_set_finalize(shift);
+error:
+	isl_basic_set_free(shift);
+	isl_basic_set_free(cone);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Given a rational point vec in a (transformed) basic set,
+ * such that cone is the recession cone of the original basic set,
+ * "round up" the rational point to an integer point.
+ *
+ * We first check if the rational point just happens to be integer.
+ * If not, we transform the cone in the same way as the basic set,
+ * pick a point x in this cone shifted to the rational point such that
+ * the whole unit cube at x is also inside this affine cone.
+ * Then we simply round up the coordinates of x and return the
+ * resulting integer point.
+ */
+static struct isl_vec *round_up_in_cone(struct isl_vec *vec,
+	struct isl_basic_set *cone, struct isl_mat *U)
+{
+	unsigned total;
+
+	if (!vec || !cone || !U)
+		goto error;
+
+	isl_assert(vec->ctx, vec->size != 0, goto error);
+	if (isl_int_is_one(vec->el[0])) {
+		isl_mat_free(U);
+		isl_basic_set_free(cone);
+		return vec;
+	}
+
+	total = isl_basic_set_total_dim(cone);
+	cone = isl_basic_set_preimage(cone, U);
+	cone = isl_basic_set_remove_dims(cone, isl_dim_set,
+					 0, total - (vec->size - 1));
+
+	cone = shift_cone(cone, vec);
+
+	vec = rational_sample(cone);
+	vec = isl_vec_ceil(vec);
+	return vec;
+error:
+	isl_mat_free(U);
+	isl_vec_free(vec);
+	isl_basic_set_free(cone);
+	return NULL;
+}
+
+/* Concatenate two integer vectors, i.e., two vectors with denominator
+ * (stored in element 0) equal to 1.
+ */
+static struct isl_vec *vec_concat(struct isl_vec *vec1, struct isl_vec *vec2)
+{
+	struct isl_vec *vec;
+
+	if (!vec1 || !vec2)
+		goto error;
+	isl_assert(vec1->ctx, vec1->size > 0, goto error);
+	isl_assert(vec2->ctx, vec2->size > 0, goto error);
+	isl_assert(vec1->ctx, isl_int_is_one(vec1->el[0]), goto error);
+	isl_assert(vec2->ctx, isl_int_is_one(vec2->el[0]), goto error);
+
+	vec = isl_vec_alloc(vec1->ctx, vec1->size + vec2->size - 1);
+	if (!vec)
+		goto error;
+
+	isl_seq_cpy(vec->el, vec1->el, vec1->size);
+	isl_seq_cpy(vec->el + vec1->size, vec2->el + 1, vec2->size - 1);
+
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+
+	return vec;
+error:
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+	return NULL;
+}
+
+/* Give a basic set "bset" with recession cone "cone", compute and
+ * return an integer point in bset, if any.
+ *
+ * If the recession cone is full-dimensional, then we know that
+ * bset contains an infinite number of integer points and it is
+ * fairly easy to pick one of them.
+ * If the recession cone is not full-dimensional, then we first
+ * transform bset such that the bounded directions appear as
+ * the first dimensions of the transformed basic set.
+ * We do this by using a unimodular transformation that transforms
+ * the equalities in the recession cone to equalities on the first
+ * dimensions.
+ *
+ * The transformed set is then projected onto its bounded dimensions.
+ * Note that to compute this projection, we can simply drop all constraints
+ * involving any of the unbounded dimensions since these constraints
+ * cannot be combined to produce a constraint on the bounded dimensions.
+ * To see this, assume that there is such a combination of constraints
+ * that produces a constraint on the bounded dimensions.  This means
+ * that some combination of the unbounded dimensions has both an upper
+ * bound and a lower bound in terms of the bounded dimensions, but then
+ * this combination would be a bounded direction too and would have been
+ * transformed into a bounded dimensions.
+ *
+ * We then compute a sample value in the bounded dimensions.
+ * If no such value can be found, then the original set did not contain
+ * any integer points and we are done.
+ * Otherwise, we plug in the value we found in the bounded dimensions,
+ * project out these bounded dimensions and end up with a set with
+ * a full-dimensional recession cone.
+ * A sample point in this set is computed by "rounding up" any
+ * rational point in the set.
+ *
+ * The sample points in the bounded and unbounded dimensions are
+ * then combined into a single sample point and transformed back
+ * to the original space.
+ */
+__isl_give isl_vec *isl_basic_set_sample_with_cone(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone)
+{
+	unsigned total;
+	unsigned cone_dim;
+	struct isl_mat *M, *U;
+	struct isl_vec *sample;
+	struct isl_vec *cone_sample;
+	struct isl_ctx *ctx;
+	struct isl_basic_set *bounded;
+
+	if (!bset || !cone)
+		goto error;
+
+	ctx = bset->ctx;
+	total = isl_basic_set_total_dim(cone);
+	cone_dim = total - cone->n_eq;
+
+	M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
+	M = isl_mat_left_hermite(M, 0, &U, NULL);
+	if (!M)
+		goto error;
+	isl_mat_free(M);
+
+	U = isl_mat_lin_to_aff(U);
+	bset = isl_basic_set_preimage(bset, isl_mat_copy(U));
+
+	bounded = isl_basic_set_copy(bset);
+	bounded = isl_basic_set_drop_constraints_involving(bounded,
+						   total - cone_dim, cone_dim);
+	bounded = isl_basic_set_drop_dims(bounded, total - cone_dim, cone_dim);
+	sample = sample_bounded(bounded);
+	if (!sample || sample->size == 0) {
+		isl_basic_set_free(bset);
+		isl_basic_set_free(cone);
+		isl_mat_free(U);
+		return sample;
+	}
+	bset = plug_in(bset, isl_vec_copy(sample));
+	cone_sample = rational_sample(bset);
+	cone_sample = round_up_in_cone(cone_sample, cone, isl_mat_copy(U));
+	sample = vec_concat(sample, cone_sample);
+	sample = isl_mat_vec_product(U, sample);
+	return sample;
+error:
+	isl_basic_set_free(cone);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static void vec_sum_of_neg(struct isl_vec *v, isl_int *s)
+{
+	int i;
+
+	isl_int_set_si(*s, 0);
+
+	for (i = 0; i < v->size; ++i)
+		if (isl_int_is_neg(v->el[i]))
+			isl_int_add(*s, *s, v->el[i]);
+}
+
+/* Given a tableau "tab", a tableau "tab_cone" that corresponds
+ * to the recession cone and the inverse of a new basis U = inv(B),
+ * with the unbounded directions in B last,
+ * add constraints to "tab" that ensure any rational value
+ * in the unbounded directions can be rounded up to an integer value.
+ *
+ * The new basis is given by x' = B x, i.e., x = U x'.
+ * For any rational value of the last tab->n_unbounded coordinates
+ * in the update tableau, the value that is obtained by rounding
+ * up this value should be contained in the original tableau.
+ * For any constraint "a x + c >= 0", we therefore need to add
+ * a constraint "a x + c + s >= 0", with s the sum of all negative
+ * entries in the last elements of "a U".
+ *
+ * Since we are not interested in the first entries of any of the "a U",
+ * we first drop the columns of U that correpond to bounded directions.
+ */
+static int tab_shift_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone, struct isl_mat *U)
+{
+	int i;
+	isl_int v;
+	struct isl_basic_set *bset = NULL;
+
+	if (tab && tab->n_unbounded == 0) {
+		isl_mat_free(U);
+		return 0;
+	}
+	isl_int_init(v);
+	if (!tab || !tab_cone || !U)
+		goto error;
+	bset = isl_tab_peek_bset(tab_cone);
+	U = isl_mat_drop_cols(U, 0, tab->n_var - tab->n_unbounded);
+	for (i = 0; i < bset->n_ineq; ++i) {
+		int ok;
+		struct isl_vec *row = NULL;
+		if (isl_tab_is_equality(tab_cone, tab_cone->n_eq + i))
+			continue;
+		row = isl_vec_alloc(bset->ctx, tab_cone->n_var);
+		if (!row)
+			goto error;
+		isl_seq_cpy(row->el, bset->ineq[i] + 1, tab_cone->n_var);
+		row = isl_vec_mat_product(row, isl_mat_copy(U));
+		if (!row)
+			goto error;
+		vec_sum_of_neg(row, &v);
+		isl_vec_free(row);
+		if (isl_int_is_zero(v))
+			continue;
+		if (isl_tab_extend_cons(tab, 1) < 0)
+			goto error;
+		isl_int_add(bset->ineq[i][0], bset->ineq[i][0], v);
+		ok = isl_tab_add_ineq(tab, bset->ineq[i]) >= 0;
+		isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], v);
+		if (!ok)
+			goto error;
+	}
+
+	isl_mat_free(U);
+	isl_int_clear(v);
+	return 0;
+error:
+	isl_mat_free(U);
+	isl_int_clear(v);
+	return -1;
+}
+
+/* Compute and return an initial basis for the possibly
+ * unbounded tableau "tab".  "tab_cone" is a tableau
+ * for the corresponding recession cone.
+ * Additionally, add constraints to "tab" that ensure
+ * that any rational value for the unbounded directions
+ * can be rounded up to an integer value.
+ *
+ * If the tableau is bounded, i.e., if the recession cone
+ * is zero-dimensional, then we just use inital_basis.
+ * Otherwise, we construct a basis whose first directions
+ * correspond to equalities, followed by bounded directions,
+ * i.e., equalities in the recession cone.
+ * The remaining directions are then unbounded.
+ */
+int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone)
+{
+	struct isl_mat *eq;
+	struct isl_mat *cone_eq;
+	struct isl_mat *U, *Q;
+
+	if (!tab || !tab_cone)
+		return -1;
+
+	if (tab_cone->n_col == tab_cone->n_dead) {
+		tab->basis = initial_basis(tab);
+		return tab->basis ? 0 : -1;
+	}
+
+	eq = tab_equalities(tab);
+	if (!eq)
+		return -1;
+	tab->n_zero = eq->n_row;
+	cone_eq = tab_equalities(tab_cone);
+	eq = isl_mat_concat(eq, cone_eq);
+	if (!eq)
+		return -1;
+	tab->n_unbounded = tab->n_var - (eq->n_row - tab->n_zero);
+	eq = isl_mat_left_hermite(eq, 0, &U, &Q);
+	if (!eq)
+		return -1;
+	isl_mat_free(eq);
+	tab->basis = isl_mat_lin_to_aff(Q);
+	if (tab_shift_cone(tab, tab_cone, U) < 0)
+		return -1;
+	if (!tab->basis)
+		return -1;
+	return 0;
+}
+
+/* Compute and return a sample point in bset using generalized basis
+ * reduction.  We first check if the input set has a non-trivial
+ * recession cone.  If so, we perform some extra preprocessing in
+ * sample_with_cone.  Otherwise, we directly perform generalized basis
+ * reduction.
+ */
+static struct isl_vec *gbr_sample(struct isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_basic_set *cone;
+
+	dim = isl_basic_set_total_dim(bset);
+
+	cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset));
+	if (!cone)
+		goto error;
+
+	if (cone->n_eq < dim)
+		return isl_basic_set_sample_with_cone(bset, cone);
+
+	isl_basic_set_free(cone);
+	return sample_bounded(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static struct isl_vec *basic_set_sample(struct isl_basic_set *bset, int bounded)
+{
+	struct isl_ctx *ctx;
+	unsigned dim;
+	if (!bset)
+		return NULL;
+
+	ctx = bset->ctx;
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+
+	dim = isl_basic_set_n_dim(bset);
+	isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(ctx, bset->n_div == 0, goto error);
+
+	if (bset->sample && bset->sample->size == 1 + dim) {
+		int contains = isl_basic_set_contains(bset, bset->sample);
+		if (contains < 0)
+			goto error;
+		if (contains) {
+			struct isl_vec *sample = isl_vec_copy(bset->sample);
+			isl_basic_set_free(bset);
+			return sample;
+		}
+	}
+	isl_vec_free(bset->sample);
+	bset->sample = NULL;
+
+	if (bset->n_eq > 0)
+		return sample_eq(bset, bounded ? isl_basic_set_sample_bounded
+					       : isl_basic_set_sample_vec);
+	if (dim == 0)
+		return zero_sample(bset);
+	if (dim == 1)
+		return interval_sample(bset);
+
+	return bounded ? sample_bounded(bset) : gbr_sample(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset)
+{
+	return basic_set_sample(bset, 0);
+}
+
+/* Compute an integer sample in "bset", where the caller guarantees
+ * that "bset" is bounded.
+ */
+struct isl_vec *isl_basic_set_sample_bounded(struct isl_basic_set *bset)
+{
+	return basic_set_sample(bset, 1);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec)
+{
+	int i;
+	int k;
+	struct isl_basic_set *bset = NULL;
+	struct isl_ctx *ctx;
+	unsigned dim;
+
+	if (!vec)
+		return NULL;
+	ctx = vec->ctx;
+	isl_assert(ctx, vec->size != 0, goto error);
+
+	bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0);
+	if (!bset)
+		goto error;
+	dim = isl_basic_set_n_dim(bset);
+	for (i = dim - 1; i >= 0; --i) {
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->eq[k], 1 + dim);
+		isl_int_neg(bset->eq[k][0], vec->el[1 + i]);
+		isl_int_set(bset->eq[k][1 + i], vec->el[0]);
+	}
+	bset->sample = vec;
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset;
+	struct isl_vec *sample_vec;
+
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	sample_vec = isl_basic_set_sample_vec(bset);
+	if (!sample_vec)
+		goto error;
+	if (sample_vec->size == 0) {
+		struct isl_basic_map *sample;
+		sample = isl_basic_map_empty_like(bmap);
+		isl_vec_free(sample_vec);
+		isl_basic_map_free(bmap);
+		return sample;
+	}
+	bset = isl_basic_set_from_vec(sample_vec);
+	return isl_basic_map_overlying_set(bset, bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_sample(bset);
+}
+
+__isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map)
+{
+	int i;
+	isl_basic_map *sample = NULL;
+
+	if (!map)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		sample = isl_basic_map_sample(isl_basic_map_copy(map->p[i]));
+		if (!sample)
+			goto error;
+		if (!ISL_F_ISSET(sample, ISL_BASIC_MAP_EMPTY))
+			break;
+		isl_basic_map_free(sample);
+	}
+	if (i == map->n)
+		sample = isl_basic_map_empty_like_map(map);
+	isl_map_free(map);
+	return sample;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set)
+{
+	return (isl_basic_set *) isl_map_sample((isl_map *)set);
+}
+
+__isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset)
+{
+	isl_vec *vec;
+	isl_space *dim;
+
+	dim = isl_basic_set_get_space(bset);
+	bset = isl_basic_set_underlying_set(bset);
+	vec = isl_basic_set_sample_vec(bset);
+
+	return isl_point_alloc(dim, vec);
+}
+
+__isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set)
+{
+	int i;
+	isl_point *pnt;
+
+	if (!set)
+		return NULL;
+
+	for (i = 0; i < set->n; ++i) {
+		pnt = isl_basic_set_sample_point(isl_basic_set_copy(set->p[i]));
+		if (!pnt)
+			goto error;
+		if (!isl_point_is_void(pnt))
+			break;
+		isl_point_free(pnt);
+	}
+	if (i == set->n)
+		pnt = isl_point_void(isl_set_get_space(set));
+
+	isl_set_free(set);
+	return pnt;
+error:
+	isl_set_free(set);
+	return NULL;
+}

Added: polly/trunk/lib/External/isl/isl_sample.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_sample.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_sample.h (added)
+++ polly/trunk/lib/External/isl/isl_sample.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,35 @@
+/*
+ * 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_SAMPLE_H
+#define ISL_SAMPLE_H
+
+#include <isl/set.h>
+#include <isl_tab.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset);
+struct isl_vec *isl_basic_set_sample_bounded(struct isl_basic_set *bset);
+__isl_give isl_vec *isl_basic_set_sample_with_cone(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone);
+
+__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec);
+
+int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone);
+struct isl_vec *isl_tab_sample(struct isl_tab *tab);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

Added: polly/trunk/lib/External/isl/isl_scan.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_scan.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_scan.c (added)
+++ polly/trunk/lib/External/isl/isl_scan.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,324 @@
+/*
+ * 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_basis_reduction.h"
+#include "isl_scan.h"
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+
+struct isl_counter {
+	struct isl_scan_callback callback;
+	isl_int count;
+	isl_int max;
+};
+
+static int increment_counter(struct isl_scan_callback *cb,
+	__isl_take isl_vec *sample)
+{
+	struct isl_counter *cnt = (struct isl_counter *)cb;
+
+	isl_int_add_ui(cnt->count, cnt->count, 1);
+
+	isl_vec_free(sample);
+
+	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
+		return 0;
+	return -1;
+}
+
+static int increment_range(struct isl_scan_callback *cb, isl_int min, isl_int max)
+{
+	struct isl_counter *cnt = (struct isl_counter *)cb;
+
+	isl_int_add(cnt->count, cnt->count, max);
+	isl_int_sub(cnt->count, cnt->count, min);
+	isl_int_add_ui(cnt->count, cnt->count, 1);
+
+	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
+		return 0;
+	isl_int_set(cnt->count, cnt->max);
+	return -1;
+}
+
+/* Call callback->add with the current sample value of the tableau "tab".
+ */
+static int add_solution(struct isl_tab *tab, struct isl_scan_callback *callback)
+{
+	struct isl_vec *sample;
+
+	if (!tab)
+		return -1;
+	sample = isl_tab_get_sample_value(tab);
+	if (!sample)
+		return -1;
+
+	return callback->add(callback, sample);
+}
+
+static int scan_0D(struct isl_basic_set *bset,
+	struct isl_scan_callback *callback)
+{
+	struct isl_vec *sample;
+
+	sample = isl_vec_alloc(bset->ctx, 1);
+	isl_basic_set_free(bset);
+
+	if (!sample)
+		return -1;
+
+	isl_int_set_si(sample->el[0], 1);
+
+	return callback->add(callback, sample);
+}
+
+/* Look for all integer points in "bset", which is assumed to be bounded,
+ * and call callback->add on each of them.
+ *
+ * We first compute a reduced basis for the set and then scan
+ * the set in the directions of this basis.
+ * We basically perform a depth first search, where in each level i
+ * we compute the range in the i-th basis vector direction, given
+ * fixed values in the directions of the previous basis vector.
+ * We then add an equality to the tableau fixing the value in the
+ * direction of the current basis vector to each value in the range
+ * in turn and then continue to the next level.
+ *
+ * The search is implemented iteratively.  "level" identifies the current
+ * basis vector.  "init" is true if we want the first value at the current
+ * level and false if we want the next value.
+ * Solutions are added in the leaves of the search tree, i.e., after
+ * we have fixed a value in each direction of the basis.
+ */
+int isl_basic_set_scan(struct isl_basic_set *bset,
+	struct isl_scan_callback *callback)
+{
+	unsigned dim;
+	struct isl_mat *B = NULL;
+	struct isl_tab *tab = NULL;
+	struct isl_vec *min;
+	struct isl_vec *max;
+	struct isl_tab_undo **snap;
+	int level;
+	int init;
+	enum isl_lp_result res;
+
+	if (!bset)
+		return -1;
+
+	dim = isl_basic_set_total_dim(bset);
+	if (dim == 0)
+		return scan_0D(bset, callback);
+
+	min = isl_vec_alloc(bset->ctx, dim);
+	max = isl_vec_alloc(bset->ctx, dim);
+	snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, dim);
+
+	if (!min || !max || !snap)
+		goto error;
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!tab)
+		goto error;
+	if (isl_tab_extend_cons(tab, dim + 1) < 0)
+		goto error;
+
+	tab->basis = isl_mat_identity(bset->ctx, 1 + dim);
+	if (1)
+		tab = isl_tab_compute_reduced_basis(tab);
+	if (!tab)
+		goto error;
+	B = isl_mat_copy(tab->basis);
+	if (!B)
+		goto error;
+
+	level = 0;
+	init = 1;
+
+	while (level >= 0) {
+		int empty = 0;
+		if (init) {
+			res = isl_tab_min(tab, B->row[1 + level],
+				    bset->ctx->one, &min->el[level], NULL, 0);
+			if (res == isl_lp_empty)
+				empty = 1;
+			if (res == isl_lp_error || res == isl_lp_unbounded)
+				goto error;
+			isl_seq_neg(B->row[1 + level] + 1,
+				    B->row[1 + level] + 1, dim);
+			res = isl_tab_min(tab, B->row[1 + level],
+				    bset->ctx->one, &max->el[level], NULL, 0);
+			isl_seq_neg(B->row[1 + level] + 1,
+				    B->row[1 + level] + 1, dim);
+			isl_int_neg(max->el[level], max->el[level]);
+			if (res == isl_lp_empty)
+				empty = 1;
+			if (res == isl_lp_error || res == isl_lp_unbounded)
+				goto error;
+			snap[level] = isl_tab_snap(tab);
+		} else
+			isl_int_add_ui(min->el[level], min->el[level], 1);
+
+		if (empty || isl_int_gt(min->el[level], max->el[level])) {
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		if (level == dim - 1 && callback->add == increment_counter) {
+			if (increment_range(callback,
+					    min->el[level], max->el[level]))
+				goto error;
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		isl_int_neg(B->row[1 + level][0], min->el[level]);
+		if (isl_tab_add_valid_eq(tab, B->row[1 + level]) < 0)
+			goto error;
+		isl_int_set_si(B->row[1 + level][0], 0);
+		if (level < dim - 1) {
+			++level;
+			init = 1;
+			continue;
+		}
+		if (add_solution(tab, callback) < 0)
+			goto error;
+		init = 0;
+		if (isl_tab_rollback(tab, snap[level]) < 0)
+			goto error;
+	}
+
+	isl_tab_free(tab);
+	free(snap);
+	isl_vec_free(min);
+	isl_vec_free(max);
+	isl_basic_set_free(bset);
+	isl_mat_free(B);
+	return 0;
+error:
+	isl_tab_free(tab);
+	free(snap);
+	isl_vec_free(min);
+	isl_vec_free(max);
+	isl_basic_set_free(bset);
+	isl_mat_free(B);
+	return -1;
+}
+
+int isl_set_scan(__isl_take isl_set *set, struct isl_scan_callback *callback)
+{
+	int i;
+
+	if (!set || !callback)
+		goto error;
+
+	set = isl_set_cow(set);
+	set = isl_set_make_disjoint(set);
+	set = isl_set_compute_divs(set);
+	if (!set)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
+					callback) < 0)
+			goto error;
+
+	isl_set_free(set);
+	return 0;
+error:
+	isl_set_free(set);
+	return -1;
+}
+
+int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
+	isl_int max, isl_int *count)
+{
+	struct isl_counter cnt = { { &increment_counter } };
+
+	if (!bset)
+		return -1;
+
+	isl_int_init(cnt.count);
+	isl_int_init(cnt.max);
+
+	isl_int_set_si(cnt.count, 0);
+	isl_int_set(cnt.max, max);
+	if (isl_basic_set_scan(isl_basic_set_copy(bset), &cnt.callback) < 0 &&
+	    isl_int_lt(cnt.count, cnt.max))
+		goto error;
+
+	isl_int_set(*count, cnt.count);
+	isl_int_clear(cnt.max);
+	isl_int_clear(cnt.count);
+
+	return 0;
+error:
+	isl_int_clear(cnt.count);
+	return -1;
+}
+
+int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count)
+{
+	struct isl_counter cnt = { { &increment_counter } };
+
+	if (!set)
+		return -1;
+
+	isl_int_init(cnt.count);
+	isl_int_init(cnt.max);
+
+	isl_int_set_si(cnt.count, 0);
+	isl_int_set(cnt.max, max);
+	if (isl_set_scan(isl_set_copy(set), &cnt.callback) < 0 &&
+	    isl_int_lt(cnt.count, cnt.max))
+		goto error;
+
+	isl_int_set(*count, cnt.count);
+	isl_int_clear(cnt.max);
+	isl_int_clear(cnt.count);
+
+	return 0;
+error:
+	isl_int_clear(cnt.count);
+	return -1;
+}
+
+int isl_set_count(__isl_keep isl_set *set, isl_int *count)
+{
+	if (!set)
+		return -1;
+	return isl_set_count_upto(set, set->ctx->zero, count);
+}
+
+/* Count the total number of elements in "set" (in an inefficient way) and
+ * return the result.
+ */
+__isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set)
+{
+	isl_val *v;
+
+	if (!set)
+		return NULL;
+	v = isl_val_zero(isl_set_get_ctx(set));
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	if (isl_set_count(set, &v->n) < 0)
+		v = isl_val_free(v);
+	return v;
+}

Added: polly/trunk/lib/External/isl/isl_scan.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_scan.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_scan.h (added)
+++ polly/trunk/lib/External/isl/isl_scan.h 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
+ */
+
+#ifndef ISL_SCAN_H
+#define ISL_SCAN_H
+
+#include <isl/set.h>
+#include <isl/vec.h>
+
+struct isl_scan_callback {
+	int (*add)(struct isl_scan_callback *cb, __isl_take isl_vec *sample);
+};
+
+int isl_basic_set_scan(struct isl_basic_set *bset,
+	struct isl_scan_callback *callback);
+int isl_set_scan(__isl_take isl_set *set, struct isl_scan_callback *callback);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_schedule.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_schedule.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_schedule.c (added)
+++ polly/trunk/lib/External/isl/isl_schedule.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,672 @@
+/*
+ * 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.h>
+#include <isl_aff_private.h>
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl_sort.h>
+#include <isl_schedule_private.h>
+#include <isl_band_private.h>
+
+__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched)
+{
+	int i;
+	if (!sched)
+		return NULL;
+
+	if (--sched->ref > 0)
+		return NULL;
+
+	for (i = 0; i < sched->n; ++i) {
+		isl_multi_aff_free(sched->node[i].sched);
+		free(sched->node[i].band_end);
+		free(sched->node[i].band_id);
+		free(sched->node[i].coincident);
+	}
+	isl_space_free(sched->dim);
+	isl_band_list_free(sched->band_forest);
+	free(sched);
+	return NULL;
+}
+
+isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule)
+{
+	return schedule ? isl_space_get_ctx(schedule->dim) : NULL;
+}
+
+/* Set max_out to the maximal number of output dimensions over
+ * all maps.
+ */
+static int update_max_out(__isl_take isl_map *map, void *user)
+{
+	int *max_out = user;
+	int n_out = isl_map_dim(map, isl_dim_out);
+
+	if (n_out > *max_out)
+		*max_out = n_out;
+
+	isl_map_free(map);
+	return 0;
+}
+
+/* Internal data structure for map_pad_range.
+ *
+ * "max_out" is the maximal schedule dimension.
+ * "res" collects the results.
+ */
+struct isl_pad_schedule_map_data {
+	int max_out;
+	isl_union_map *res;
+};
+
+/* Pad the range of the given map with zeros to data->max_out and
+ * then add the result to data->res.
+ */
+static int map_pad_range(__isl_take isl_map *map, void *user)
+{
+	struct isl_pad_schedule_map_data *data = user;
+	int i;
+	int n_out = isl_map_dim(map, isl_dim_out);
+
+	map = isl_map_add_dims(map, isl_dim_out, data->max_out - n_out);
+	for (i = n_out; i < data->max_out; ++i)
+		map = isl_map_fix_si(map, isl_dim_out, i, 0);
+
+	data->res = isl_union_map_add_map(data->res, map);
+	if (!data->res)
+		return -1;
+
+	return 0;
+}
+
+/* Pad the ranges of the maps in the union map with zeros such they all have
+ * the same dimension.
+ */
+static __isl_give isl_union_map *pad_schedule_map(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_pad_schedule_map_data data;
+
+	if (!umap)
+		return NULL;
+	if (isl_union_map_n_map(umap) <= 1)
+		return umap;
+
+	data.max_out = 0;
+	if (isl_union_map_foreach_map(umap, &update_max_out, &data.max_out) < 0)
+		return isl_union_map_free(umap);
+
+	data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+	if (isl_union_map_foreach_map(umap, &map_pad_range, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_union_map_free(umap);
+	return data.res;
+}
+
+/* Return an isl_union_map of the schedule.  If we have already constructed
+ * a band forest, then this band forest may have been modified so we need
+ * to extract the isl_union_map from the forest rather than from
+ * the originally computed schedule.  This reconstructed schedule map
+ * then needs to be padded with zeros to unify the schedule space
+ * since the result of isl_band_list_get_suffix_schedule may not have
+ * a unified schedule space.
+ */
+__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
+{
+	int i;
+	isl_union_map *umap;
+
+	if (!sched)
+		return NULL;
+
+	if (sched->band_forest) {
+		umap = isl_band_list_get_suffix_schedule(sched->band_forest);
+		return pad_schedule_map(umap);
+	}
+
+	umap = isl_union_map_empty(isl_space_copy(sched->dim));
+	for (i = 0; i < sched->n; ++i) {
+		isl_multi_aff *ma;
+
+		ma = isl_multi_aff_copy(sched->node[i].sched);
+		umap = isl_union_map_add_map(umap, isl_map_from_multi_aff(ma));
+	}
+
+	return umap;
+}
+
+static __isl_give isl_band_list *construct_band_list(
+	__isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
+	int band_nr, int *parent_active, int n_active);
+
+/* Construct an isl_band structure for the band in the given schedule
+ * with sequence number band_nr for the n_active nodes marked by active.
+ * If the nodes don't have a band with the given sequence number,
+ * then a band without members is created.
+ *
+ * Because of the way the schedule is constructed, we know that
+ * the position of the band inside the schedule of a node is the same
+ * for all active nodes.
+ *
+ * The partial schedule for the band is created before the children
+ * are created to that construct_band_list can refer to the partial
+ * schedule of the parent.
+ */
+static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
+	__isl_keep isl_band *parent,
+	int band_nr, int *active, int n_active)
+{
+	int i, j;
+	isl_ctx *ctx = isl_schedule_get_ctx(schedule);
+	isl_band *band;
+	unsigned start, end;
+
+	band = isl_band_alloc(ctx);
+	if (!band)
+		return NULL;
+
+	band->schedule = schedule;
+	band->parent = parent;
+
+	for (i = 0; i < schedule->n; ++i)
+		if (active[i])
+			break;
+
+	if (i >= schedule->n)
+		isl_die(ctx, isl_error_internal,
+			"band without active statements", goto error);
+
+	start = band_nr ? schedule->node[i].band_end[band_nr - 1] : 0;
+	end = band_nr < schedule->node[i].n_band ?
+		schedule->node[i].band_end[band_nr] : start;
+	band->n = end - start;
+
+	band->coincident = isl_alloc_array(ctx, int, band->n);
+	if (band->n && !band->coincident)
+		goto error;
+
+	for (j = 0; j < band->n; ++j)
+		band->coincident[j] = schedule->node[i].coincident[start + j];
+
+	band->pma = isl_union_pw_multi_aff_empty(isl_space_copy(schedule->dim));
+	for (i = 0; i < schedule->n; ++i) {
+		isl_multi_aff *ma;
+		isl_pw_multi_aff *pma;
+		unsigned n_out;
+
+		if (!active[i])
+			continue;
+
+		ma = isl_multi_aff_copy(schedule->node[i].sched);
+		n_out = isl_multi_aff_dim(ma, isl_dim_out);
+		ma = isl_multi_aff_drop_dims(ma, isl_dim_out, end, n_out - end);
+		ma = isl_multi_aff_drop_dims(ma, isl_dim_out, 0, start);
+		pma = isl_pw_multi_aff_from_multi_aff(ma);
+		band->pma = isl_union_pw_multi_aff_add_pw_multi_aff(band->pma,
+								    pma);
+	}
+	if (!band->pma)
+		goto error;
+
+	for (i = 0; i < schedule->n; ++i)
+		if (active[i] && schedule->node[i].n_band > band_nr + 1)
+			break;
+
+	if (i < schedule->n) {
+		band->children = construct_band_list(schedule, band,
+						band_nr + 1, active, n_active);
+		if (!band->children)
+			goto error;
+	}
+
+	return band;
+error:
+	isl_band_free(band);
+	return NULL;
+}
+
+/* Internal data structure used inside cmp_band and pw_multi_aff_extract_int.
+ *
+ * r is set to a negative value if anything goes wrong.
+ *
+ * c1 stores the result of extract_int.
+ * c2 is a temporary value used inside cmp_band_in_ancestor.
+ * t is a temporary value used inside extract_int.
+ *
+ * first and equal are used inside extract_int.
+ * first is set if we are looking at the first isl_multi_aff inside
+ * the isl_union_pw_multi_aff.
+ * equal is set if all the isl_multi_affs have been equal so far.
+ */
+struct isl_cmp_band_data {
+	int r;
+
+	int first;
+	int equal;
+
+	isl_int t;
+	isl_int c1;
+	isl_int c2;
+};
+
+/* Check if "ma" assigns a constant value.
+ * Note that this function is only called on isl_multi_affs
+ * with a single output dimension.
+ *
+ * If "ma" assigns a constant value then we compare it to data->c1
+ * or assign it to data->c1 if this is the first isl_multi_aff we consider.
+ * If "ma" does not assign a constant value or if it assigns a value
+ * that is different from data->c1, then we set data->equal to zero
+ * and terminate the check.
+ */
+static int multi_aff_extract_int(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma, void *user)
+{
+	isl_aff *aff;
+	struct isl_cmp_band_data *data = user;
+
+	aff = isl_multi_aff_get_aff(ma, 0);
+	data->r = isl_aff_is_cst(aff);
+	if (data->r >= 0 && data->r) {
+		isl_aff_get_constant(aff, &data->t);
+		if (data->first) {
+			isl_int_set(data->c1, data->t);
+			data->first = 0;
+		} else if (!isl_int_eq(data->c1, data->t))
+			data->equal = 0;
+	} else if (data->r >= 0 && !data->r)
+		data->equal = 0;
+
+	isl_aff_free(aff);
+	isl_set_free(set);
+	isl_multi_aff_free(ma);
+
+	if (data->r < 0)
+		return -1;
+	if (!data->equal)
+		return -1;
+	return 0;
+}
+
+/* This function is called for each isl_pw_multi_aff in
+ * the isl_union_pw_multi_aff checked by extract_int.
+ * Check all the isl_multi_affs inside "pma".
+ */
+static int pw_multi_aff_extract_int(__isl_take isl_pw_multi_aff *pma,
+	void *user)
+{
+	int r;
+
+	r = isl_pw_multi_aff_foreach_piece(pma, &multi_aff_extract_int, user);
+	isl_pw_multi_aff_free(pma);
+
+	return r;
+}
+
+/* Check if "upma" assigns a single constant value to its domain.
+ * If so, return 1 and store the result in data->c1.
+ * If not, return 0.
+ *
+ * A negative return value from isl_union_pw_multi_aff_foreach_pw_multi_aff
+ * means that either an error occurred or that we have broken off the check
+ * because we already know the result is going to be negative.
+ * In the latter case, data->equal is set to zero.
+ */
+static int extract_int(__isl_keep isl_union_pw_multi_aff *upma,
+	struct isl_cmp_band_data *data)
+{
+	data->first = 1;
+	data->equal = 1;
+
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+					&pw_multi_aff_extract_int, data) < 0) {
+		if (!data->equal)
+			return 0;
+		return -1;
+	}
+
+	return !data->first && data->equal;
+}
+
+/* Compare "b1" and "b2" based on the parent schedule of their ancestor
+ * "ancestor".
+ *
+ * If the parent of "ancestor" also has a single member, then we
+ * first try to compare the two band based on the partial schedule
+ * of this parent.
+ *
+ * Otherwise, or if the result is inconclusive, we look at the partial schedule
+ * of "ancestor" itself.
+ * In particular, we specialize the parent schedule based
+ * on the domains of the child schedules, check if both assign
+ * a single constant value and, if so, compare the two constant values.
+ * If the specialized parent schedules do not assign a constant value,
+ * then they cannot be used to order the two bands and so in this case
+ * we return 0.
+ */
+static int cmp_band_in_ancestor(__isl_keep isl_band *b1,
+	__isl_keep isl_band *b2, struct isl_cmp_band_data *data,
+	__isl_keep isl_band *ancestor)
+{
+	isl_union_pw_multi_aff *upma;
+	isl_union_set *domain;
+	int r;
+
+	if (data->r < 0)
+		return 0;
+
+	if (ancestor->parent && ancestor->parent->n == 1) {
+		r = cmp_band_in_ancestor(b1, b2, data, ancestor->parent);
+		if (data->r < 0)
+			return 0;
+		if (r)
+			return r;
+	}
+
+	upma = isl_union_pw_multi_aff_copy(b1->pma);
+	domain = isl_union_pw_multi_aff_domain(upma);
+	upma = isl_union_pw_multi_aff_copy(ancestor->pma);
+	upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
+	r = extract_int(upma, data);
+	isl_union_pw_multi_aff_free(upma);
+
+	if (r < 0)
+		data->r = -1;
+	if (r < 0 || !r)
+		return 0;
+
+	isl_int_set(data->c2, data->c1);
+
+	upma = isl_union_pw_multi_aff_copy(b2->pma);
+	domain = isl_union_pw_multi_aff_domain(upma);
+	upma = isl_union_pw_multi_aff_copy(ancestor->pma);
+	upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
+	r = extract_int(upma, data);
+	isl_union_pw_multi_aff_free(upma);
+
+	if (r < 0)
+		data->r = -1;
+	if (r < 0 || !r)
+		return 0;
+
+	return isl_int_cmp(data->c2, data->c1);
+}
+
+/* Compare "a" and "b" based on the parent schedule of their parent.
+ */
+static int cmp_band(const void *a, const void *b, void *user)
+{
+	isl_band *b1 = *(isl_band * const *) a;
+	isl_band *b2 = *(isl_band * const *) b;
+	struct isl_cmp_band_data *data = user;
+
+	return cmp_band_in_ancestor(b1, b2, data, b1->parent);
+}
+
+/* Sort the elements in "list" based on the partial schedules of its parent
+ * (and ancestors).  In particular if the parent assigns constant values
+ * to the domains of the bands in "list", then the elements are sorted
+ * according to that order.
+ * This order should be a more "natural" order for the user, but otherwise
+ * shouldn't have any effect.
+ * If we would be constructing an isl_band forest directly in
+ * isl_schedule_constraints_compute_schedule then there wouldn't be any need
+ * for a reordering, since the children would be added to the list
+ * in their natural order automatically.
+ *
+ * If there is only one element in the list, then there is no need to sort
+ * anything.
+ * If the partial schedule of the parent has more than one member
+ * (or if there is no parent), then it's
+ * defnitely not assigning constant values to the different children in
+ * the list and so we wouldn't be able to use it to sort the list.
+ */
+static __isl_give isl_band_list *sort_band_list(__isl_take isl_band_list *list,
+	__isl_keep isl_band *parent)
+{
+	struct isl_cmp_band_data data;
+
+	if (!list)
+		return NULL;
+	if (list->n <= 1)
+		return list;
+	if (!parent || parent->n != 1)
+		return list;
+
+	data.r = 0;
+	isl_int_init(data.c1);
+	isl_int_init(data.c2);
+	isl_int_init(data.t);
+	isl_sort(list->p, list->n, sizeof(list->p[0]), &cmp_band, &data);
+	if (data.r < 0)
+		list = isl_band_list_free(list);
+	isl_int_clear(data.c1);
+	isl_int_clear(data.c2);
+	isl_int_clear(data.t);
+
+	return list;
+}
+
+/* Construct a list of bands that start at the same position (with
+ * sequence number band_nr) in the schedules of the nodes that
+ * were active in the parent band.
+ *
+ * A separate isl_band structure is created for each band_id
+ * and for each node that does not have a band with sequence
+ * number band_nr.  In the latter case, a band without members
+ * is created.
+ * This ensures that if a band has any children, then each node
+ * that was active in the band is active in exactly one of the children.
+ */
+static __isl_give isl_band_list *construct_band_list(
+	__isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
+	int band_nr, int *parent_active, int n_active)
+{
+	int i, j;
+	isl_ctx *ctx = isl_schedule_get_ctx(schedule);
+	int *active;
+	int n_band;
+	isl_band_list *list;
+
+	n_band = 0;
+	for (i = 0; i < n_active; ++i) {
+		for (j = 0; j < schedule->n; ++j) {
+			if (!parent_active[j])
+				continue;
+			if (schedule->node[j].n_band <= band_nr)
+				continue;
+			if (schedule->node[j].band_id[band_nr] == i) {
+				n_band++;
+				break;
+			}
+		}
+	}
+	for (j = 0; j < schedule->n; ++j)
+		if (schedule->node[j].n_band <= band_nr)
+			n_band++;
+
+	if (n_band == 1) {
+		isl_band *band;
+		list = isl_band_list_alloc(ctx, n_band);
+		band = construct_band(schedule, parent, band_nr,
+					parent_active, n_active);
+		return isl_band_list_add(list, band);
+	}
+
+	active = isl_alloc_array(ctx, int, schedule->n);
+	if (schedule->n && !active)
+		return NULL;
+
+	list = isl_band_list_alloc(ctx, n_band);
+
+	for (i = 0; i < n_active; ++i) {
+		int n = 0;
+		isl_band *band;
+
+		for (j = 0; j < schedule->n; ++j) {
+			active[j] = parent_active[j] &&
+					schedule->node[j].n_band > band_nr &&
+					schedule->node[j].band_id[band_nr] == i;
+			if (active[j])
+				n++;
+		}
+		if (n == 0)
+			continue;
+
+		band = construct_band(schedule, parent, band_nr, active, n);
+
+		list = isl_band_list_add(list, band);
+	}
+	for (i = 0; i < schedule->n; ++i) {
+		isl_band *band;
+		if (!parent_active[i])
+			continue;
+		if (schedule->node[i].n_band > band_nr)
+			continue;
+		for (j = 0; j < schedule->n; ++j)
+			active[j] = j == i;
+		band = construct_band(schedule, parent, band_nr, active, 1);
+		list = isl_band_list_add(list, band);
+	}
+
+	free(active);
+
+	list = sort_band_list(list, parent);
+
+	return list;
+}
+
+/* Construct a band forest representation of the schedule and
+ * return the list of roots.
+ */
+static __isl_give isl_band_list *construct_forest(
+	__isl_keep isl_schedule *schedule)
+{
+	int i;
+	isl_ctx *ctx = isl_schedule_get_ctx(schedule);
+	isl_band_list *forest;
+	int *active;
+
+	active = isl_alloc_array(ctx, int, schedule->n);
+	if (schedule->n && !active)
+		return NULL;
+
+	for (i = 0; i < schedule->n; ++i)
+		active[i] = 1;
+
+	forest = construct_band_list(schedule, NULL, 0, active, schedule->n);
+
+	free(active);
+
+	return forest;
+}
+
+/* Return the roots of a band forest representation of the schedule.
+ */
+__isl_give isl_band_list *isl_schedule_get_band_forest(
+	__isl_keep isl_schedule *schedule)
+{
+	if (!schedule)
+		return NULL;
+	if (!schedule->band_forest)
+		schedule->band_forest = construct_forest(schedule);
+	return isl_band_list_dup(schedule->band_forest);
+}
+
+/* Call "fn" on each band in the schedule in depth-first post-order.
+ */
+int isl_schedule_foreach_band(__isl_keep isl_schedule *sched,
+	int (*fn)(__isl_keep isl_band *band, void *user), void *user)
+{
+	int r;
+	isl_band_list *forest;
+
+	if (!sched)
+		return -1;
+
+	forest = isl_schedule_get_band_forest(sched);
+	r = isl_band_list_foreach_band(forest, fn, user);
+	isl_band_list_free(forest);
+
+	return r;
+}
+
+static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
+	__isl_keep isl_band_list *list);
+
+static __isl_give isl_printer *print_band(__isl_take isl_printer *p,
+	__isl_keep isl_band *band)
+{
+	isl_band_list *children;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_union_pw_multi_aff(p, band->pma);
+	p = isl_printer_end_line(p);
+
+	if (!isl_band_has_children(band))
+		return p;
+
+	children = isl_band_get_children(band);
+
+	p = isl_printer_indent(p, 4);
+	p = print_band_list(p, children);
+	p = isl_printer_indent(p, -4);
+
+	isl_band_list_free(children);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
+	__isl_keep isl_band_list *list)
+{
+	int i, n;
+
+	n = isl_band_list_n_band(list);
+	for (i = 0; i < n; ++i) {
+		isl_band *band;
+		band = isl_band_list_get_band(list, i);
+		p = print_band(p, band);
+		isl_band_free(band);
+	}
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p,
+	__isl_keep isl_schedule *schedule)
+{
+	isl_band_list *forest;
+
+	forest = isl_schedule_get_band_forest(schedule);
+
+	p = print_band_list(p, forest);
+
+	isl_band_list_free(forest);
+
+	return p;
+}
+
+void isl_schedule_dump(__isl_keep isl_schedule *schedule)
+{
+	isl_printer *printer;
+
+	if (!schedule)
+		return;
+
+	printer = isl_printer_to_file(isl_schedule_get_ctx(schedule), stderr);
+	printer = isl_printer_print_schedule(printer, schedule);
+
+	isl_printer_free(printer);
+}

Added: polly/trunk/lib/External/isl/isl_schedule_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_schedule_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_schedule_private.h (added)
+++ polly/trunk/lib/External/isl/isl_schedule_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,44 @@
+#ifndef ISL_SCHEDLUE_PRIVATE_H
+#define ISL_SCHEDLUE_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/schedule.h>
+
+/* The schedule for an individual domain, plus information about the bands
+ * and scheduling dimensions.
+ * In particular, we keep track of the number of bands and for each
+ * band, the starting position of the next band.  The first band starts at
+ * position 0.
+ * For each scheduling dimension, we keep track of whether it satisfies
+ * the coincidence constraints (within its band).
+ */
+struct isl_schedule_node {
+	isl_multi_aff *sched;
+	int	 n_band;
+	int	*band_end;
+	int	*band_id;
+	int	*coincident;
+};
+
+/* Information about the computed schedule.
+ * n is the number of nodes/domains/statements.
+ * n_band is the maximal number of bands.
+ * n_total_row is the number of coordinates of the schedule.
+ * dim contains a description of the parameters.
+ * band_forest points to a band forest representation of the schedule
+ * and may be NULL if the forest hasn't been created yet.
+ */
+struct isl_schedule {
+	int ref;
+
+	int n;
+	int n_band;
+	int n_total_row;
+	isl_space *dim;
+
+	isl_band_list *band_forest;
+
+	struct isl_schedule_node node[1];
+};
+
+#endif

Added: polly/trunk/lib/External/isl/isl_scheduler.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_scheduler.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_scheduler.c (added)
+++ polly/trunk/lib/External/isl/isl_scheduler.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,4148 @@
+/*
+ * 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_space_private.h>
+#include <isl_aff_private.h>
+#include <isl/hash.h>
+#include <isl/constraint.h>
+#include <isl/schedule.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_tab.h>
+#include <isl_dim_map.h>
+#include <isl/map_to_basic_set.h>
+#include <isl_sort.h>
+#include <isl_schedule_private.h>
+#include <isl_options_private.h>
+#include <isl_tarjan.h>
+#include <isl_morph.h>
+
+/*
+ * The scheduling algorithm implemented in this file was inspired by
+ * Bondhugula et al., "Automatic Transformations for Communication-Minimized
+ * Parallelization and Locality Optimization in the Polyhedral Model".
+ */
+
+enum isl_edge_type {
+	isl_edge_validity = 0,
+	isl_edge_first = isl_edge_validity,
+	isl_edge_coincidence,
+	isl_edge_condition,
+	isl_edge_conditional_validity,
+	isl_edge_proximity,
+	isl_edge_last = isl_edge_proximity
+};
+
+/* The constraints that need to be satisfied by a schedule on "domain".
+ *
+ * "validity" constraints map domain elements i to domain elements
+ * that should be scheduled after i.  (Hard constraint)
+ * "proximity" constraints map domain elements i to domains elements
+ * that should be scheduled as early as possible after i (or before i).
+ * (Soft constraint)
+ *
+ * "condition" and "conditional_validity" constraints map possibly "tagged"
+ * domain elements i -> s to "tagged" domain elements j -> t.
+ * The elements of the "conditional_validity" constraints, but without the
+ * tags (i.e., the elements i -> j) are treated as validity constraints,
+ * except that during the construction of a tilable band,
+ * the elements of the "conditional_validity" constraints may be violated
+ * provided that all adjacent elements of the "condition" constraints
+ * are local within the band.
+ * A dependence is local within a band if domain and range are mapped
+ * to the same schedule point by the band.
+ */
+struct isl_schedule_constraints {
+	isl_union_set *domain;
+
+	isl_union_map *constraint[isl_edge_last + 1];
+};
+
+ __isl_give isl_schedule_constraints *isl_schedule_constraints_copy(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	isl_ctx *ctx;
+	isl_schedule_constraints *sc_copy;
+	enum isl_edge_type i;
+
+	ctx = isl_union_set_get_ctx(sc->domain);
+	sc_copy = isl_calloc_type(ctx, struct isl_schedule_constraints);
+	if (!sc_copy)
+		return NULL;
+
+	sc_copy->domain = isl_union_set_copy(sc->domain);
+	if (!sc_copy->domain)
+		return isl_schedule_constraints_free(sc_copy);
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		sc_copy->constraint[i] = isl_union_map_copy(sc->constraint[i]);
+		if (!sc_copy->constraint[i])
+			return isl_schedule_constraints_free(sc_copy);
+	}
+
+	return sc_copy;
+}
+
+
+/* Construct an isl_schedule_constraints object for computing a schedule
+ * on "domain".  The initial object does not impose any constraints.
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain(
+	__isl_take isl_union_set *domain)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_schedule_constraints *sc;
+	isl_union_map *empty;
+	enum isl_edge_type i;
+
+	if (!domain)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(domain);
+	sc = isl_calloc_type(ctx, struct isl_schedule_constraints);
+	if (!sc)
+		goto error;
+
+	space = isl_union_set_get_space(domain);
+	sc->domain = domain;
+	empty = isl_union_map_empty(space);
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		sc->constraint[i] = isl_union_map_copy(empty);
+		if (!sc->constraint[i])
+			sc->domain = isl_union_set_free(sc->domain);
+	}
+	isl_union_map_free(empty);
+
+	if (!sc->domain)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+error:
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Replace the validity constraints of "sc" by "validity".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *validity)
+{
+	if (!sc || !validity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_validity]);
+	sc->constraint[isl_edge_validity] = validity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(validity);
+	return NULL;
+}
+
+/* Replace the coincidence constraints of "sc" by "coincidence".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *coincidence)
+{
+	if (!sc || !coincidence)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_coincidence]);
+	sc->constraint[isl_edge_coincidence] = coincidence;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(coincidence);
+	return NULL;
+}
+
+/* Replace the proximity constraints of "sc" by "proximity".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *proximity)
+{
+	if (!sc || !proximity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_proximity]);
+	sc->constraint[isl_edge_proximity] = proximity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(proximity);
+	return NULL;
+}
+
+/* Replace the conditional validity constraints of "sc" by "condition"
+ * and "validity".
+ */
+__isl_give isl_schedule_constraints *
+isl_schedule_constraints_set_conditional_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *condition,
+	__isl_take isl_union_map *validity)
+{
+	if (!sc || !condition || !validity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_condition]);
+	sc->constraint[isl_edge_condition] = condition;
+	isl_union_map_free(sc->constraint[isl_edge_conditional_validity]);
+	sc->constraint[isl_edge_conditional_validity] = validity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(condition);
+	isl_union_map_free(validity);
+	return NULL;
+}
+
+__isl_null isl_schedule_constraints *isl_schedule_constraints_free(
+	__isl_take isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+
+	if (!sc)
+		return NULL;
+
+	isl_union_set_free(sc->domain);
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		isl_union_map_free(sc->constraint[i]);
+
+	free(sc);
+
+	return NULL;
+}
+
+isl_ctx *isl_schedule_constraints_get_ctx(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return sc ? isl_union_set_get_ctx(sc->domain) : NULL;
+}
+
+void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return;
+
+	fprintf(stderr, "domain: ");
+	isl_union_set_dump(sc->domain);
+	fprintf(stderr, "validity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_validity]);
+	fprintf(stderr, "proximity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_proximity]);
+	fprintf(stderr, "coincidence: ");
+	isl_union_map_dump(sc->constraint[isl_edge_coincidence]);
+	fprintf(stderr, "condition: ");
+	isl_union_map_dump(sc->constraint[isl_edge_condition]);
+	fprintf(stderr, "conditional_validity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_conditional_validity]);
+}
+
+/* Align the parameters of the fields of "sc".
+ */
+static __isl_give isl_schedule_constraints *
+isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc)
+{
+	isl_space *space;
+	enum isl_edge_type i;
+
+	if (!sc)
+		return NULL;
+
+	space = isl_union_set_get_space(sc->domain);
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		space = isl_space_align_params(space,
+				    isl_union_map_get_space(sc->constraint[i]));
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		sc->constraint[i] = isl_union_map_align_params(
+				    sc->constraint[i], isl_space_copy(space));
+		if (!sc->constraint[i])
+			space = isl_space_free(space);
+	}
+	sc->domain = isl_union_set_align_params(sc->domain, space);
+	if (!sc->domain)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+}
+
+/* Return the total number of isl_maps in the constraints of "sc".
+ */
+static __isl_give int isl_schedule_constraints_n_map(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+	int n = 0;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		n += isl_union_map_n_map(sc->constraint[i]);
+
+	return n;
+}
+
+/* Internal information about a node that is used during the construction
+ * of a schedule.
+ * space represents the space in which the domain lives
+ * sched is a matrix representation of the schedule being constructed
+ *	for this node; if compressed is set, then this schedule is
+ *	defined over the compressed domain space
+ * sched_map is an isl_map representation of the same (partial) schedule
+ *	sched_map may be NULL; if compressed is set, then this map
+ *	is defined over the uncompressed domain space
+ * rank is the number of linearly independent rows in the linear part
+ *	of sched
+ * the columns of cmap represent a change of basis for the schedule
+ *	coefficients; the first rank columns span the linear part of
+ *	the schedule rows
+ * cinv is the inverse of cmap.
+ * start is the first variable in the LP problem in the sequences that
+ *	represents the schedule coefficients of this node
+ * nvar is the dimension of the domain
+ * nparam is the number of parameters or 0 if we are not constructing
+ *	a parametric schedule
+ *
+ * If compressed is set, then hull represents the constraints
+ * that were used to derive the compression, while compress and
+ * decompress map the original space to the compressed space and
+ * vice versa.
+ *
+ * scc is the index of SCC (or WCC) this node belongs to
+ *
+ * band contains the band index for each of the rows of the schedule.
+ * band_id is used to differentiate between separate bands at the same
+ * level within the same parent band, i.e., bands that are separated
+ * by the parent band or bands that are independent of each other.
+ * coincident contains a boolean for each of the rows of the schedule,
+ * indicating whether the corresponding scheduling dimension satisfies
+ * the coincidence constraints in the sense that the corresponding
+ * dependence distances are zero.
+ */
+struct isl_sched_node {
+	isl_space *space;
+	int	compressed;
+	isl_set	*hull;
+	isl_multi_aff *compress;
+	isl_multi_aff *decompress;
+	isl_mat *sched;
+	isl_map *sched_map;
+	int	 rank;
+	isl_mat *cmap;
+	isl_mat *cinv;
+	int	 start;
+	int	 nvar;
+	int	 nparam;
+
+	int	 scc;
+
+	int	*band;
+	int	*band_id;
+	int	*coincident;
+};
+
+static int node_has_space(const void *entry, const void *val)
+{
+	struct isl_sched_node *node = (struct isl_sched_node *)entry;
+	isl_space *dim = (isl_space *)val;
+
+	return isl_space_is_equal(node->space, dim);
+}
+
+/* An edge in the dependence graph.  An edge may be used to
+ * ensure validity of the generated schedule, to minimize the dependence
+ * distance or both
+ *
+ * map is the dependence relation, with i -> j in the map if j depends on i
+ * tagged_condition and tagged_validity contain the union of all tagged
+ *	condition or conditional validity dependence relations that
+ *	specialize the dependence relation "map"; that is,
+ *	if (i -> a) -> (j -> b) is an element of "tagged_condition"
+ *	or "tagged_validity", then i -> j is an element of "map".
+ *	If these fields are NULL, then they represent the empty relation.
+ * src is the source node
+ * dst is the sink node
+ * validity is set if the edge is used to ensure correctness
+ * coincidence is used to enforce zero dependence distances
+ * proximity is set if the edge is used to minimize dependence distances
+ * condition is set if the edge represents a condition
+ *	for a conditional validity schedule constraint
+ * local can only be set for condition edges and indicates that
+ *	the dependence distance over the edge should be zero
+ * conditional_validity is set if the edge is used to conditionally
+ *	ensure correctness
+ *
+ * For validity edges, start and end mark the sequence of inequality
+ * constraints in the LP problem that encode the validity constraint
+ * corresponding to this edge.
+ */
+struct isl_sched_edge {
+	isl_map *map;
+	isl_union_map *tagged_condition;
+	isl_union_map *tagged_validity;
+
+	struct isl_sched_node *src;
+	struct isl_sched_node *dst;
+
+	unsigned validity : 1;
+	unsigned coincidence : 1;
+	unsigned proximity : 1;
+	unsigned local : 1;
+	unsigned condition : 1;
+	unsigned conditional_validity : 1;
+
+	int start;
+	int end;
+};
+
+/* Internal information about the dependence graph used during
+ * the construction of the schedule.
+ *
+ * intra_hmap is a cache, mapping dependence relations to their dual,
+ *	for dependences from a node to itself
+ * inter_hmap is a cache, mapping dependence relations to their dual,
+ *	for dependences between distinct nodes
+ * if compression is involved then the key for these maps
+ * it the original, uncompressed dependence relation, while
+ * the value is the dual of the compressed dependence relation.
+ *
+ * n is the number of nodes
+ * node is the list of nodes
+ * maxvar is the maximal number of variables over all nodes
+ * max_row is the allocated number of rows in the schedule
+ * n_row is the current (maximal) number of linearly independent
+ *	rows in the node schedules
+ * n_total_row is the current number of rows in the node schedules
+ * n_band is the current number of completed bands
+ * band_start is the starting row in the node schedules of the current band
+ * root is set if this graph is the original dependence graph,
+ *	without any splitting
+ *
+ * sorted contains a list of node indices sorted according to the
+ *	SCC to which a node belongs
+ *
+ * n_edge is the number of edges
+ * edge is the list of edges
+ * max_edge contains the maximal number of edges of each type;
+ *	in particular, it contains the number of edges in the inital graph.
+ * edge_table contains pointers into the edge array, hashed on the source
+ *	and sink spaces; there is one such table for each type;
+ *	a given edge may be referenced from more than one table
+ *	if the corresponding relation appears in more than of the
+ *	sets of dependences
+ *
+ * node_table contains pointers into the node array, hashed on the space
+ *
+ * region contains a list of variable sequences that should be non-trivial
+ *
+ * lp contains the (I)LP problem used to obtain new schedule rows
+ *
+ * src_scc and dst_scc are the source and sink SCCs of an edge with
+ *	conflicting constraints
+ *
+ * scc represents the number of components
+ */
+struct isl_sched_graph {
+	isl_map_to_basic_set *intra_hmap;
+	isl_map_to_basic_set *inter_hmap;
+
+	struct isl_sched_node *node;
+	int n;
+	int maxvar;
+	int max_row;
+	int n_row;
+
+	int *sorted;
+
+	int n_band;
+	int n_total_row;
+	int band_start;
+
+	int root;
+
+	struct isl_sched_edge *edge;
+	int n_edge;
+	int max_edge[isl_edge_last + 1];
+	struct isl_hash_table *edge_table[isl_edge_last + 1];
+
+	struct isl_hash_table *node_table;
+	struct isl_region *region;
+
+	isl_basic_set *lp;
+
+	int src_scc;
+	int dst_scc;
+
+	int scc;
+};
+
+/* Initialize node_table based on the list of nodes.
+ */
+static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	graph->node_table = isl_hash_table_alloc(ctx, graph->n);
+	if (!graph->node_table)
+		return -1;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_hash_table_entry *entry;
+		uint32_t hash;
+
+		hash = isl_space_get_hash(graph->node[i].space);
+		entry = isl_hash_table_find(ctx, graph->node_table, hash,
+					    &node_has_space,
+					    graph->node[i].space, 1);
+		if (!entry)
+			return -1;
+		entry->data = &graph->node[i];
+	}
+
+	return 0;
+}
+
+/* Return a pointer to the node that lives within the given space,
+ * or NULL if there is no such node.
+ */
+static struct isl_sched_node *graph_find_node(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_keep isl_space *dim)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t hash;
+
+	hash = isl_space_get_hash(dim);
+	entry = isl_hash_table_find(ctx, graph->node_table, hash,
+				    &node_has_space, dim, 0);
+
+	return entry ? entry->data : NULL;
+}
+
+static int edge_has_src_and_dst(const void *entry, const void *val)
+{
+	const struct isl_sched_edge *edge = entry;
+	const struct isl_sched_edge *temp = val;
+
+	return edge->src == temp->src && edge->dst == temp->dst;
+}
+
+/* Add the given edge to graph->edge_table[type].
+ */
+static int graph_edge_table_add(isl_ctx *ctx, struct isl_sched_graph *graph,
+	enum isl_edge_type type, struct isl_sched_edge *edge)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t hash;
+
+	hash = isl_hash_init();
+	hash = isl_hash_builtin(hash, edge->src);
+	hash = isl_hash_builtin(hash, edge->dst);
+	entry = isl_hash_table_find(ctx, graph->edge_table[type], hash,
+				    &edge_has_src_and_dst, edge, 1);
+	if (!entry)
+		return -1;
+	entry->data = edge;
+
+	return 0;
+}
+
+/* Allocate the edge_tables based on the maximal number of edges of
+ * each type.
+ */
+static int graph_init_edge_tables(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i <= isl_edge_last; ++i) {
+		graph->edge_table[i] = isl_hash_table_alloc(ctx,
+							    graph->max_edge[i]);
+		if (!graph->edge_table[i])
+			return -1;
+	}
+
+	return 0;
+}
+
+/* If graph->edge_table[type] contains an edge from the given source
+ * to the given destination, then return the hash table entry of this edge.
+ * Otherwise, return NULL.
+ */
+static struct isl_hash_table_entry *graph_find_edge_entry(
+	struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	isl_ctx *ctx = isl_space_get_ctx(src->space);
+	uint32_t hash;
+	struct isl_sched_edge temp = { .src = src, .dst = dst };
+
+	hash = isl_hash_init();
+	hash = isl_hash_builtin(hash, temp.src);
+	hash = isl_hash_builtin(hash, temp.dst);
+	return isl_hash_table_find(ctx, graph->edge_table[type], hash,
+				    &edge_has_src_and_dst, &temp, 0);
+}
+
+
+/* If graph->edge_table[type] contains an edge from the given source
+ * to the given destination, then return this edge.
+ * Otherwise, return NULL.
+ */
+static struct isl_sched_edge *graph_find_edge(struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	struct isl_hash_table_entry *entry;
+
+	entry = graph_find_edge_entry(graph, type, src, dst);
+	if (!entry)
+		return NULL;
+
+	return entry->data;
+}
+
+/* Check whether the dependence graph has an edge of the given type
+ * between the given two nodes.
+ */
+static int graph_has_edge(struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	struct isl_sched_edge *edge;
+	int empty;
+
+	edge = graph_find_edge(graph, type, src, dst);
+	if (!edge)
+		return 0;
+
+	empty = isl_map_plain_is_empty(edge->map);
+	if (empty < 0)
+		return -1;
+
+	return !empty;
+}
+
+/* Look for any edge with the same src, dst and map fields as "model".
+ *
+ * Return the matching edge if one can be found.
+ * Return "model" if no matching edge is found.
+ * Return NULL on error.
+ */
+static struct isl_sched_edge *graph_find_matching_edge(
+	struct isl_sched_graph *graph, struct isl_sched_edge *model)
+{
+	enum isl_edge_type i;
+	struct isl_sched_edge *edge;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		int is_equal;
+
+		edge = graph_find_edge(graph, i, model->src, model->dst);
+		if (!edge)
+			continue;
+		is_equal = isl_map_plain_is_equal(model->map, edge->map);
+		if (is_equal < 0)
+			return NULL;
+		if (is_equal)
+			return edge;
+	}
+
+	return model;
+}
+
+/* Remove the given edge from all the edge_tables that refer to it.
+ */
+static void graph_remove_edge(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	isl_ctx *ctx = isl_map_get_ctx(edge->map);
+	enum isl_edge_type i;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		struct isl_hash_table_entry *entry;
+
+		entry = graph_find_edge_entry(graph, i, edge->src, edge->dst);
+		if (!entry)
+			continue;
+		if (entry->data != edge)
+			continue;
+		isl_hash_table_remove(ctx, graph->edge_table[i], entry);
+	}
+}
+
+/* Check whether the dependence graph has any edge
+ * between the given two nodes.
+ */
+static int graph_has_any_edge(struct isl_sched_graph *graph,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	enum isl_edge_type i;
+	int r;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		r = graph_has_edge(graph, i, src, dst);
+		if (r < 0 || r)
+			return r;
+	}
+
+	return r;
+}
+
+/* Check whether the dependence graph has a validity edge
+ * between the given two nodes.
+ *
+ * Conditional validity edges are essentially validity edges that
+ * can be ignored if the corresponding condition edges are iteration private.
+ * Here, we are only checking for the presence of validity
+ * edges, so we need to consider the conditional validity edges too.
+ * In particular, this function is used during the detection
+ * of strongly connected components and we cannot ignore
+ * conditional validity edges during this detection.
+ */
+static int graph_has_validity_edge(struct isl_sched_graph *graph,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	int r;
+
+	r = graph_has_edge(graph, isl_edge_validity, src, dst);
+	if (r < 0 || r)
+		return r;
+
+	return graph_has_edge(graph, isl_edge_conditional_validity, src, dst);
+}
+
+static int graph_alloc(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int n_node, int n_edge)
+{
+	int i;
+
+	graph->n = n_node;
+	graph->n_edge = n_edge;
+	graph->node = isl_calloc_array(ctx, struct isl_sched_node, graph->n);
+	graph->sorted = isl_calloc_array(ctx, int, graph->n);
+	graph->region = isl_alloc_array(ctx, struct isl_region, graph->n);
+	graph->edge = isl_calloc_array(ctx,
+					struct isl_sched_edge, graph->n_edge);
+
+	graph->intra_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge);
+	graph->inter_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge);
+
+	if (!graph->node || !graph->region || (graph->n_edge && !graph->edge) ||
+	    !graph->sorted)
+		return -1;
+
+	for(i = 0; i < graph->n; ++i)
+		graph->sorted[i] = i;
+
+	return 0;
+}
+
+static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	isl_map_to_basic_set_free(graph->intra_hmap);
+	isl_map_to_basic_set_free(graph->inter_hmap);
+
+	if (graph->node)
+		for (i = 0; i < graph->n; ++i) {
+			isl_space_free(graph->node[i].space);
+			isl_set_free(graph->node[i].hull);
+			isl_multi_aff_free(graph->node[i].compress);
+			isl_multi_aff_free(graph->node[i].decompress);
+			isl_mat_free(graph->node[i].sched);
+			isl_map_free(graph->node[i].sched_map);
+			isl_mat_free(graph->node[i].cmap);
+			isl_mat_free(graph->node[i].cinv);
+			if (graph->root) {
+				free(graph->node[i].band);
+				free(graph->node[i].band_id);
+				free(graph->node[i].coincident);
+			}
+		}
+	free(graph->node);
+	free(graph->sorted);
+	if (graph->edge)
+		for (i = 0; i < graph->n_edge; ++i) {
+			isl_map_free(graph->edge[i].map);
+			isl_union_map_free(graph->edge[i].tagged_condition);
+			isl_union_map_free(graph->edge[i].tagged_validity);
+		}
+	free(graph->edge);
+	free(graph->region);
+	for (i = 0; i <= isl_edge_last; ++i)
+		isl_hash_table_free(ctx, graph->edge_table[i]);
+	isl_hash_table_free(ctx, graph->node_table);
+	isl_basic_set_free(graph->lp);
+}
+
+/* For each "set" on which this function is called, increment
+ * graph->n by one and update graph->maxvar.
+ */
+static int init_n_maxvar(__isl_take isl_set *set, void *user)
+{
+	struct isl_sched_graph *graph = user;
+	int nvar = isl_set_dim(set, isl_dim_set);
+
+	graph->n++;
+	if (nvar > graph->maxvar)
+		graph->maxvar = nvar;
+
+	isl_set_free(set);
+
+	return 0;
+}
+
+/* Add the number of basic maps in "map" to *n.
+ */
+static int add_n_basic_map(__isl_take isl_map *map, void *user)
+{
+	int *n = user;
+
+	*n += isl_map_n_basic_map(map);
+	isl_map_free(map);
+
+	return 0;
+}
+
+/* Compute the number of rows that should be allocated for the schedule.
+ * The graph can be split at most "n - 1" times, there can be at most
+ * one row for each dimension in the iteration domains plus two rows
+ * for each basic map in the dependences (in particular,
+ * we usually have one row, but it may be split by split_scaled),
+ * and there can be one extra row for ordering the statements.
+ * Note that if we have actually split "n - 1" times, then no ordering
+ * is needed, so in principle we could use "graph->n + 2 * graph->maxvar - 1".
+ * It is also practically impossible to exhaust both the number of dependences
+ * and the number of variables.
+ */
+static int compute_max_row(struct isl_sched_graph *graph,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+	int n_edge;
+
+	graph->n = 0;
+	graph->maxvar = 0;
+	if (isl_union_set_foreach_set(sc->domain, &init_n_maxvar, graph) < 0)
+		return -1;
+	n_edge = 0;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		if (isl_union_map_foreach_map(sc->constraint[i],
+						&add_n_basic_map, &n_edge) < 0)
+			return -1;
+	graph->max_row = graph->n + 2 * n_edge + graph->maxvar;
+
+	return 0;
+}
+
+/* Does "bset" have any defining equalities for its set variables?
+ */
+static int has_any_defining_equality(__isl_keep isl_basic_set *bset)
+{
+	int i, n;
+
+	if (!bset)
+		return -1;
+
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		int has;
+
+		has = isl_basic_set_has_defining_equality(bset, isl_dim_set, i,
+							NULL);
+		if (has < 0 || has)
+			return has;
+	}
+
+	return 0;
+}
+
+/* Add a new node to the graph representing the given space.
+ * "nvar" is the (possibly compressed) number of variables and
+ * may be smaller than then number of set variables in "space"
+ * if "compressed" is set.
+ * If "compressed" is set, then "hull" represents the constraints
+ * that were used to derive the compression, while "compress" and
+ * "decompress" map the original space to the compressed space and
+ * vice versa.
+ * If "compressed" is not set, then "hull", "compress" and "decompress"
+ * should be NULL.
+ */
+static int add_node(struct isl_sched_graph *graph, __isl_take isl_space *space,
+	int nvar, int compressed, __isl_take isl_set *hull,
+	__isl_take isl_multi_aff *compress,
+	__isl_take isl_multi_aff *decompress)
+{
+	int nparam;
+	isl_ctx *ctx;
+	isl_mat *sched;
+	int *band, *band_id, *coincident;
+
+	if (!space)
+		return -1;
+
+	ctx = isl_space_get_ctx(space);
+	nparam = isl_space_dim(space, isl_dim_param);
+	if (!ctx->opt->schedule_parametric)
+		nparam = 0;
+	sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar);
+	graph->node[graph->n].space = space;
+	graph->node[graph->n].nvar = nvar;
+	graph->node[graph->n].nparam = nparam;
+	graph->node[graph->n].sched = sched;
+	graph->node[graph->n].sched_map = NULL;
+	band = isl_alloc_array(ctx, int, graph->max_row);
+	graph->node[graph->n].band = band;
+	band_id = isl_calloc_array(ctx, int, graph->max_row);
+	graph->node[graph->n].band_id = band_id;
+	coincident = isl_calloc_array(ctx, int, graph->max_row);
+	graph->node[graph->n].coincident = coincident;
+	graph->node[graph->n].compressed = compressed;
+	graph->node[graph->n].hull = hull;
+	graph->node[graph->n].compress = compress;
+	graph->node[graph->n].decompress = decompress;
+	graph->n++;
+
+	if (!space || !sched ||
+	    (graph->max_row && (!band || !band_id || !coincident)))
+		return -1;
+	if (compressed && (!hull || !compress || !decompress))
+		return -1;
+
+	return 0;
+}
+
+/* Add a new node to the graph representing the given set.
+ *
+ * If any of the set variables is defined by an equality, then
+ * we perform variable compression such that we can perform
+ * the scheduling on the compressed domain.
+ */
+static int extract_node(__isl_take isl_set *set, void *user)
+{
+	int nvar;
+	int has_equality;
+	isl_space *space;
+	isl_basic_set *hull;
+	isl_set *hull_set;
+	isl_morph *morph;
+	isl_multi_aff *compress, *decompress;
+	struct isl_sched_graph *graph = user;
+
+	space = isl_set_get_space(set);
+	hull = isl_set_affine_hull(set);
+	hull = isl_basic_set_remove_divs(hull);
+	nvar = isl_space_dim(space, isl_dim_set);
+	has_equality = has_any_defining_equality(hull);
+
+	if (has_equality < 0)
+		goto error;
+	if (!has_equality) {
+		isl_basic_set_free(hull);
+		return add_node(graph, space, nvar, 0, NULL, NULL, NULL);
+	}
+
+	morph = isl_basic_set_variable_compression(hull, isl_dim_set);
+	nvar = isl_morph_ran_dim(morph, isl_dim_set);
+	compress = isl_morph_get_var_multi_aff(morph);
+	morph = isl_morph_inverse(morph);
+	decompress = isl_morph_get_var_multi_aff(morph);
+	isl_morph_free(morph);
+
+	hull_set = isl_set_from_basic_set(hull);
+	return add_node(graph, space, nvar, 1, hull_set, compress, decompress);
+error:
+	isl_basic_set_free(hull);
+	isl_space_free(space);
+	return -1;
+}
+
+struct isl_extract_edge_data {
+	enum isl_edge_type type;
+	struct isl_sched_graph *graph;
+};
+
+/* Merge edge2 into edge1, freeing the contents of edge2.
+ * "type" is the type of the schedule constraint from which edge2 was
+ * extracted.
+ * Return 0 on success and -1 on failure.
+ *
+ * edge1 and edge2 are assumed to have the same value for the map field.
+ */
+static int merge_edge(enum isl_edge_type type, struct isl_sched_edge *edge1,
+	struct isl_sched_edge *edge2)
+{
+	edge1->validity |= edge2->validity;
+	edge1->coincidence |= edge2->coincidence;
+	edge1->proximity |= edge2->proximity;
+	edge1->condition |= edge2->condition;
+	edge1->conditional_validity |= edge2->conditional_validity;
+	isl_map_free(edge2->map);
+
+	if (type == isl_edge_condition) {
+		if (!edge1->tagged_condition)
+			edge1->tagged_condition = edge2->tagged_condition;
+		else
+			edge1->tagged_condition =
+				isl_union_map_union(edge1->tagged_condition,
+						    edge2->tagged_condition);
+	}
+
+	if (type == isl_edge_conditional_validity) {
+		if (!edge1->tagged_validity)
+			edge1->tagged_validity = edge2->tagged_validity;
+		else
+			edge1->tagged_validity =
+				isl_union_map_union(edge1->tagged_validity,
+						    edge2->tagged_validity);
+	}
+
+	if (type == isl_edge_condition && !edge1->tagged_condition)
+		return -1;
+	if (type == isl_edge_conditional_validity && !edge1->tagged_validity)
+		return -1;
+
+	return 0;
+}
+
+/* Insert dummy tags in domain and range of "map".
+ *
+ * In particular, if "map" is of the form
+ *
+ *	A -> B
+ *
+ * then return
+ *
+ *	[A -> dummy_tag] -> [B -> dummy_tag]
+ *
+ * where the dummy_tags are identical and equal to any dummy tags
+ * introduced by any other call to this function.
+ */
+static __isl_give isl_map *insert_dummy_tags(__isl_take isl_map *map)
+{
+	static char dummy;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_space *space;
+	isl_set *domain, *range;
+
+	ctx = isl_map_get_ctx(map);
+
+	id = isl_id_alloc(ctx, NULL, &dummy);
+	space = isl_space_params(isl_map_get_space(map));
+	space = isl_space_set_from_params(space);
+	space = isl_space_set_tuple_id(space, isl_dim_set, id);
+	space = isl_space_map_from_set(space);
+
+	domain = isl_map_wrap(map);
+	range = isl_map_wrap(isl_map_universe(space));
+	map = isl_map_from_domain_and_range(domain, range);
+	map = isl_map_zip(map);
+
+	return map;
+}
+
+/* Given that at least one of "src" or "dst" is compressed, return
+ * a map between the spaces of these nodes restricted to the affine
+ * hull that was used in the compression.
+ */
+static __isl_give isl_map *extract_hull(struct isl_sched_node *src,
+	struct isl_sched_node *dst)
+{
+	isl_set *dom, *ran;
+
+	if (src->compressed)
+		dom = isl_set_copy(src->hull);
+	else
+		dom = isl_set_universe(isl_space_copy(src->space));
+	if (dst->compressed)
+		ran = isl_set_copy(dst->hull);
+	else
+		ran = isl_set_universe(isl_space_copy(dst->space));
+
+	return isl_map_from_domain_and_range(dom, ran);
+}
+
+/* Intersect the domains of the nested relations in domain and range
+ * of "tagged" with "map".
+ */
+static __isl_give isl_map *map_intersect_domains(__isl_take isl_map *tagged,
+	__isl_keep isl_map *map)
+{
+	isl_set *set;
+
+	tagged = isl_map_zip(tagged);
+	set = isl_map_wrap(isl_map_copy(map));
+	tagged = isl_map_intersect_domain(tagged, set);
+	tagged = isl_map_zip(tagged);
+	return tagged;
+}
+
+/* Add a new edge to the graph based on the given map
+ * and add it to data->graph->edge_table[data->type].
+ * If a dependence relation of a given type happens to be identical
+ * to one of the dependence relations of a type that was added before,
+ * then we don't create a new edge, but instead mark the original edge
+ * as also representing a dependence of the current type.
+ *
+ * Edges of type isl_edge_condition or isl_edge_conditional_validity
+ * may be specified as "tagged" dependence relations.  That is, "map"
+ * may contain elements (i -> a) -> (j -> b), where i -> j denotes
+ * the dependence on iterations and a and b are tags.
+ * edge->map is set to the relation containing the elements i -> j,
+ * while edge->tagged_condition and edge->tagged_validity contain
+ * the union of all the "map" relations
+ * for which extract_edge is called that result in the same edge->map.
+ *
+ * If the source or the destination node is compressed, then
+ * intersect both "map" and "tagged" with the constraints that
+ * were used to construct the compression.
+ * This ensures that there are no schedule constraints defined
+ * outside of these domains, while the scheduler no longer has
+ * any control over those outside parts.
+ */
+static int extract_edge(__isl_take isl_map *map, void *user)
+{
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	struct isl_extract_edge_data *data = user;
+	struct isl_sched_graph *graph = data->graph;
+	struct isl_sched_node *src, *dst;
+	isl_space *dim;
+	struct isl_sched_edge *edge;
+	isl_map *tagged = NULL;
+
+	if (data->type == isl_edge_condition ||
+	    data->type == isl_edge_conditional_validity) {
+		if (isl_map_can_zip(map)) {
+			tagged = isl_map_copy(map);
+			map = isl_set_unwrap(isl_map_domain(isl_map_zip(map)));
+		} else {
+			tagged = insert_dummy_tags(isl_map_copy(map));
+		}
+	}
+
+	dim = isl_space_domain(isl_map_get_space(map));
+	src = graph_find_node(ctx, graph, dim);
+	isl_space_free(dim);
+	dim = isl_space_range(isl_map_get_space(map));
+	dst = graph_find_node(ctx, graph, dim);
+	isl_space_free(dim);
+
+	if (!src || !dst) {
+		isl_map_free(map);
+		isl_map_free(tagged);
+		return 0;
+	}
+
+	if (src->compressed || dst->compressed) {
+		isl_map *hull;
+		hull = extract_hull(src, dst);
+		if (tagged)
+			tagged = map_intersect_domains(tagged, hull);
+		map = isl_map_intersect(map, hull);
+	}
+
+	graph->edge[graph->n_edge].src = src;
+	graph->edge[graph->n_edge].dst = dst;
+	graph->edge[graph->n_edge].map = map;
+	graph->edge[graph->n_edge].validity = 0;
+	graph->edge[graph->n_edge].coincidence = 0;
+	graph->edge[graph->n_edge].proximity = 0;
+	graph->edge[graph->n_edge].condition = 0;
+	graph->edge[graph->n_edge].local = 0;
+	graph->edge[graph->n_edge].conditional_validity = 0;
+	graph->edge[graph->n_edge].tagged_condition = NULL;
+	graph->edge[graph->n_edge].tagged_validity = NULL;
+	if (data->type == isl_edge_validity)
+		graph->edge[graph->n_edge].validity = 1;
+	if (data->type == isl_edge_coincidence)
+		graph->edge[graph->n_edge].coincidence = 1;
+	if (data->type == isl_edge_proximity)
+		graph->edge[graph->n_edge].proximity = 1;
+	if (data->type == isl_edge_condition) {
+		graph->edge[graph->n_edge].condition = 1;
+		graph->edge[graph->n_edge].tagged_condition =
+					isl_union_map_from_map(tagged);
+	}
+	if (data->type == isl_edge_conditional_validity) {
+		graph->edge[graph->n_edge].conditional_validity = 1;
+		graph->edge[graph->n_edge].tagged_validity =
+					isl_union_map_from_map(tagged);
+	}
+
+	edge = graph_find_matching_edge(graph, &graph->edge[graph->n_edge]);
+	if (!edge) {
+		graph->n_edge++;
+		return -1;
+	}
+	if (edge == &graph->edge[graph->n_edge])
+		return graph_edge_table_add(ctx, graph, data->type,
+				    &graph->edge[graph->n_edge++]);
+
+	if (merge_edge(data->type, edge, &graph->edge[graph->n_edge]) < 0)
+		return -1;
+
+	return graph_edge_table_add(ctx, graph, data->type, edge);
+}
+
+/* Check whether there is any dependence from node[j] to node[i]
+ * or from node[i] to node[j].
+ */
+static int node_follows_weak(int i, int j, void *user)
+{
+	int f;
+	struct isl_sched_graph *graph = user;
+
+	f = graph_has_any_edge(graph, &graph->node[j], &graph->node[i]);
+	if (f < 0 || f)
+		return f;
+	return graph_has_any_edge(graph, &graph->node[i], &graph->node[j]);
+}
+
+/* Check whether there is a (conditional) validity dependence from node[j]
+ * to node[i], forcing node[i] to follow node[j].
+ */
+static int node_follows_strong(int i, int j, void *user)
+{
+	struct isl_sched_graph *graph = user;
+
+	return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]);
+}
+
+/* Use Tarjan's algorithm for computing the strongly connected components
+ * in the dependence graph (only validity edges).
+ * If weak is set, we consider the graph to be undirected and
+ * we effectively compute the (weakly) connected components.
+ * Additionally, we also consider other edges when weak is set.
+ */
+static int detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, int weak)
+{
+	int i, n;
+	struct isl_tarjan_graph *g = NULL;
+
+	g = isl_tarjan_graph_init(ctx, graph->n,
+		weak ? &node_follows_weak : &node_follows_strong, graph);
+	if (!g)
+		return -1;
+
+	graph->scc = 0;
+	i = 0;
+	n = graph->n;
+	while (n) {
+		while (g->order[i] != -1) {
+			graph->node[g->order[i]].scc = graph->scc;
+			--n;
+			++i;
+		}
+		++i;
+		graph->scc++;
+	}
+
+	isl_tarjan_graph_free(g);
+
+	return 0;
+}
+
+/* Apply Tarjan's algorithm to detect the strongly connected components
+ * in the dependence graph.
+ */
+static int detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	return detect_ccs(ctx, graph, 0);
+}
+
+/* Apply Tarjan's algorithm to detect the (weakly) connected components
+ * in the dependence graph.
+ */
+static int detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	return detect_ccs(ctx, graph, 1);
+}
+
+static int cmp_scc(const void *a, const void *b, void *data)
+{
+	struct isl_sched_graph *graph = data;
+	const int *i1 = a;
+	const int *i2 = b;
+
+	return graph->node[*i1].scc - graph->node[*i2].scc;
+}
+
+/* Sort the elements of graph->sorted according to the corresponding SCCs.
+ */
+static int sort_sccs(struct isl_sched_graph *graph)
+{
+	return isl_sort(graph->sorted, graph->n, sizeof(int), &cmp_scc, graph);
+}
+
+/* Given a dependence relation R from "node" to itself,
+ * construct the set of coefficients of valid constraints for elements
+ * in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x such that
+ *
+ *	c_0 + c_n n + c_x y - c_x x >= 0 for each (x,y) in R
+ *
+ * or, equivalently,
+ *
+ *	c_0 + c_n n + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R }
+ *
+ * We choose here to compute the dual of delta R.
+ * Alternatively, we could have computed the dual of R, resulting
+ * in a set of tuples c_0, c_n, c_x, c_y, and then
+ * plugged in (c_0, c_n, c_x, -c_x).
+ *
+ * If "node" has been compressed, then the dependence relation
+ * is also compressed before the set of coefficients is computed.
+ */
+static __isl_give isl_basic_set *intra_coefficients(
+	struct isl_sched_graph *graph, struct isl_sched_node *node,
+	__isl_take isl_map *map)
+{
+	isl_set *delta;
+	isl_map *key;
+	isl_basic_set *coef;
+
+	if (isl_map_to_basic_set_has(graph->intra_hmap, map))
+		return isl_map_to_basic_set_get(graph->intra_hmap, map);
+
+	key = isl_map_copy(map);
+	if (node->compressed) {
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+	}
+	delta = isl_set_remove_divs(isl_map_deltas(map));
+	coef = isl_set_coefficients(delta);
+	graph->intra_hmap = isl_map_to_basic_set_set(graph->intra_hmap, key,
+					isl_basic_set_copy(coef));
+
+	return coef;
+}
+
+/* Given a dependence relation R, construct the set of coefficients
+ * of valid constraints for elements in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x, c_y such that
+ *
+ *	c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R
+ *
+ * If the source or destination nodes of "edge" have been compressed,
+ * then the dependence relation is also compressed before
+ * the set of coefficients is computed.
+ */
+static __isl_give isl_basic_set *inter_coefficients(
+	struct isl_sched_graph *graph, struct isl_sched_edge *edge,
+	__isl_take isl_map *map)
+{
+	isl_set *set;
+	isl_map *key;
+	isl_basic_set *coef;
+
+	if (isl_map_to_basic_set_has(graph->inter_hmap, map))
+		return isl_map_to_basic_set_get(graph->inter_hmap, map);
+
+	key = isl_map_copy(map);
+	if (edge->src->compressed)
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(edge->src->decompress));
+	if (edge->dst->compressed)
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(edge->dst->decompress));
+	set = isl_map_wrap(isl_map_remove_divs(map));
+	coef = isl_set_coefficients(set);
+	graph->inter_hmap = isl_map_to_basic_set_set(graph->inter_hmap, key,
+					isl_basic_set_copy(coef));
+
+	return coef;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from a node i to itself.
+ * That is, add constraints that enforce
+ *
+ *	(c_i_0 + c_i_n n + c_i_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *	= c_i_x (y - x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (0, 0, c_i_x^+ - c_i_x^-),
+ * where c_i_x = c_i_x^+ - c_i_x^-, with c_i_x^+ and c_i_x^- non-negative.
+ * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_intra_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	unsigned total;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
+	if (!coef)
+		goto error;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, 1);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from node i to node j.
+ * That is, add constraints that enforce
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (c_j_0 - c_i_0, c_j_n^+ - c_j_n^- - (c_i_n^+ - c_i_n^-),
+ *  c_j_x^+ - c_j_x^- - (c_i_x^+ - c_i_x^-)),
+ * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative.
+ * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_inter_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	unsigned total;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *src = edge->src;
+	struct isl_sched_node *dst = edge->dst;
+
+	coef = inter_coefficients(graph, edge, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set) + src->nvar,
+		    isl_mat_copy(dst->cmap));
+	if (!coef)
+		goto error;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, 1);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, 1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -1);
+
+	edge->start = graph->lp->n_ineq;
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	if (!graph->lp)
+		goto error;
+	isl_space_free(dim);
+	edge->end = graph->lp->n_ineq;
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from a node i to itself.
+ * If s = 1, we add the constraint
+ *
+ *	c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *	-c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *	-c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *	c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (m_0, m_n, -s * c_i_x),
+ * with each coefficient (except m_0) represented as a pair of non-negative
+ * coefficients.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ *
+ *
+ * If "local" is set, then we add constraints
+ *
+ *	c_i_x (y - x) <= 0
+ *
+ * or
+ *
+ *	-c_i_x (y - x) <= 0
+ *
+ * instead, forcing the dependence distance to be (less than or) equal to 0.
+ * That is, we plug in (0, 0, -s * c_i_x),
+ * Note that dependences marked local are treated as validity constraints
+ * by add_all_validity_constraints and therefore also have
+ * their distances bounded by 0 from below.
+ */
+static int add_intra_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	unsigned total;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
+	if (!coef)
+		goto error;
+
+	nparam = isl_space_dim(node->space, isl_dim_param);
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	if (!local) {
+		isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+		isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+		isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+	}
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, s);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -s);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from node i to node j.
+ * If s = 1, we add the constraint
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *		<= m_0 + m_n n
+ *
+ * or
+ *
+ *	-(c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x) +
+ *		m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *	-((c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x))
+ *		<= m_0 + m_n n
+ *
+ * or
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) +
+ *		m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (m_0 - s*c_j_0 + s*c_i_0, m_n - s*c_j_n + s*c_i_n,
+ *  -s*c_j_x+s*c_i_x)
+ * with each coefficient (except m_0, c_j_0 and c_i_0)
+ * represented as a pair of non-negative coefficients.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ *
+ *
+ * If "local" is set, then we add constraints
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) <= 0
+ *
+ * or
+ *
+ *	-((c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x)) <= 0
+ *
+ * instead, forcing the dependence distance to be (less than or) equal to 0.
+ * That is, we plug in
+ * (-s*c_j_0 + s*c_i_0, -s*c_j_n + s*c_i_n, -s*c_j_x+s*c_i_x).
+ * Note that dependences marked local are treated as validity constraints
+ * by add_all_validity_constraints and therefore also have
+ * their distances bounded by 0 from below.
+ */
+static int add_inter_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	unsigned total;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *src = edge->src;
+	struct isl_sched_node *dst = edge->dst;
+
+	coef = inter_coefficients(graph, edge, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set) + src->nvar,
+		    isl_mat_copy(dst->cmap));
+	if (!coef)
+		goto error;
+
+	nparam = isl_space_dim(src->space, isl_dim_param);
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	if (!local) {
+		isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+		isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+		isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+	}
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, -s);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, s);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, -s);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, s);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -s);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, s);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, -s);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, s);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -s);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, s);
+
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* Add all validity constraints to graph->lp.
+ *
+ * An edge that is forced to be local needs to have its dependence
+ * distances equal to zero.  We take care of bounding them by 0 from below
+ * here.  add_all_proximity_constraints takes care of bounding them by 0
+ * from above.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int add_all_validity_constraints(struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+		int local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->validity && !local)
+			continue;
+		if (edge->src != edge->dst)
+			continue;
+		if (add_intra_validity_constraints(graph, edge) < 0)
+			return -1;
+	}
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		int local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->validity && !local)
+			continue;
+		if (edge->src == edge->dst)
+			continue;
+		if (add_inter_validity_constraints(graph, edge) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance
+ * for all dependence relations.
+ * If a given proximity dependence is identical to a validity
+ * dependence, then the dependence distance is already bounded
+ * from below (by zero), so we only need to bound the distance
+ * from above.  (This includes the case of "local" dependences
+ * which are treated as validity dependence by add_all_validity_constraints.)
+ * Otherwise, we need to bound the distance both from above and from below.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int add_all_proximity_constraints(struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+		int local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->proximity && !local)
+			continue;
+		if (edge->src == edge->dst &&
+		    add_intra_proximity_constraints(graph, edge, 1, local) < 0)
+			return -1;
+		if (edge->src != edge->dst &&
+		    add_inter_proximity_constraints(graph, edge, 1, local) < 0)
+			return -1;
+		if (edge->validity || local)
+			continue;
+		if (edge->src == edge->dst &&
+		    add_intra_proximity_constraints(graph, edge, -1, 0) < 0)
+			return -1;
+		if (edge->src != edge->dst &&
+		    add_inter_proximity_constraints(graph, edge, -1, 0) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Compute a basis for the rows in the linear part of the schedule
+ * and extend this basis to a full basis.  The remaining rows
+ * can then be used to force linear independence from the rows
+ * in the schedule.
+ *
+ * In particular, given the schedule rows S, we compute
+ *
+ *	S   = H Q
+ *	S U = H
+ *
+ * with H the Hermite normal form of S.  That is, all but the
+ * first rank columns of H are zero and so each row in S is
+ * a linear combination of the first rank rows of Q.
+ * The matrix Q is then transposed because we will write the
+ * coefficients of the next schedule row as a column vector s
+ * and express this s as a linear combination s = Q c of the
+ * computed basis.
+ * Similarly, the matrix U is transposed such that we can
+ * compute the coefficients c = U s from a schedule row s.
+ */
+static int node_update_cmap(struct isl_sched_node *node)
+{
+	isl_mat *H, *U, *Q;
+	int n_row = isl_mat_rows(node->sched);
+
+	H = isl_mat_sub_alloc(node->sched, 0, n_row,
+			      1 + node->nparam, node->nvar);
+
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+	isl_mat_free(node->cmap);
+	isl_mat_free(node->cinv);
+	node->cmap = isl_mat_transpose(Q);
+	node->cinv = isl_mat_transpose(U);
+	node->rank = isl_mat_initial_non_zero_cols(H);
+	isl_mat_free(H);
+
+	if (!node->cmap || !node->cinv || node->rank < 0)
+		return -1;
+	return 0;
+}
+
+/* How many times should we count the constraints in "edge"?
+ *
+ * If carry is set, then we are counting the number of
+ * (validity or conditional validity) constraints that will be added
+ * in setup_carry_lp and we count each edge exactly once.
+ *
+ * Otherwise, we count as follows
+ * validity		-> 1 (>= 0)
+ * validity+proximity	-> 2 (>= 0 and upper bound)
+ * proximity		-> 2 (lower and upper bound)
+ * local(+any)		-> 2 (>= 0 and <= 0)
+ *
+ * If an edge is only marked conditional_validity then it counts
+ * as zero since it is only checked afterwards.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int edge_multiplicity(struct isl_sched_edge *edge, int carry,
+	int use_coincidence)
+{
+	if (carry && !edge->validity && !edge->conditional_validity)
+		return 0;
+	if (carry)
+		return 1;
+	if (edge->proximity || edge->local)
+		return 2;
+	if (use_coincidence && edge->coincidence)
+		return 2;
+	if (edge->validity)
+		return 1;
+	return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added for the given map.
+ *
+ * "use_coincidence" is set if we should take into account coincidence edges.
+ */
+static int count_map_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map,
+	int *n_eq, int *n_ineq, int carry, int use_coincidence)
+{
+	isl_basic_set *coef;
+	int f = edge_multiplicity(edge, carry, use_coincidence);
+
+	if (f == 0) {
+		isl_map_free(map);
+		return 0;
+	}
+
+	if (edge->src == edge->dst)
+		coef = intra_coefficients(graph, edge->src, map);
+	else
+		coef = inter_coefficients(graph, edge, map);
+	if (!coef)
+		return -1;
+	*n_eq += f * coef->n_eq;
+	*n_ineq += f * coef->n_ineq;
+	isl_basic_set_free(coef);
+
+	return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added to the main lp problem.
+ * We count as follows
+ * validity		-> 1 (>= 0)
+ * validity+proximity	-> 2 (>= 0 and upper bound)
+ * proximity		-> 2 (lower and upper bound)
+ * local(+any)		-> 2 (>= 0 and <= 0)
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int count_constraints(struct isl_sched_graph *graph,
+	int *n_eq, int *n_ineq, int use_coincidence)
+{
+	int i;
+
+	*n_eq = *n_ineq = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+		isl_map *map = isl_map_copy(edge->map);
+
+		if (count_map_constraints(graph, edge, map, n_eq, n_ineq,
+					    0, use_coincidence) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Count the number of constraints that will be added by
+ * add_bound_coefficient_constraints and increment *n_eq and *n_ineq
+ * accordingly.
+ *
+ * In practice, add_bound_coefficient_constraints only adds inequalities.
+ */
+static int count_bound_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int *n_eq, int *n_ineq)
+{
+	int i;
+
+	if (ctx->opt->schedule_max_coefficient == -1)
+		return 0;
+
+	for (i = 0; i < graph->n; ++i)
+		*n_ineq += 2 * graph->node[i].nparam + 2 * graph->node[i].nvar;
+
+	return 0;
+}
+
+/* Add constraints that bound the values of the variable and parameter
+ * coefficients of the schedule.
+ *
+ * The maximal value of the coefficients is defined by the option
+ * 'schedule_max_coefficient'.
+ */
+static int add_bound_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i, j, k;
+	int max_coefficient;
+	int total;
+
+	max_coefficient = ctx->opt->schedule_max_coefficient;
+
+	if (max_coefficient == -1)
+		return 0;
+
+	total = isl_basic_set_total_dim(graph->lp);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		for (j = 0; j < 2 * node->nparam + 2 * node->nvar; ++j) {
+			int dim;
+			k = isl_basic_set_alloc_inequality(graph->lp);
+			if (k < 0)
+				return -1;
+			dim = 1 + node->start + 1 + j;
+			isl_seq_clr(graph->lp->ineq[k], 1 +  total);
+			isl_int_set_si(graph->lp->ineq[k][dim], -1);
+			isl_int_set_si(graph->lp->ineq[k][0], max_coefficient);
+		}
+	}
+
+	return 0;
+}
+
+/* Construct an ILP problem for finding schedule coefficients
+ * that result in non-negative, but small dependence distances
+ * over all dependences.
+ * In particular, the dependence distances over proximity edges
+ * are bounded by m_0 + m_n n and we compute schedule coefficients
+ * with small values (preferably zero) of m_n and m_0.
+ *
+ * All variables of the ILP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *	- sum of positive and negative parts of m_n coefficients
+ *	- m_0
+ *	- sum of positive and negative parts of all c_n coefficients
+ *		(unconstrained when computing non-parametric schedules)
+ *	- sum of positive and negative parts of all c_x coefficients
+ *	- positive and negative parts of m_n coefficients
+ *	- for each node
+ *		- c_i_0
+ *		- positive and negative parts of c_i_n (if parametric)
+ *		- positive and negative parts of c_i_x
+ *
+ * The c_i_x are not represented directly, but through the columns of
+ * node->cmap.  That is, the computed values are for variable t_i_x
+ * such that c_i_x = Q t_i_x with Q equal to node->cmap.
+ *
+ * The constraints are those from the edges plus two or three equalities
+ * to express the sums.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i, j;
+	int k;
+	unsigned nparam;
+	unsigned total;
+	isl_space *dim;
+	int parametric;
+	int param_pos;
+	int n_eq, n_ineq;
+	int max_constant_term;
+
+	max_constant_term = ctx->opt->schedule_max_constant_term;
+
+	parametric = ctx->opt->schedule_parametric;
+	nparam = isl_space_dim(graph->node[0].space, isl_dim_param);
+	param_pos = 4;
+	total = param_pos + 2 * nparam;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+		if (node_update_cmap(node) < 0)
+			return -1;
+		node->start = total;
+		total += 1 + 2 * (node->nparam + node->nvar);
+	}
+
+	if (count_constraints(graph, &n_eq, &n_ineq, use_coincidence) < 0)
+		return -1;
+	if (count_bound_coefficient_constraints(ctx, graph, &n_eq, &n_ineq) < 0)
+		return -1;
+
+	dim = isl_space_set_alloc(ctx, 0, total);
+	isl_basic_set_free(graph->lp);
+	n_eq += 2 + parametric;
+	if (max_constant_term != -1)
+		n_ineq += graph->n;
+
+	graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][1], -1);
+	for (i = 0; i < 2 * nparam; ++i)
+		isl_int_set_si(graph->lp->eq[k][1 + param_pos + i], 1);
+
+	if (parametric) {
+		k = isl_basic_set_alloc_equality(graph->lp);
+		if (k < 0)
+			return -1;
+		isl_seq_clr(graph->lp->eq[k], 1 +  total);
+		isl_int_set_si(graph->lp->eq[k][3], -1);
+		for (i = 0; i < graph->n; ++i) {
+			int pos = 1 + graph->node[i].start + 1;
+
+			for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+				isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+		}
+	}
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][4], -1);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+		for (j = 0; j < 2 * node->nvar; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	if (max_constant_term != -1)
+		for (i = 0; i < graph->n; ++i) {
+			struct isl_sched_node *node = &graph->node[i];
+			k = isl_basic_set_alloc_inequality(graph->lp);
+			if (k < 0)
+				return -1;
+			isl_seq_clr(graph->lp->ineq[k], 1 +  total);
+			isl_int_set_si(graph->lp->ineq[k][1 + node->start], -1);
+			isl_int_set_si(graph->lp->ineq[k][0], max_constant_term);
+		}
+
+	if (add_bound_coefficient_constraints(ctx, graph) < 0)
+		return -1;
+	if (add_all_validity_constraints(graph, use_coincidence) < 0)
+		return -1;
+	if (add_all_proximity_constraints(graph, use_coincidence) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Analyze the conflicting constraint found by
+ * isl_tab_basic_set_non_trivial_lexmin.  If it corresponds to the validity
+ * constraint of one of the edges between distinct nodes, living, moreover
+ * in distinct SCCs, then record the source and sink SCC as this may
+ * be a good place to cut between SCCs.
+ */
+static int check_conflict(int con, void *user)
+{
+	int i;
+	struct isl_sched_graph *graph = user;
+
+	if (graph->src_scc >= 0)
+		return 0;
+
+	con -= graph->lp->n_eq;
+
+	if (con >= graph->lp->n_ineq)
+		return 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (!graph->edge[i].validity)
+			continue;
+		if (graph->edge[i].src == graph->edge[i].dst)
+			continue;
+		if (graph->edge[i].src->scc == graph->edge[i].dst->scc)
+			continue;
+		if (graph->edge[i].start > con)
+			continue;
+		if (graph->edge[i].end <= con)
+			continue;
+		graph->src_scc = graph->edge[i].src->scc;
+		graph->dst_scc = graph->edge[i].dst->scc;
+	}
+
+	return 0;
+}
+
+/* Check whether the next schedule row of the given node needs to be
+ * non-trivial.  Lower-dimensional domains may have some trivial rows,
+ * but as soon as the number of remaining required non-trivial rows
+ * is as large as the number or remaining rows to be computed,
+ * all remaining rows need to be non-trivial.
+ */
+static int needs_row(struct isl_sched_graph *graph, struct isl_sched_node *node)
+{
+	return node->nvar - node->rank >= graph->maxvar - graph->n_row;
+}
+
+/* Solve the ILP problem constructed in setup_lp.
+ * For each node such that all the remaining rows of its schedule
+ * need to be non-trivial, we construct a non-triviality region.
+ * This region imposes that the next row is independent of previous rows.
+ * In particular the coefficients c_i_x are represented by t_i_x
+ * variables with c_i_x = Q t_i_x and Q a unimodular matrix such that
+ * its first columns span the rows of the previously computed part
+ * of the schedule.  The non-triviality region enforces that at least
+ * one of the remaining components of t_i_x is non-zero, i.e.,
+ * that the new schedule row depends on at least one of the remaining
+ * columns of Q.
+ */
+static __isl_give isl_vec *solve_lp(struct isl_sched_graph *graph)
+{
+	int i;
+	isl_vec *sol;
+	isl_basic_set *lp;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int skip = node->rank;
+		graph->region[i].pos = node->start + 1 + 2*(node->nparam+skip);
+		if (needs_row(graph, node))
+			graph->region[i].len = 2 * (node->nvar - skip);
+		else
+			graph->region[i].len = 0;
+	}
+	lp = isl_basic_set_copy(graph->lp);
+	sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n,
+				       graph->region, &check_conflict, graph);
+	return sol;
+}
+
+/* Update the schedules of all nodes based on the given solution
+ * of the LP problem.
+ * The new row is added to the current band.
+ * All possibly negative coefficients are encoded as a difference
+ * of two non-negative variables, so we need to perform the subtraction
+ * here.  Moreover, if use_cmap is set, then the solution does
+ * not refer to the actual coefficients c_i_x, but instead to variables
+ * t_i_x such that c_i_x = Q t_i_x and Q is equal to node->cmap.
+ * In this case, we then also need to perform this multiplication
+ * to obtain the values of c_i_x.
+ *
+ * If coincident is set, then the caller guarantees that the new
+ * row satisfies the coincidence constraints.
+ */
+static int update_schedule(struct isl_sched_graph *graph,
+	__isl_take isl_vec *sol, int use_cmap, int coincident)
+{
+	int i, j;
+	isl_vec *csol = NULL;
+
+	if (!sol)
+		goto error;
+	if (sol->size == 0)
+		isl_die(sol->ctx, isl_error_internal,
+			"no solution found", goto error);
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(sol->ctx, isl_error_internal,
+			"too many schedule rows", goto error);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = node->start;
+		int row = isl_mat_rows(node->sched);
+
+		isl_vec_free(csol);
+		csol = isl_vec_alloc(sol->ctx, node->nvar);
+		if (!csol)
+			goto error;
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_rows(node->sched, 1);
+		if (!node->sched)
+			goto error;
+		node->sched = isl_mat_set_element(node->sched, row, 0,
+						  sol->el[1 + pos]);
+		for (j = 0; j < node->nparam + node->nvar; ++j)
+			isl_int_sub(sol->el[1 + pos + 1 + 2 * j + 1],
+				    sol->el[1 + pos + 1 + 2 * j + 1],
+				    sol->el[1 + pos + 1 + 2 * j]);
+		for (j = 0; j < node->nparam; ++j)
+			node->sched = isl_mat_set_element(node->sched,
+					row, 1 + j, sol->el[1+pos+1+2*j+1]);
+		for (j = 0; j < node->nvar; ++j)
+			isl_int_set(csol->el[j],
+				    sol->el[1+pos+1+2*(node->nparam+j)+1]);
+		if (use_cmap)
+			csol = isl_mat_vec_product(isl_mat_copy(node->cmap),
+						   csol);
+		if (!csol)
+			goto error;
+		for (j = 0; j < node->nvar; ++j)
+			node->sched = isl_mat_set_element(node->sched,
+					row, 1 + node->nparam + j, csol->el[j]);
+		node->band[graph->n_total_row] = graph->n_band;
+		node->coincident[graph->n_total_row] = coincident;
+	}
+	isl_vec_free(sol);
+	isl_vec_free(csol);
+
+	graph->n_row++;
+	graph->n_total_row++;
+
+	return 0;
+error:
+	isl_vec_free(sol);
+	isl_vec_free(csol);
+	return -1;
+}
+
+/* Convert row "row" of node->sched into an isl_aff living in "ls"
+ * and return this isl_aff.
+ */
+static __isl_give isl_aff *extract_schedule_row(__isl_take isl_local_space *ls,
+	struct isl_sched_node *node, int row)
+{
+	int j;
+	isl_int v;
+	isl_aff *aff;
+
+	isl_int_init(v);
+
+	aff = isl_aff_zero_on_domain(ls);
+	isl_mat_get_element(node->sched, row, 0, &v);
+	aff = isl_aff_set_constant(aff, v);
+	for (j = 0; j < node->nparam; ++j) {
+		isl_mat_get_element(node->sched, row, 1 + j, &v);
+		aff = isl_aff_set_coefficient(aff, isl_dim_param, j, v);
+	}
+	for (j = 0; j < node->nvar; ++j) {
+		isl_mat_get_element(node->sched, row, 1 + node->nparam + j, &v);
+		aff = isl_aff_set_coefficient(aff, isl_dim_in, j, v);
+	}
+
+	isl_int_clear(v);
+
+	return aff;
+}
+
+/* Convert node->sched into a multi_aff and return this multi_aff.
+ *
+ * The result is defined over the uncompressed node domain.
+ */
+static __isl_give isl_multi_aff *node_extract_schedule_multi_aff(
+	struct isl_sched_node *node)
+{
+	int i;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff;
+	isl_multi_aff *ma;
+	int nrow, ncol;
+
+	nrow = isl_mat_rows(node->sched);
+	ncol = isl_mat_cols(node->sched) - 1;
+	if (node->compressed)
+		space = isl_multi_aff_get_domain_space(node->decompress);
+	else
+		space = isl_space_copy(node->space);
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, nrow);
+	ma = isl_multi_aff_zero(space);
+
+	for (i = 0; i < nrow; ++i) {
+		aff = extract_schedule_row(isl_local_space_copy(ls), node, i);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_local_space_free(ls);
+
+	if (node->compressed)
+		ma = isl_multi_aff_pullback_multi_aff(ma,
+					isl_multi_aff_copy(node->compress));
+
+	return ma;
+}
+
+/* Convert node->sched into a map and return this map.
+ *
+ * The result is cached in node->sched_map, which needs to be released
+ * whenever node->sched is updated.
+ * It is defined over the uncompressed node domain.
+ */
+static __isl_give isl_map *node_extract_schedule(struct isl_sched_node *node)
+{
+	if (!node->sched_map) {
+		isl_multi_aff *ma;
+
+		ma = node_extract_schedule_multi_aff(node);
+		node->sched_map = isl_map_from_multi_aff(ma);
+	}
+
+	return isl_map_copy(node->sched_map);
+}
+
+/* Construct a map that can be used to update a dependence relation
+ * based on the current schedule.
+ * That is, construct a map expressing that source and sink
+ * are executed within the same iteration of the current schedule.
+ * This map can then be intersected with the dependence relation.
+ * This is not the most efficient way, but this shouldn't be a critical
+ * operation.
+ */
+static __isl_give isl_map *specializer(struct isl_sched_node *src,
+	struct isl_sched_node *dst)
+{
+	isl_map *src_sched, *dst_sched;
+
+	src_sched = node_extract_schedule(src);
+	dst_sched = node_extract_schedule(dst);
+	return isl_map_apply_range(src_sched, isl_map_reverse(dst_sched));
+}
+
+/* Intersect the domains of the nested relations in domain and range
+ * of "umap" with "map".
+ */
+static __isl_give isl_union_map *intersect_domains(
+	__isl_take isl_union_map *umap, __isl_keep isl_map *map)
+{
+	isl_union_set *uset;
+
+	umap = isl_union_map_zip(umap);
+	uset = isl_union_set_from_set(isl_map_wrap(isl_map_copy(map)));
+	umap = isl_union_map_intersect_domain(umap, uset);
+	umap = isl_union_map_zip(umap);
+	return umap;
+}
+
+/* Update the dependence relation of the given edge based
+ * on the current schedule.
+ * If the dependence is carried completely by the current schedule, then
+ * it is removed from the edge_tables.  It is kept in the list of edges
+ * as otherwise all edge_tables would have to be recomputed.
+ */
+static int update_edge(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	isl_map *id;
+
+	id = specializer(edge->src, edge->dst);
+	edge->map = isl_map_intersect(edge->map, isl_map_copy(id));
+	if (!edge->map)
+		goto error;
+
+	if (edge->tagged_condition) {
+		edge->tagged_condition =
+			intersect_domains(edge->tagged_condition, id);
+		if (!edge->tagged_condition)
+			goto error;
+	}
+	if (edge->tagged_validity) {
+		edge->tagged_validity =
+			intersect_domains(edge->tagged_validity, id);
+		if (!edge->tagged_validity)
+			goto error;
+	}
+
+	isl_map_free(id);
+	if (isl_map_plain_is_empty(edge->map))
+		graph_remove_edge(graph, edge);
+
+	return 0;
+error:
+	isl_map_free(id);
+	return -1;
+}
+
+/* Update the dependence relations of all edges based on the current schedule.
+ */
+static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = graph->n_edge - 1; i >= 0; --i) {
+		if (update_edge(graph, &graph->edge[i]) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void next_band(struct isl_sched_graph *graph)
+{
+	graph->band_start = graph->n_total_row;
+	graph->n_band++;
+}
+
+/* Topologically sort statements mapped to the same schedule iteration
+ * and add a row to the schedule corresponding to this order.
+ */
+static int sort_statements(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i, j;
+
+	if (graph->n <= 1)
+		return 0;
+
+	if (update_edges(ctx, graph) < 0)
+		return -1;
+
+	if (graph->n_edge == 0)
+		return 0;
+
+	if (detect_sccs(ctx, graph) < 0)
+		return -1;
+
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(ctx, isl_error_internal,
+			"too many schedule rows", return -1);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int row = isl_mat_rows(node->sched);
+		int cols = isl_mat_cols(node->sched);
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_rows(node->sched, 1);
+		if (!node->sched)
+			return -1;
+		node->sched = isl_mat_set_element_si(node->sched, row, 0,
+						     node->scc);
+		for (j = 1; j < cols; ++j)
+			node->sched = isl_mat_set_element_si(node->sched,
+							     row, j, 0);
+		node->band[graph->n_total_row] = graph->n_band;
+	}
+
+	graph->n_total_row++;
+	next_band(graph);
+
+	return 0;
+}
+
+/* Construct an isl_schedule based on the computed schedule stored
+ * in graph and with parameters specified by dim.
+ */
+static __isl_give isl_schedule *extract_schedule(struct isl_sched_graph *graph,
+	__isl_take isl_space *dim)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_schedule *sched = NULL;
+
+	if (!dim)
+		return NULL;
+
+	ctx = isl_space_get_ctx(dim);
+	sched = isl_calloc(ctx, struct isl_schedule,
+			   sizeof(struct isl_schedule) +
+			   (graph->n - 1) * sizeof(struct isl_schedule_node));
+	if (!sched)
+		goto error;
+
+	sched->ref = 1;
+	sched->n = graph->n;
+	sched->n_band = graph->n_band;
+	sched->n_total_row = graph->n_total_row;
+
+	for (i = 0; i < sched->n; ++i) {
+		int r, b;
+		int *band_end, *band_id, *coincident;
+
+		sched->node[i].sched =
+			node_extract_schedule_multi_aff(&graph->node[i]);
+		if (!sched->node[i].sched)
+			goto error;
+
+		sched->node[i].n_band = graph->n_band;
+		if (graph->n_band == 0)
+			continue;
+
+		band_end = isl_alloc_array(ctx, int, graph->n_band);
+		band_id = isl_alloc_array(ctx, int, graph->n_band);
+		coincident = isl_alloc_array(ctx, int, graph->n_total_row);
+		sched->node[i].band_end = band_end;
+		sched->node[i].band_id = band_id;
+		sched->node[i].coincident = coincident;
+		if (!band_end || !band_id || !coincident)
+			goto error;
+
+		for (r = 0; r < graph->n_total_row; ++r)
+			coincident[r] = graph->node[i].coincident[r];
+		for (r = b = 0; r < graph->n_total_row; ++r) {
+			if (graph->node[i].band[r] == b)
+				continue;
+			band_end[b++] = r;
+			if (graph->node[i].band[r] == -1)
+				break;
+		}
+		if (r == graph->n_total_row)
+			band_end[b++] = r;
+		sched->node[i].n_band = b;
+		for (--b; b >= 0; --b)
+			band_id[b] = graph->node[i].band_id[b];
+	}
+
+	sched->dim = dim;
+
+	return sched;
+error:
+	isl_space_free(dim);
+	isl_schedule_free(sched);
+	return NULL;
+}
+
+/* Copy nodes that satisfy node_pred from the src dependence graph
+ * to the dst dependence graph.
+ */
+static int copy_nodes(struct isl_sched_graph *dst, struct isl_sched_graph *src,
+	int (*node_pred)(struct isl_sched_node *node, int data), int data)
+{
+	int i;
+
+	dst->n = 0;
+	for (i = 0; i < src->n; ++i) {
+		int j;
+
+		if (!node_pred(&src->node[i], data))
+			continue;
+
+		j = dst->n;
+		dst->node[j].space = isl_space_copy(src->node[i].space);
+		dst->node[j].compressed = src->node[i].compressed;
+		dst->node[j].hull = isl_set_copy(src->node[i].hull);
+		dst->node[j].compress =
+			isl_multi_aff_copy(src->node[i].compress);
+		dst->node[j].decompress =
+			isl_multi_aff_copy(src->node[i].decompress);
+		dst->node[j].nvar = src->node[i].nvar;
+		dst->node[j].nparam = src->node[i].nparam;
+		dst->node[j].sched = isl_mat_copy(src->node[i].sched);
+		dst->node[j].sched_map = isl_map_copy(src->node[i].sched_map);
+		dst->node[j].band = src->node[i].band;
+		dst->node[j].band_id = src->node[i].band_id;
+		dst->node[j].coincident = src->node[i].coincident;
+		dst->n++;
+
+		if (!dst->node[j].space || !dst->node[j].sched)
+			return -1;
+		if (dst->node[j].compressed &&
+		    (!dst->node[j].hull || !dst->node[j].compress ||
+		     !dst->node[j].decompress))
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Copy non-empty edges that satisfy edge_pred from the src dependence graph
+ * to the dst dependence graph.
+ * If the source or destination node of the edge is not in the destination
+ * graph, then it must be a backward proximity edge and it should simply
+ * be ignored.
+ */
+static int copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst,
+	struct isl_sched_graph *src,
+	int (*edge_pred)(struct isl_sched_edge *edge, int data), int data)
+{
+	int i;
+	enum isl_edge_type t;
+
+	dst->n_edge = 0;
+	for (i = 0; i < src->n_edge; ++i) {
+		struct isl_sched_edge *edge = &src->edge[i];
+		isl_map *map;
+		isl_union_map *tagged_condition;
+		isl_union_map *tagged_validity;
+		struct isl_sched_node *dst_src, *dst_dst;
+
+		if (!edge_pred(edge, data))
+			continue;
+
+		if (isl_map_plain_is_empty(edge->map))
+			continue;
+
+		dst_src = graph_find_node(ctx, dst, edge->src->space);
+		dst_dst = graph_find_node(ctx, dst, edge->dst->space);
+		if (!dst_src || !dst_dst) {
+			if (edge->validity || edge->conditional_validity)
+				isl_die(ctx, isl_error_internal,
+					"backward (conditional) validity edge",
+					return -1);
+			continue;
+		}
+
+		map = isl_map_copy(edge->map);
+		tagged_condition = isl_union_map_copy(edge->tagged_condition);
+		tagged_validity = isl_union_map_copy(edge->tagged_validity);
+
+		dst->edge[dst->n_edge].src = dst_src;
+		dst->edge[dst->n_edge].dst = dst_dst;
+		dst->edge[dst->n_edge].map = map;
+		dst->edge[dst->n_edge].tagged_condition = tagged_condition;
+		dst->edge[dst->n_edge].tagged_validity = tagged_validity;
+		dst->edge[dst->n_edge].validity = edge->validity;
+		dst->edge[dst->n_edge].proximity = edge->proximity;
+		dst->edge[dst->n_edge].coincidence = edge->coincidence;
+		dst->edge[dst->n_edge].condition = edge->condition;
+		dst->edge[dst->n_edge].conditional_validity =
+						edge->conditional_validity;
+		dst->n_edge++;
+
+		if (edge->tagged_condition && !tagged_condition)
+			return -1;
+		if (edge->tagged_validity && !tagged_validity)
+			return -1;
+
+		for (t = isl_edge_first; t <= isl_edge_last; ++t) {
+			if (edge !=
+			    graph_find_edge(src, t, edge->src, edge->dst))
+				continue;
+			if (graph_edge_table_add(ctx, dst, t,
+					    &dst->edge[dst->n_edge - 1]) < 0)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Given a "src" dependence graph that contains the nodes from "dst"
+ * that satisfy node_pred, copy the schedule computed in "src"
+ * for those nodes back to "dst".
+ */
+static int copy_schedule(struct isl_sched_graph *dst,
+	struct isl_sched_graph *src,
+	int (*node_pred)(struct isl_sched_node *node, int data), int data)
+{
+	int i;
+
+	src->n = 0;
+	for (i = 0; i < dst->n; ++i) {
+		if (!node_pred(&dst->node[i], data))
+			continue;
+		isl_mat_free(dst->node[i].sched);
+		isl_map_free(dst->node[i].sched_map);
+		dst->node[i].sched = isl_mat_copy(src->node[src->n].sched);
+		dst->node[i].sched_map =
+			isl_map_copy(src->node[src->n].sched_map);
+		src->n++;
+	}
+
+	dst->max_row = src->max_row;
+	dst->n_total_row = src->n_total_row;
+	dst->n_band = src->n_band;
+
+	return 0;
+}
+
+/* Compute the maximal number of variables over all nodes.
+ * This is the maximal number of linearly independent schedule
+ * rows that we need to compute.
+ * Just in case we end up in a part of the dependence graph
+ * with only lower-dimensional domains, we make sure we will
+ * compute the required amount of extra linearly independent rows.
+ */
+static int compute_maxvar(struct isl_sched_graph *graph)
+{
+	int i;
+
+	graph->maxvar = 0;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int nvar;
+
+		if (node_update_cmap(node) < 0)
+			return -1;
+		nvar = node->nvar + graph->n_row - node->rank;
+		if (nvar > graph->maxvar)
+			graph->maxvar = nvar;
+	}
+
+	return 0;
+}
+
+static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph);
+static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph);
+
+/* Compute a schedule for a subgraph of "graph".  In particular, for
+ * the graph composed of nodes that satisfy node_pred and edges that
+ * that satisfy edge_pred.  The caller should precompute the number
+ * of nodes and edges that satisfy these predicates and pass them along
+ * as "n" and "n_edge".
+ * If the subgraph is known to consist of a single component, then wcc should
+ * be set and then we call compute_schedule_wcc on the constructed subgraph.
+ * Otherwise, we call compute_schedule, which will check whether the subgraph
+ * is connected.
+ */
+static int compute_sub_schedule(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int n, int n_edge,
+	int (*node_pred)(struct isl_sched_node *node, int data),
+	int (*edge_pred)(struct isl_sched_edge *edge, int data),
+	int data, int wcc)
+{
+	struct isl_sched_graph split = { 0 };
+	int t;
+
+	if (graph_alloc(ctx, &split, n, n_edge) < 0)
+		goto error;
+	if (copy_nodes(&split, graph, node_pred, data) < 0)
+		goto error;
+	if (graph_init_table(ctx, &split) < 0)
+		goto error;
+	for (t = 0; t <= isl_edge_last; ++t)
+		split.max_edge[t] = graph->max_edge[t];
+	if (graph_init_edge_tables(ctx, &split) < 0)
+		goto error;
+	if (copy_edges(ctx, &split, graph, edge_pred, data) < 0)
+		goto error;
+	split.n_row = graph->n_row;
+	split.max_row = graph->max_row;
+	split.n_total_row = graph->n_total_row;
+	split.n_band = graph->n_band;
+	split.band_start = graph->band_start;
+
+	if (wcc && compute_schedule_wcc(ctx, &split) < 0)
+		goto error;
+	if (!wcc && compute_schedule(ctx, &split) < 0)
+		goto error;
+
+	copy_schedule(graph, &split, node_pred, data);
+
+	graph_free(ctx, &split);
+	return 0;
+error:
+	graph_free(ctx, &split);
+	return -1;
+}
+
+static int node_scc_exactly(struct isl_sched_node *node, int scc)
+{
+	return node->scc == scc;
+}
+
+static int node_scc_at_most(struct isl_sched_node *node, int scc)
+{
+	return node->scc <= scc;
+}
+
+static int node_scc_at_least(struct isl_sched_node *node, int scc)
+{
+	return node->scc >= scc;
+}
+
+static int edge_scc_exactly(struct isl_sched_edge *edge, int scc)
+{
+	return edge->src->scc == scc && edge->dst->scc == scc;
+}
+
+static int edge_dst_scc_at_most(struct isl_sched_edge *edge, int scc)
+{
+	return edge->dst->scc <= scc;
+}
+
+static int edge_src_scc_at_least(struct isl_sched_edge *edge, int scc)
+{
+	return edge->src->scc >= scc;
+}
+
+/* Pad the schedules of all nodes with zero rows such that in the end
+ * they all have graph->n_total_row rows.
+ * The extra rows don't belong to any band, so they get assigned band number -1.
+ */
+static int pad_schedule(struct isl_sched_graph *graph)
+{
+	int i, j;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int row = isl_mat_rows(node->sched);
+		if (graph->n_total_row > row) {
+			isl_map_free(node->sched_map);
+			node->sched_map = NULL;
+		}
+		node->sched = isl_mat_add_zero_rows(node->sched,
+						    graph->n_total_row - row);
+		if (!node->sched)
+			return -1;
+		for (j = row; j < graph->n_total_row; ++j)
+			node->band[j] = -1;
+	}
+
+	return 0;
+}
+
+/* Reset the current band by dropping all its schedule rows.
+ */
+static int reset_band(struct isl_sched_graph *graph)
+{
+	int i;
+	int drop;
+
+	drop = graph->n_total_row - graph->band_start;
+	graph->n_total_row -= drop;
+	graph->n_row -= drop;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+
+		node->sched = isl_mat_drop_rows(node->sched,
+						graph->band_start, drop);
+
+		if (!node->sched)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Split the current graph into two parts and compute a schedule for each
+ * part individually.  In particular, one part consists of all SCCs up
+ * to and including graph->src_scc, while the other part contains the other
+ * SCCS.
+ *
+ * The split is enforced in the schedule by constant rows with two different
+ * values (0 and 1).  These constant rows replace the previously computed rows
+ * in the current band.
+ * It would be possible to reuse them as the first rows in the next
+ * band, but recomputing them may result in better rows as we are looking
+ * at a smaller part of the dependence graph.
+ *
+ * Since we do not enforce coincidence, we conservatively mark the
+ * splitting row as not coincident.
+ *
+ * The band_id of the second group is set to n, where n is the number
+ * of nodes in the first group.  This ensures that the band_ids over
+ * the two groups remain disjoint, even if either or both of the two
+ * groups contain independent components.
+ */
+static int compute_split_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i, j, n, e1, e2;
+	int n_total_row, orig_total_row;
+	int n_band, orig_band;
+
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(ctx, isl_error_internal,
+			"too many schedule rows", return -1);
+
+	if (reset_band(graph) < 0)
+		return -1;
+
+	n = 0;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int row = isl_mat_rows(node->sched);
+		int cols = isl_mat_cols(node->sched);
+		int before = node->scc <= graph->src_scc;
+
+		if (before)
+			n++;
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_rows(node->sched, 1);
+		if (!node->sched)
+			return -1;
+		node->sched = isl_mat_set_element_si(node->sched, row, 0,
+						     !before);
+		for (j = 1; j < cols; ++j)
+			node->sched = isl_mat_set_element_si(node->sched,
+							     row, j, 0);
+		node->band[graph->n_total_row] = graph->n_band;
+		node->coincident[graph->n_total_row] = 0;
+	}
+
+	e1 = e2 = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (graph->edge[i].dst->scc <= graph->src_scc)
+			e1++;
+		if (graph->edge[i].src->scc > graph->src_scc)
+			e2++;
+	}
+
+	graph->n_total_row++;
+	next_band(graph);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		if (node->scc > graph->src_scc)
+			node->band_id[graph->n_band] = n;
+	}
+
+	orig_total_row = graph->n_total_row;
+	orig_band = graph->n_band;
+	if (compute_sub_schedule(ctx, graph, n, e1,
+				&node_scc_at_most, &edge_dst_scc_at_most,
+				graph->src_scc, 0) < 0)
+		return -1;
+	n_total_row = graph->n_total_row;
+	graph->n_total_row = orig_total_row;
+	n_band = graph->n_band;
+	graph->n_band = orig_band;
+	if (compute_sub_schedule(ctx, graph, graph->n - n, e2,
+				&node_scc_at_least, &edge_src_scc_at_least,
+				graph->src_scc + 1, 0) < 0)
+		return -1;
+	if (n_total_row > graph->n_total_row)
+		graph->n_total_row = n_total_row;
+	if (n_band > graph->n_band)
+		graph->n_band = n_band;
+
+	return pad_schedule(graph);
+}
+
+/* Compute the next band of the schedule after updating the dependence
+ * relations based on the the current schedule.
+ */
+static int compute_next_band(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	if (update_edges(ctx, graph) < 0)
+		return -1;
+	next_band(graph);
+
+	return compute_schedule(ctx, graph);
+}
+
+/* Add constraints to graph->lp that force the dependence "map" (which
+ * is part of the dependence relation of "edge")
+ * to be respected and attempt to carry it, where the edge is one from
+ * a node j to itself.  "pos" is the sequence number of the given map.
+ * That is, add constraints that enforce
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_j_0 + c_j_n n + c_j_x x)
+ *	= c_j_x (y - x) >= e_i
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (-e_i, 0, c_j_x),
+ * with each coefficient in c_j_x represented as a pair of non-negative
+ * coefficients.
+ */
+static int add_intra_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
+{
+	unsigned total;
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+	if (!coef)
+		return -1;
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+	isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, 1);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that force the dependence "map" (which
+ * is part of the dependence relation of "edge")
+ * to be respected and attempt to carry it, where the edge is one from
+ * node j to node k.  "pos" is the sequence number of the given map.
+ * That is, add constraints that enforce
+ *
+ *	(c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= e_i
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for R and then plug in
+ * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, c_k_x - c_j_x)
+ * with each coefficient (except e_i, c_k_0 and c_j_0)
+ * represented as a pair of non-negative coefficients.
+ */
+static int add_inter_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
+{
+	unsigned total;
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *src = edge->src;
+	struct isl_sched_node *dst = edge->dst;
+
+	coef = inter_coefficients(graph, edge, map);
+	if (!coef)
+		return -1;
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, 1);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, 1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -1);
+
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that force all (conditional) validity
+ * dependences to be respected and attempt to carry them.
+ */
+static int add_all_constraints(struct isl_sched_graph *graph)
+{
+	int i, j;
+	int pos;
+
+	pos = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+
+		if (!edge->validity && !edge->conditional_validity)
+			continue;
+
+		for (j = 0; j < edge->map->n; ++j) {
+			isl_basic_map *bmap;
+			isl_map *map;
+
+			bmap = isl_basic_map_copy(edge->map->p[j]);
+			map = isl_map_from_basic_map(bmap);
+
+			if (edge->src == edge->dst &&
+			    add_intra_constraints(graph, edge, map, pos) < 0)
+				return -1;
+			if (edge->src != edge->dst &&
+			    add_inter_constraints(graph, edge, map, pos) < 0)
+				return -1;
+			++pos;
+		}
+	}
+
+	return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added to the carry_lp problem.
+ * We count each edge exactly once.
+ */
+static int count_all_constraints(struct isl_sched_graph *graph,
+	int *n_eq, int *n_ineq)
+{
+	int i, j;
+
+	*n_eq = *n_ineq = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+		for (j = 0; j < edge->map->n; ++j) {
+			isl_basic_map *bmap;
+			isl_map *map;
+
+			bmap = isl_basic_map_copy(edge->map->p[j]);
+			map = isl_map_from_basic_map(bmap);
+
+			if (count_map_constraints(graph, edge, map,
+						  n_eq, n_ineq, 1, 0) < 0)
+				    return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many dependences as possible.
+ * In particular, for each dependence i, we bound the dependence distance
+ * from below by e_i, with 0 <= e_i <= 1 and then maximize the sum
+ * of all e_i's.  Dependence with e_i = 0 in the solution are simply
+ * respected, while those with e_i > 0 (in practice e_i = 1) are carried.
+ * Note that if the dependence relation is a union of basic maps,
+ * then we have to consider each basic map individually as it may only
+ * be possible to carry the dependences expressed by some of those
+ * basic maps and not all off them.
+ * Below, we consider each of those basic maps as a separate "edge".
+ *
+ * All variables of the LP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *	- sum of (1 - e_i) over all edges
+ *	- sum of positive and negative parts of all c_n coefficients
+ *		(unconstrained when computing non-parametric schedules)
+ *	- sum of positive and negative parts of all c_x coefficients
+ *	- for each edge
+ *		- e_i
+ *	- for each node
+ *		- c_i_0
+ *		- positive and negative parts of c_i_n (if parametric)
+ *		- positive and negative parts of c_i_x
+ *
+ * The constraints are those from the (validity) edges plus three equalities
+ * to express the sums and n_edge inequalities to express e_i <= 1.
+ */
+static int setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i, j;
+	int k;
+	isl_space *dim;
+	unsigned total;
+	int n_eq, n_ineq;
+	int n_edge;
+
+	n_edge = 0;
+	for (i = 0; i < graph->n_edge; ++i)
+		n_edge += graph->edge[i].map->n;
+
+	total = 3 + n_edge;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+		node->start = total;
+		total += 1 + 2 * (node->nparam + node->nvar);
+	}
+
+	if (count_all_constraints(graph, &n_eq, &n_ineq) < 0)
+		return -1;
+	if (count_bound_coefficient_constraints(ctx, graph, &n_eq, &n_ineq) < 0)
+		return -1;
+
+	dim = isl_space_set_alloc(ctx, 0, total);
+	isl_basic_set_free(graph->lp);
+	n_eq += 3;
+	n_ineq += n_edge;
+	graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
+	graph->lp = isl_basic_set_set_rational(graph->lp);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][0], -n_edge);
+	isl_int_set_si(graph->lp->eq[k][1], 1);
+	for (i = 0; i < n_edge; ++i)
+		isl_int_set_si(graph->lp->eq[k][4 + i], 1);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][2], -1);
+	for (i = 0; i < graph->n; ++i) {
+		int pos = 1 + graph->node[i].start + 1;
+
+		for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][3], -1);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+		for (j = 0; j < 2 * node->nvar; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	for (i = 0; i < n_edge; ++i) {
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			return -1;
+		isl_seq_clr(graph->lp->ineq[k], 1 +  total);
+		isl_int_set_si(graph->lp->ineq[k][4 + i], -1);
+		isl_int_set_si(graph->lp->ineq[k][0], 1);
+	}
+
+	if (add_bound_coefficient_constraints(ctx, graph) < 0)
+		return -1;
+	if (add_all_constraints(graph) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* If the schedule_split_scaled option is set and if the linear
+ * parts of the scheduling rows for all nodes in the graphs have
+ * non-trivial common divisor, then split off the constant term
+ * from the linear part.
+ * The constant term is then placed in a separate band and
+ * the linear part is reduced.
+ */
+static int split_scaled(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+	int row;
+	isl_int gcd, gcd_i;
+
+	if (!ctx->opt->schedule_split_scaled)
+		return 0;
+	if (graph->n <= 1)
+		return 0;
+
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(ctx, isl_error_internal,
+			"too many schedule rows", return -1);
+
+	isl_int_init(gcd);
+	isl_int_init(gcd_i);
+
+	isl_int_set_si(gcd, 0);
+
+	row = isl_mat_rows(graph->node[0].sched) - 1;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int cols = isl_mat_cols(node->sched);
+
+		isl_seq_gcd(node->sched->row[row] + 1, cols - 1, &gcd_i);
+		isl_int_gcd(gcd, gcd, gcd_i);
+	}
+
+	isl_int_clear(gcd_i);
+
+	if (isl_int_cmp_si(gcd, 1) <= 0) {
+		isl_int_clear(gcd);
+		return 0;
+	}
+
+	next_band(graph);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_zero_rows(node->sched, 1);
+		if (!node->sched)
+			goto error;
+		isl_int_fdiv_r(node->sched->row[row + 1][0],
+			       node->sched->row[row][0], gcd);
+		isl_int_fdiv_q(node->sched->row[row][0],
+			       node->sched->row[row][0], gcd);
+		isl_int_mul(node->sched->row[row][0],
+			    node->sched->row[row][0], gcd);
+		node->sched = isl_mat_scale_down_row(node->sched, row, gcd);
+		if (!node->sched)
+			goto error;
+		node->band[graph->n_total_row] = graph->n_band;
+	}
+
+	graph->n_total_row++;
+
+	isl_int_clear(gcd);
+	return 0;
+error:
+	isl_int_clear(gcd);
+	return -1;
+}
+
+static int compute_component_schedule(isl_ctx *ctx,
+	struct isl_sched_graph *graph);
+
+/* Is the schedule row "sol" trivial on node "node"?
+ * That is, is the solution zero on the dimensions orthogonal to
+ * the previously found solutions?
+ * Return 1 if the solution is trivial, 0 if it is not and -1 on error.
+ *
+ * Each coefficient is represented as the difference between
+ * two non-negative values in "sol".  "sol" has been computed
+ * in terms of the original iterators (i.e., without use of cmap).
+ * We construct the schedule row s and write it as a linear
+ * combination of (linear combinations of) previously computed schedule rows.
+ * s = Q c or c = U s.
+ * If the final entries of c are all zero, then the solution is trivial.
+ */
+static int is_trivial(struct isl_sched_node *node, __isl_keep isl_vec *sol)
+{
+	int i;
+	int pos;
+	int trivial;
+	isl_ctx *ctx;
+	isl_vec *node_sol;
+
+	if (!sol)
+		return -1;
+	if (node->nvar == node->rank)
+		return 0;
+
+	ctx = isl_vec_get_ctx(sol);
+	node_sol = isl_vec_alloc(ctx, node->nvar);
+	if (!node_sol)
+		return -1;
+
+	pos = 1 + node->start + 1 + 2 * node->nparam;
+
+	for (i = 0; i < node->nvar; ++i)
+		isl_int_sub(node_sol->el[i],
+			    sol->el[pos + 2 * i + 1], sol->el[pos + 2 * i]);
+
+	node_sol = isl_mat_vec_product(isl_mat_copy(node->cinv), node_sol);
+
+	if (!node_sol)
+		return -1;
+
+	trivial = isl_seq_first_non_zero(node_sol->el + node->rank,
+					node->nvar - node->rank) == -1;
+
+	isl_vec_free(node_sol);
+
+	return trivial;
+}
+
+/* Is the schedule row "sol" trivial on any node where it should
+ * not be trivial?
+ * "sol" has been computed in terms of the original iterators
+ * (i.e., without use of cmap).
+ * Return 1 if any solution is trivial, 0 if they are not and -1 on error.
+ */
+static int is_any_trivial(struct isl_sched_graph *graph,
+	__isl_keep isl_vec *sol)
+{
+	int i;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int trivial;
+
+		if (!needs_row(graph, node))
+			continue;
+		trivial = is_trivial(node, sol);
+		if (trivial < 0 || trivial)
+			return trivial;
+	}
+
+	return 0;
+}
+
+/* Construct a schedule row for each node such that as many dependences
+ * as possible are carried and then continue with the next band.
+ *
+ * If the computed schedule row turns out to be trivial on one or
+ * more nodes where it should not be trivial, then we throw it away
+ * and try again on each component separately.
+ *
+ * If there is only one component, then we accept the schedule row anyway,
+ * but we do not consider it as a complete row and therefore do not
+ * increment graph->n_row.  Note that the ranks of the nodes that
+ * do get a non-trivial schedule part will get updated regardless and
+ * graph->maxvar is computed based on these ranks.  The test for
+ * whether more schedule rows are required in compute_schedule_wcc
+ * is therefore not affected.
+ */
+static int carry_dependences(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+	int n_edge;
+	int trivial;
+	isl_vec *sol;
+	isl_basic_set *lp;
+
+	n_edge = 0;
+	for (i = 0; i < graph->n_edge; ++i)
+		n_edge += graph->edge[i].map->n;
+
+	if (setup_carry_lp(ctx, graph) < 0)
+		return -1;
+
+	lp = isl_basic_set_copy(graph->lp);
+	sol = isl_tab_basic_set_non_neg_lexmin(lp);
+	if (!sol)
+		return -1;
+
+	if (sol->size == 0) {
+		isl_vec_free(sol);
+		isl_die(ctx, isl_error_internal,
+			"error in schedule construction", return -1);
+	}
+
+	isl_int_divexact(sol->el[1], sol->el[1], sol->el[0]);
+	if (isl_int_cmp_si(sol->el[1], n_edge) >= 0) {
+		isl_vec_free(sol);
+		isl_die(ctx, isl_error_unknown,
+			"unable to carry dependences", return -1);
+	}
+
+	trivial = is_any_trivial(graph, sol);
+	if (trivial < 0) {
+		sol = isl_vec_free(sol);
+	} else if (trivial && graph->scc > 1) {
+		isl_vec_free(sol);
+		return compute_component_schedule(ctx, graph);
+	}
+
+	if (update_schedule(graph, sol, 0, 0) < 0)
+		return -1;
+	if (trivial)
+		graph->n_row--;
+
+	if (split_scaled(ctx, graph) < 0)
+		return -1;
+
+	return compute_next_band(ctx, graph);
+}
+
+/* Are there any (non-empty) (conditional) validity edges in the graph?
+ */
+static int has_validity_edges(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		int empty;
+
+		empty = isl_map_plain_is_empty(graph->edge[i].map);
+		if (empty < 0)
+			return -1;
+		if (empty)
+			continue;
+		if (graph->edge[i].validity ||
+		    graph->edge[i].conditional_validity)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Should we apply a Feautrier step?
+ * That is, did the user request the Feautrier algorithm and are
+ * there any validity dependences (left)?
+ */
+static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	if (ctx->opt->schedule_algorithm != ISL_SCHEDULE_ALGORITHM_FEAUTRIER)
+		return 0;
+
+	return has_validity_edges(graph);
+}
+
+/* Compute a schedule for a connected dependence graph using Feautrier's
+ * multi-dimensional scheduling algorithm.
+ * The original algorithm is described in [1].
+ * The main idea is to minimize the number of scheduling dimensions, by
+ * trying to satisfy as many dependences as possible per scheduling dimension.
+ *
+ * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling
+ *     Problem, Part II: Multi-Dimensional Time.
+ *     In Intl. Journal of Parallel Programming, 1992.
+ */
+static int compute_schedule_wcc_feautrier(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	return carry_dependences(ctx, graph);
+}
+
+/* Turn off the "local" bit on all (condition) edges.
+ */
+static void clear_local_edges(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i)
+		if (graph->edge[i].condition)
+			graph->edge[i].local = 0;
+}
+
+/* Does "graph" have both condition and conditional validity edges?
+ */
+static int need_condition_check(struct isl_sched_graph *graph)
+{
+	int i;
+	int any_condition = 0;
+	int any_conditional_validity = 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (graph->edge[i].condition)
+			any_condition = 1;
+		if (graph->edge[i].conditional_validity)
+			any_conditional_validity = 1;
+	}
+
+	return any_condition && any_conditional_validity;
+}
+
+/* Does "graph" contain any coincidence edge?
+ */
+static int has_any_coincidence(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i)
+		if (graph->edge[i].coincidence)
+			return 1;
+
+	return 0;
+}
+
+/* Extract the final schedule row as a map with the iteration domain
+ * of "node" as domain.
+ */
+static __isl_give isl_map *final_row(struct isl_sched_node *node)
+{
+	isl_local_space *ls;
+	isl_aff *aff;
+	int row;
+
+	row = isl_mat_rows(node->sched) - 1;
+	ls = isl_local_space_from_space(isl_space_copy(node->space));
+	aff = extract_schedule_row(ls, node, row);
+	return isl_map_from_aff(aff);
+}
+
+/* Is the conditional validity dependence in the edge with index "edge_index"
+ * violated by the latest (i.e., final) row of the schedule?
+ * That is, is i scheduled after j
+ * for any conditional validity dependence i -> j?
+ */
+static int is_violated(struct isl_sched_graph *graph, int edge_index)
+{
+	isl_map *src_sched, *dst_sched, *map;
+	struct isl_sched_edge *edge = &graph->edge[edge_index];
+	int empty;
+
+	src_sched = final_row(edge->src);
+	dst_sched = final_row(edge->dst);
+	map = isl_map_copy(edge->map);
+	map = isl_map_apply_domain(map, src_sched);
+	map = isl_map_apply_range(map, dst_sched);
+	map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_out, 0);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0)
+		return -1;
+
+	return !empty;
+}
+
+/* Does the domain of "umap" intersect "uset"?
+ */
+static int domain_intersects(__isl_keep isl_union_map *umap,
+	__isl_keep isl_union_set *uset)
+{
+	int empty;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(uset));
+	empty = isl_union_map_is_empty(umap);
+	isl_union_map_free(umap);
+
+	return empty < 0 ? -1 : !empty;
+}
+
+/* Does the range of "umap" intersect "uset"?
+ */
+static int range_intersects(__isl_keep isl_union_map *umap,
+	__isl_keep isl_union_set *uset)
+{
+	int empty;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_intersect_range(umap, isl_union_set_copy(uset));
+	empty = isl_union_map_is_empty(umap);
+	isl_union_map_free(umap);
+
+	return empty < 0 ? -1 : !empty;
+}
+
+/* Are the condition dependences of "edge" local with respect to
+ * the current schedule?
+ *
+ * That is, are domain and range of the condition dependences mapped
+ * to the same point?
+ *
+ * In other words, is the condition false?
+ */
+static int is_condition_false(struct isl_sched_edge *edge)
+{
+	isl_union_map *umap;
+	isl_map *map, *sched, *test;
+	int local;
+
+	umap = isl_union_map_copy(edge->tagged_condition);
+	umap = isl_union_map_zip(umap);
+	umap = isl_union_set_unwrap(isl_union_map_domain(umap));
+	map = isl_map_from_union_map(umap);
+
+	sched = node_extract_schedule(edge->src);
+	map = isl_map_apply_domain(map, sched);
+	sched = node_extract_schedule(edge->dst);
+	map = isl_map_apply_range(map, sched);
+
+	test = isl_map_identity(isl_map_get_space(map));
+	local = isl_map_is_subset(map, test);
+	isl_map_free(map);
+	isl_map_free(test);
+
+	return local;
+}
+
+/* Does "graph" have any satisfied condition edges that
+ * are adjacent to the conditional validity constraint with
+ * domain "conditional_source" and range "conditional_sink"?
+ *
+ * A satisfied condition is one that is not local.
+ * If a condition was forced to be local already (i.e., marked as local)
+ * then there is no need to check if it is in fact local.
+ *
+ * Additionally, mark all adjacent condition edges found as local.
+ */
+static int has_adjacent_true_conditions(struct isl_sched_graph *graph,
+	__isl_keep isl_union_set *conditional_source,
+	__isl_keep isl_union_set *conditional_sink)
+{
+	int i;
+	int any = 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		int adjacent, local;
+		isl_union_map *condition;
+
+		if (!graph->edge[i].condition)
+			continue;
+		if (graph->edge[i].local)
+			continue;
+
+		condition = graph->edge[i].tagged_condition;
+		adjacent = domain_intersects(condition, conditional_sink);
+		if (adjacent >= 0 && !adjacent)
+			adjacent = range_intersects(condition,
+							conditional_source);
+		if (adjacent < 0)
+			return -1;
+		if (!adjacent)
+			continue;
+
+		graph->edge[i].local = 1;
+
+		local = is_condition_false(&graph->edge[i]);
+		if (local < 0)
+			return -1;
+		if (!local)
+			any = 1;
+	}
+
+	return any;
+}
+
+/* Are there any violated conditional validity dependences with
+ * adjacent condition dependences that are not local with respect
+ * to the current schedule?
+ * That is, is the conditional validity constraint violated?
+ *
+ * Additionally, mark all those adjacent condition dependences as local.
+ * We also mark those adjacent condition dependences that were not marked
+ * as local before, but just happened to be local already.  This ensures
+ * that they remain local if the schedule is recomputed.
+ *
+ * We first collect domain and range of all violated conditional validity
+ * dependences and then check if there are any adjacent non-local
+ * condition dependences.
+ */
+static int has_violated_conditional_constraint(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i;
+	int any = 0;
+	isl_union_set *source, *sink;
+
+	source = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	sink = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	for (i = 0; i < graph->n_edge; ++i) {
+		isl_union_set *uset;
+		isl_union_map *umap;
+		int violated;
+
+		if (!graph->edge[i].conditional_validity)
+			continue;
+
+		violated = is_violated(graph, i);
+		if (violated < 0)
+			goto error;
+		if (!violated)
+			continue;
+
+		any = 1;
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_validity);
+		uset = isl_union_map_domain(umap);
+		source = isl_union_set_union(source, uset);
+		source = isl_union_set_coalesce(source);
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_validity);
+		uset = isl_union_map_range(umap);
+		sink = isl_union_set_union(sink, uset);
+		sink = isl_union_set_coalesce(sink);
+	}
+
+	if (any)
+		any = has_adjacent_true_conditions(graph, source, sink);
+
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return any;
+error:
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return -1;
+}
+
+/* Compute a schedule for a connected dependence graph.
+ * We try to find a sequence of as many schedule rows as possible that result
+ * in non-negative dependence distances (independent of the previous rows
+ * in the sequence, i.e., such that the sequence is tilable), with as
+ * many of the initial rows as possible satisfying the coincidence constraints.
+ * If we can't find any more rows we either
+ * - split between SCCs and start over (assuming we found an interesting
+ *	pair of SCCs between which to split)
+ * - continue with the next band (assuming the current band has at least
+ *	one row)
+ * - try to carry as many dependences as possible and continue with the next
+ *	band
+ *
+ * If Feautrier's algorithm is selected, we first recursively try to satisfy
+ * as many validity dependences as possible. When all validity dependences
+ * are satisfied we extend the schedule to a full-dimensional schedule.
+ *
+ * If we manage to complete the schedule, we finish off by topologically
+ * sorting the statements based on the remaining dependences.
+ *
+ * If ctx->opt->schedule_outer_coincidence is set, then we force the
+ * outermost dimension to satisfy the coincidence constraints.  If this
+ * turns out to be impossible, we fall back on the general scheme above
+ * and try to carry as many dependences as possible.
+ *
+ * If "graph" contains both condition and conditional validity dependences,
+ * then we need to check that that the conditional schedule constraint
+ * is satisfied, i.e., there are no violated conditional validity dependences
+ * that are adjacent to any non-local condition dependences.
+ * If there are, then we mark all those adjacent condition dependences
+ * as local and recompute the current band.  Those dependences that
+ * are marked local will then be forced to be local.
+ * The initial computation is performed with no dependences marked as local.
+ * If we are lucky, then there will be no violated conditional validity
+ * dependences adjacent to any non-local condition dependences.
+ * Otherwise, we mark some additional condition dependences as local and
+ * recompute.  We continue this process until there are no violations left or
+ * until we are no longer able to compute a schedule.
+ * Since there are only a finite number of dependences,
+ * there will only be a finite number of iterations.
+ */
+static int compute_schedule_wcc(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int has_coincidence;
+	int use_coincidence;
+	int force_coincidence = 0;
+	int check_conditional;
+
+	if (detect_sccs(ctx, graph) < 0)
+		return -1;
+	if (sort_sccs(graph) < 0)
+		return -1;
+
+	if (compute_maxvar(graph) < 0)
+		return -1;
+
+	if (need_feautrier_step(ctx, graph))
+		return compute_schedule_wcc_feautrier(ctx, graph);
+
+	clear_local_edges(graph);
+	check_conditional = need_condition_check(graph);
+	has_coincidence = has_any_coincidence(graph);
+
+	if (ctx->opt->schedule_outer_coincidence)
+		force_coincidence = 1;
+
+	use_coincidence = has_coincidence;
+	while (graph->n_row < graph->maxvar) {
+		isl_vec *sol;
+		int violated;
+		int coincident;
+
+		graph->src_scc = -1;
+		graph->dst_scc = -1;
+
+		if (setup_lp(ctx, graph, use_coincidence) < 0)
+			return -1;
+		sol = solve_lp(graph);
+		if (!sol)
+			return -1;
+		if (sol->size == 0) {
+			int empty = graph->n_total_row == graph->band_start;
+
+			isl_vec_free(sol);
+			if (use_coincidence && (!force_coincidence || !empty)) {
+				use_coincidence = 0;
+				continue;
+			}
+			if (!ctx->opt->schedule_maximize_band_depth && !empty)
+				return compute_next_band(ctx, graph);
+			if (graph->src_scc >= 0)
+				return compute_split_schedule(ctx, graph);
+			if (!empty)
+				return compute_next_band(ctx, graph);
+			return carry_dependences(ctx, graph);
+		}
+		coincident = !has_coincidence || use_coincidence;
+		if (update_schedule(graph, sol, 1, coincident) < 0)
+			return -1;
+
+		if (!check_conditional)
+			continue;
+		violated = has_violated_conditional_constraint(ctx, graph);
+		if (violated < 0)
+			return -1;
+		if (!violated)
+			continue;
+		if (reset_band(graph) < 0)
+			return -1;
+		use_coincidence = has_coincidence;
+	}
+
+	if (graph->n_total_row > graph->band_start)
+		next_band(graph);
+	return sort_statements(ctx, graph);
+}
+
+/* Add a row to the schedules that separates the SCCs and move
+ * to the next band.
+ */
+static int split_on_scc(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(ctx, isl_error_internal,
+			"too many schedule rows", return -1);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int row = isl_mat_rows(node->sched);
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_zero_rows(node->sched, 1);
+		node->sched = isl_mat_set_element_si(node->sched, row, 0,
+						     node->scc);
+		if (!node->sched)
+			return -1;
+		node->band[graph->n_total_row] = graph->n_band;
+	}
+
+	graph->n_total_row++;
+	next_band(graph);
+
+	return 0;
+}
+
+/* Compute a schedule for each component (identified by node->scc)
+ * of the dependence graph separately and then combine the results.
+ * Depending on the setting of schedule_fuse, a component may be
+ * either weakly or strongly connected.
+ *
+ * The band_id is adjusted such that each component has a separate id.
+ * Note that the band_id may have already been set to a value different
+ * from zero by compute_split_schedule.
+ */
+static int compute_component_schedule(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int wcc, i;
+	int n, n_edge;
+	int n_total_row, orig_total_row;
+	int n_band, orig_band;
+
+	if (ctx->opt->schedule_fuse == ISL_SCHEDULE_FUSE_MIN ||
+	    ctx->opt->schedule_separate_components)
+		if (split_on_scc(ctx, graph) < 0)
+			return -1;
+
+	n_total_row = 0;
+	orig_total_row = graph->n_total_row;
+	n_band = 0;
+	orig_band = graph->n_band;
+	for (i = 0; i < graph->n; ++i)
+		graph->node[i].band_id[graph->n_band] += graph->node[i].scc;
+	for (wcc = 0; wcc < graph->scc; ++wcc) {
+		n = 0;
+		for (i = 0; i < graph->n; ++i)
+			if (graph->node[i].scc == wcc)
+				n++;
+		n_edge = 0;
+		for (i = 0; i < graph->n_edge; ++i)
+			if (graph->edge[i].src->scc == wcc &&
+			    graph->edge[i].dst->scc == wcc)
+				n_edge++;
+
+		if (compute_sub_schedule(ctx, graph, n, n_edge,
+				    &node_scc_exactly,
+				    &edge_scc_exactly, wcc, 1) < 0)
+			return -1;
+		if (graph->n_total_row > n_total_row)
+			n_total_row = graph->n_total_row;
+		graph->n_total_row = orig_total_row;
+		if (graph->n_band > n_band)
+			n_band = graph->n_band;
+		graph->n_band = orig_band;
+	}
+
+	graph->n_total_row = n_total_row;
+	graph->n_band = n_band;
+
+	return pad_schedule(graph);
+}
+
+/* Compute a schedule for the given dependence graph.
+ * We first check if the graph is connected (through validity and conditional
+ * validity dependences) and, if not, compute a schedule
+ * for each component separately.
+ * If schedule_fuse is set to minimal fusion, then we check for strongly
+ * connected components instead and compute a separate schedule for
+ * each such strongly connected component.
+ */
+static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	if (ctx->opt->schedule_fuse == ISL_SCHEDULE_FUSE_MIN) {
+		if (detect_sccs(ctx, graph) < 0)
+			return -1;
+	} else {
+		if (detect_wccs(ctx, graph) < 0)
+			return -1;
+	}
+
+	if (graph->scc > 1)
+		return compute_component_schedule(ctx, graph);
+
+	return compute_schedule_wcc(ctx, graph);
+}
+
+/* Compute a schedule on sc->domain that respects the given schedule
+ * constraints.
+ *
+ * In particular, the schedule respects all the validity dependences.
+ * If the default isl scheduling algorithm is used, it tries to minimize
+ * the dependence distances over the proximity dependences.
+ * If Feautrier's scheduling algorithm is used, the proximity dependence
+ * distances are only minimized during the extension to a full-dimensional
+ * schedule.
+ *
+ * If there are any condition and conditional validity dependences,
+ * then the conditional validity dependences may be violated inside
+ * a tilable band, provided they have no adjacent non-local
+ * condition dependences.
+ */
+__isl_give isl_schedule *isl_schedule_constraints_compute_schedule(
+	__isl_take isl_schedule_constraints *sc)
+{
+	isl_ctx *ctx = isl_schedule_constraints_get_ctx(sc);
+	struct isl_sched_graph graph = { 0 };
+	isl_schedule *sched;
+	struct isl_extract_edge_data data;
+	enum isl_edge_type i;
+
+	sc = isl_schedule_constraints_align_params(sc);
+	if (!sc)
+		return NULL;
+
+	graph.n = isl_union_set_n_set(sc->domain);
+	if (graph.n == 0)
+		goto empty;
+	if (graph_alloc(ctx, &graph, graph.n,
+	    isl_schedule_constraints_n_map(sc)) < 0)
+		goto error;
+	if (compute_max_row(&graph, sc) < 0)
+		goto error;
+	graph.root = 1;
+	graph.n = 0;
+	if (isl_union_set_foreach_set(sc->domain, &extract_node, &graph) < 0)
+		goto error;
+	if (graph_init_table(ctx, &graph) < 0)
+		goto error;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		graph.max_edge[i] = isl_union_map_n_map(sc->constraint[i]);
+	if (graph_init_edge_tables(ctx, &graph) < 0)
+		goto error;
+	graph.n_edge = 0;
+	data.graph = &graph;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		data.type = i;
+		if (isl_union_map_foreach_map(sc->constraint[i],
+						&extract_edge, &data) < 0)
+			goto error;
+	}
+
+	if (compute_schedule(ctx, &graph) < 0)
+		goto error;
+
+empty:
+	sched = extract_schedule(&graph, isl_union_set_get_space(sc->domain));
+
+	graph_free(ctx, &graph);
+	isl_schedule_constraints_free(sc);
+
+	return sched;
+error:
+	graph_free(ctx, &graph);
+	isl_schedule_constraints_free(sc);
+	return NULL;
+}
+
+/* Compute a schedule for the given union of domains that respects
+ * all the validity dependences and minimizes
+ * the dependence distances over the proximity dependences.
+ *
+ * This function is kept for backward compatibility.
+ */
+__isl_give isl_schedule *isl_union_set_compute_schedule(
+	__isl_take isl_union_set *domain,
+	__isl_take isl_union_map *validity,
+	__isl_take isl_union_map *proximity)
+{
+	isl_schedule_constraints *sc;
+
+	sc = isl_schedule_constraints_on_domain(domain);
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+
+	return isl_schedule_constraints_compute_schedule(sc);
+}

Added: polly/trunk/lib/External/isl/isl_seq.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_seq.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_seq.c (added)
+++ polly/trunk/lib/External/isl/isl_seq.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,321 @@
+/*
+ * 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_seq.h>
+
+void isl_seq_clr(isl_int *p, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set_si(p[i], 0);
+}
+
+void isl_seq_set_si(isl_int *p, int v, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set_si(p[i], v);
+}
+
+void isl_seq_set(isl_int *p, isl_int v, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set(p[i], v);
+}
+
+void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_neg(dst[i], src[i]);
+}
+
+void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set(dst[i], src[i]);
+}
+
+void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_submul(dst[i], f, src[i]);
+}
+
+void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_addmul(dst[i], f, src[i]);
+}
+
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_swap_or_set(dst[i], src[i]);
+}
+
+void isl_seq_scale(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_mul(dst[i], src[i], m);
+}
+
+void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_divexact(dst[i], src[i], m);
+}
+
+void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_cdiv_q(dst[i], src[i], m);
+}
+
+void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_fdiv_q(dst[i], src[i], m);
+}
+
+void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_fdiv_r(dst[i], src[i], m);
+}
+
+void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1,
+			isl_int m2, isl_int *src2, unsigned len)
+{
+	int i;
+	isl_int tmp;
+
+	isl_int_init(tmp);
+	for (i = 0; i < len; ++i) {
+		isl_int_mul(tmp, m1, src1[i]);
+		isl_int_addmul(tmp, m2, src2[i]);
+		isl_int_set(dst[i], tmp);
+	}
+	isl_int_clear(tmp);
+}
+
+/*
+ * Let d = dst[pos] and s = src[pos]
+ * dst is replaced by |s| dst - sgn(s)d src
+ */
+void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len,
+		  isl_int *m)
+{
+	isl_int a;
+	isl_int b;
+
+	if (isl_int_is_zero(dst[pos]))
+		return;
+
+	isl_int_init(a);
+	isl_int_init(b);
+
+	isl_int_gcd(a, src[pos], dst[pos]);
+	isl_int_divexact(b, dst[pos], a);
+	if (isl_int_is_pos(src[pos]))
+		isl_int_neg(b, b);
+	isl_int_divexact(a, src[pos], a);
+	isl_int_abs(a, a);
+	isl_seq_combine(dst, a, dst, b, src, len);
+
+	if (m)
+		isl_int_mul(*m, *m, a);
+
+	isl_int_clear(a);
+	isl_int_clear(b);
+}
+
+int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		if (isl_int_ne(p1[i], p2[i]))
+			return 0;
+	return 1;
+}
+
+int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+	int cmp;
+	for (i = 0; i < len; ++i)
+		if ((cmp = isl_int_cmp(p1[i], p2[i])) != 0)
+			return cmp;
+	return 0;
+}
+
+int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (isl_int_abs_ne(p1[i], p2[i]))
+			return 0;
+		if (isl_int_is_zero(p1[i]))
+			continue;
+		if (isl_int_eq(p1[i], p2[i]))
+			return 0;
+	}
+	return 1;
+}
+
+int isl_seq_first_non_zero(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i)
+		if (!isl_int_is_zero(p[i]))
+			return i;
+	return -1;
+}
+
+int isl_seq_last_non_zero(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; --i)
+		if (!isl_int_is_zero(p[i]))
+			return i;
+	return -1;
+}
+
+void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max)
+{
+	int i;
+
+	isl_int_set_si(*max, 0);
+
+	for (i = 0; i < len; ++i)
+		if (isl_int_abs_gt(p[i], *max))
+			isl_int_abs(*max, p[i]);
+}
+
+int isl_seq_abs_min_non_zero(isl_int *p, unsigned len)
+{
+	int i, min = isl_seq_first_non_zero(p, len);
+	if (min < 0)
+		return -1;
+	for (i = min + 1; i < len; ++i) {
+		if (isl_int_is_zero(p[i]))
+			continue;
+		if (isl_int_abs_lt(p[i], p[min]))
+			min = i;
+	}
+	return min;
+}
+
+void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd)
+{
+	int i, min = isl_seq_abs_min_non_zero(p, len);
+
+	if (min < 0) {
+		isl_int_set_si(*gcd, 0);
+		return;
+	}
+	isl_int_abs(*gcd, p[min]);
+	for (i = 0; isl_int_cmp_si(*gcd, 1) > 0 && i < len; ++i) {
+		if (i == min)
+			continue;
+		if (isl_int_is_zero(p[i]))
+			continue;
+		isl_int_gcd(*gcd, *gcd, p[i]);
+	}
+}
+
+void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len)
+{
+	if (len == 0)
+		return;
+	isl_seq_gcd(p, len, &ctx->normalize_gcd);
+	if (!isl_int_is_zero(ctx->normalize_gcd) &&
+	    !isl_int_is_one(ctx->normalize_gcd))
+		isl_seq_scale_down(p, p, ctx->normalize_gcd, len);
+}
+
+void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm)
+{
+	int i;
+
+	if (len == 0) {
+		isl_int_set_si(*lcm, 1);
+		return;
+	}
+	isl_int_set(*lcm, p[0]);
+	for (i = 1; i < len; ++i)
+		isl_int_lcm(*lcm, *lcm, p[i]);
+}
+
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+			   isl_int *prod)
+{
+	int i;
+	if (len == 0) {
+		isl_int_set_si(*prod, 0);
+		return;
+	}
+	isl_int_mul(*prod, p1[0], p2[0]);
+	for (i = 1; i < len; ++i)
+		isl_int_addmul(*prod, p1[i], p2[i]);
+}
+
+uint32_t isl_seq_hash(isl_int *p, unsigned len, uint32_t hash)
+{
+	int i;
+	for (i = 0; i < len; ++i) {
+		if (isl_int_is_zero(p[i]))
+			continue;
+		hash *= 16777619;
+		hash ^= (i & 0xFF);
+		hash = isl_int_hash(p[i], hash);
+	}
+	return hash;
+}
+
+uint32_t isl_seq_get_hash(isl_int *p, unsigned len)
+{
+	uint32_t hash = isl_hash_init();
+
+	return isl_seq_hash(p, len, hash);
+}
+
+uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits)
+{
+	uint32_t hash;
+
+	hash = isl_seq_get_hash(p, len);
+	return isl_hash_bits(hash, bits);
+}
+
+void isl_seq_dump(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (i)
+			fprintf(stderr, " ");
+		isl_int_print(stderr, p[i], 0);
+	}
+	fprintf(stderr, "\n");
+}

Added: polly/trunk/lib/External/isl/isl_seq.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_seq.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_seq.h (added)
+++ polly/trunk/lib/External/isl/isl_seq.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,60 @@
+/*
+ * 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_SEQ_H
+#define ISL_SEQ_H
+
+#include <sys/types.h>
+#include <isl_int.h>
+#include <isl/ctx.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Some common operations on sequences of isl_int's */
+
+void isl_seq_clr(isl_int *p, unsigned len);
+void isl_seq_set(isl_int *p, isl_int v, unsigned len);
+void isl_seq_set_si(isl_int *p, int v, unsigned len);
+void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len);
+void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len);
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_scale(isl_int *dst, isl_int *src, isl_int f, unsigned len);
+void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int f, unsigned len);
+void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1,
+			isl_int m2, isl_int *src2, unsigned len);
+void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len,
+		  isl_int *m);
+void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max);
+void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd);
+void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm);
+void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len);
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+			   isl_int *prod);
+int isl_seq_first_non_zero(isl_int *p, unsigned len);
+int isl_seq_last_non_zero(isl_int *p, unsigned len);
+int isl_seq_abs_min_non_zero(isl_int *p, unsigned len);
+int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len);
+int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len);
+int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len);
+
+uint32_t isl_seq_get_hash(isl_int *p, unsigned len);
+uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

Added: polly/trunk/lib/External/isl/isl_set_list.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_set_list.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_set_list.c (added)
+++ polly/trunk/lib/External/isl/isl_set_list.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,21 @@
+#include <isl/set.h>
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE basic_set
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE set
+
+#include <isl_list_templ.c>

Added: polly/trunk/lib/External/isl/isl_sort.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_sort.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_sort.c (added)
+++ polly/trunk/lib/External/isl/isl_sort.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,157 @@
+/*
+ * The code of this file was taken from http://jeffreystedfast.blogspot.be,
+ * where it was posted in 2011 by Jeffrey Stedfast under the MIT license.
+ * The MIT license text is as follows:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <isl_sort.h>
+
+#define MID(lo, hi) (lo + ((hi - lo) >> 1))
+
+/* The code here is an optimized merge sort. Starting from a generic merge sort
+ * the following optimizations were applied:
+ *
+ * o Batching of memcpy() calls: Instead of calling memcpy() to copy each and
+ *   every element into a temporary buffer, blocks of elements are copied
+ *   at a time.
+ *
+ * o To reduce the number of memcpy() calls further, copying leading
+ *   and trailing elements into our temporary buffer is avoided, in case it is
+ *   not necessary to merge them.
+ *
+ * A further optimization could be to specialize memcpy calls based on the
+ * size of the types we compare. For now, this code does not include the
+ * relevant optimization, as clang e.g. inlines a very efficient memcpy()
+ * implementation. It is not clear, that the specialized version as provided in
+ * the blog post, is really superior to the one that will be inlined by
+ * default. So we decided to keep the code simple until this optimization was
+ * proven to be beneficial.
+ */
+
+static void
+msort (void *array, void *buf, size_t low, size_t high, size_t size,
+       int (* compare) (const void *, const void *, void *), void *arg)
+{
+    char *a1, *al, *am, *ah, *ls, *hs, *lo, *hi, *b;
+    size_t copied = 0;
+    size_t mid;
+
+    mid = MID (low, high);
+
+    if (mid + 1 < high)
+        msort (array, buf, mid + 1, high, size, compare, arg);
+
+    if (mid > low)
+        msort (array, buf, low, mid, size, compare, arg);
+
+    ah = ((char *) array) + ((high + 1) * size);
+    am = ((char *) array) + ((mid + 1) * size);
+    a1 = al = ((char *) array) + (low * size);
+
+    b = (char *) buf;
+    lo = al;
+    hi = am;
+
+    do {
+        ls = lo;
+        hs = hi;
+
+        if (lo > al || hi > am) {
+            /* our last loop already compared lo & hi and found lo <= hi */
+            lo += size;
+        }
+
+        while (lo < am && compare (lo, hi, arg) <= 0)
+            lo += size;
+
+        if (lo < am) {
+            if (copied == 0) {
+                /* avoid copying the leading items */
+                a1 = lo;
+                ls = lo;
+            }
+
+            /* our last compare tells us hi < lo */
+            hi += size;
+
+            while (hi < ah && compare (hi, lo, arg) < 0)
+                hi += size;
+
+            if (lo > ls) {
+                memcpy (b, ls, lo - ls);
+                copied += (lo - ls);
+                b += (lo - ls);
+            }
+
+            memcpy (b, hs, hi - hs);
+            copied += (hi - hs);
+            b += (hi - hs);
+        } else if (copied) {
+            memcpy (b, ls, lo - ls);
+            copied += (lo - ls);
+            b += (lo - ls);
+
+            /* copy everything we needed to re-order back into array */
+            memcpy (a1, buf, copied);
+            return;
+        } else {
+            /* everything already in order */
+            return;
+        }
+    } while (hi < ah);
+
+    if (lo < am) {
+        memcpy (b, lo, am - lo);
+        copied += (am - lo);
+    }
+
+    memcpy (a1, buf, copied);
+}
+
+static int
+MergeSort (void *base, size_t nmemb, size_t size,
+           int (* compare) (const void *, const void *, void *), void *arg)
+{
+    void *tmp;
+
+    if (nmemb < 2)
+        return 0;
+
+    if (!(tmp = malloc (nmemb * size))) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    msort (base, tmp, 0, nmemb - 1, size, compare, arg);
+
+    free (tmp);
+
+    return 0;
+}
+
+int isl_sort(void *const pbase, size_t total_elems, size_t size,
+	int (*cmp)(const void *, const void *, void *arg), void *arg)
+{
+    return MergeSort (pbase, total_elems, size, cmp, arg);
+}

Added: polly/trunk/lib/External/isl/isl_sort.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_sort.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_sort.h (added)
+++ polly/trunk/lib/External/isl/isl_sort.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,9 @@
+#ifndef ISL_SORT_H
+#define ISL_SORT_H
+
+#include <stddef.h>
+
+int isl_sort(void *const pbase, size_t total_elems, size_t size,
+	int (*cmp)(const void *, const void *, void *arg), void *arg);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_space.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_space.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_space.c (added)
+++ polly/trunk/lib/External/isl/isl_space.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,2379 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2013-2014 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 <stdlib.h>
+#include <string.h>
+#include <isl_space_private.h>
+#include <isl_id_private.h>
+#include <isl_reordering.h>
+
+isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim)
+{
+	return dim ? dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	isl_space *dim;
+
+	dim = isl_alloc_type(ctx, struct isl_space);
+	if (!dim)
+		return NULL;
+
+	dim->ctx = ctx;
+	isl_ctx_ref(ctx);
+	dim->ref = 1;
+	dim->nparam = nparam;
+	dim->n_in = n_in;
+	dim->n_out = n_out;
+
+	dim->tuple_id[0] = NULL;
+	dim->tuple_id[1] = NULL;
+
+	dim->nested[0] = NULL;
+	dim->nested[1] = NULL;
+
+	dim->n_id = 0;
+	dim->ids = NULL;
+
+	return dim;
+}
+
+/* Mark the space as being that of a set, by setting the domain tuple
+ * to isl_id_none.
+ */
+static __isl_give isl_space *mark_as_set(__isl_take isl_space *space)
+{
+	space = isl_space_cow(space);
+	if (!space)
+		return NULL;
+	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
+	return space;
+}
+
+/* Is the space that of a set?
+ */
+int isl_space_is_set(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+	if (space->n_in != 0 || space->nested[0])
+		return 0;
+	if (space->tuple_id[0] != &isl_id_none)
+		return 0;
+	return 1;
+}
+
+/* Is the given space that of a map?
+ */
+int isl_space_is_map(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+	return space->tuple_id[0] != &isl_id_none &&
+		space->tuple_id[1] != &isl_id_none;
+}
+
+__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned dim)
+{
+	isl_space *space;
+	space = isl_space_alloc(ctx, nparam, 0, dim);
+	space = mark_as_set(space);
+	return space;
+}
+
+/* Mark the space as being that of a parameter domain, by setting
+ * both tuples to isl_id_none.
+ */
+static __isl_give isl_space *mark_as_params(isl_space *space)
+{
+	if (!space)
+		return NULL;
+	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
+	space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none);
+	return space;
+}
+
+/* Is the space that of a parameter domain?
+ */
+int isl_space_is_params(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+	if (space->n_in != 0 || space->nested[0] ||
+	    space->n_out != 0 || space->nested[1])
+		return 0;
+	if (space->tuple_id[0] != &isl_id_none)
+		return 0;
+	if (space->tuple_id[1] != &isl_id_none)
+		return 0;
+	return 1;
+}
+
+/* Create a space for a parameter domain.
+ */
+__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam)
+{
+	isl_space *space;
+	space = isl_space_alloc(ctx, nparam, 0, 0);
+	space = mark_as_params(space);
+	return space;
+}
+
+static unsigned global_pos(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	struct isl_ctx *ctx = dim->ctx;
+
+	switch (type) {
+	case isl_dim_param:
+		isl_assert(ctx, pos < dim->nparam,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos;
+	case isl_dim_in:
+		isl_assert(ctx, pos < dim->n_in,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos + dim->nparam;
+	case isl_dim_out:
+		isl_assert(ctx, pos < dim->n_out,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos + dim->nparam + dim->n_in;
+	default:
+		isl_assert(ctx, 0, return isl_space_dim(dim, isl_dim_all));
+	}
+	return isl_space_dim(dim, isl_dim_all);
+}
+
+/* Extend length of ids array to the total number of dimensions.
+ */
+static __isl_give isl_space *extend_ids(__isl_take isl_space *dim)
+{
+	isl_id **ids;
+	int i;
+
+	if (isl_space_dim(dim, isl_dim_all) <= dim->n_id)
+		return dim;
+
+	if (!dim->ids) {
+		dim->ids = isl_calloc_array(dim->ctx,
+				isl_id *, isl_space_dim(dim, isl_dim_all));
+		if (!dim->ids)
+			goto error;
+	} else {
+		ids = isl_realloc_array(dim->ctx, dim->ids,
+				isl_id *, isl_space_dim(dim, isl_dim_all));
+		if (!ids)
+			goto error;
+		dim->ids = ids;
+		for (i = dim->n_id; i < isl_space_dim(dim, isl_dim_all); ++i)
+			dim->ids[i] = NULL;
+	}
+
+	dim->n_id = isl_space_dim(dim, isl_dim_all);
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+static __isl_give isl_space *set_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	dim = isl_space_cow(dim);
+
+	if (!dim)
+		goto error;
+
+	pos = global_pos(dim, type, pos);
+	if (pos == isl_space_dim(dim, isl_dim_all))
+		goto error;
+
+	if (pos >= dim->n_id) {
+		if (!id)
+			return dim;
+		dim = extend_ids(dim);
+		if (!dim)
+			goto error;
+	}
+
+	dim->ids[pos] = id;
+
+	return dim;
+error:
+	isl_id_free(id);
+	isl_space_free(dim);
+	return NULL;
+}
+
+static __isl_keep isl_id *get_id(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+
+	pos = global_pos(dim, type, pos);
+	if (pos == isl_space_dim(dim, isl_dim_all))
+		return NULL;
+	if (pos >= dim->n_id)
+		return NULL;
+	return dim->ids[pos];
+}
+
+static unsigned offset(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 0;
+	case isl_dim_in:	return dim->nparam;
+	case isl_dim_out:	return dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+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;
+	}
+}
+
+unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (!dim)
+		return 0;
+	return n(dim, type);
+}
+
+unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (!dim)
+		return 0;
+	return offset(dim, type);
+}
+
+static __isl_give isl_space *copy_ids(__isl_take isl_space *dst,
+	enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src,
+	enum isl_dim_type src_type)
+{
+	int i;
+	isl_id *id;
+
+	if (!dst)
+		return NULL;
+
+	for (i = 0; i < n(src, src_type); ++i) {
+		id = get_id(src, src_type, i);
+		if (!id)
+			continue;
+		dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
+		if (!dst)
+			return NULL;
+	}
+	return dst;
+}
+
+__isl_take isl_space *isl_space_dup(__isl_keep isl_space *dim)
+{
+	isl_space *dup;
+	if (!dim)
+		return NULL;
+	dup = isl_space_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out);
+	if (!dup)
+		return NULL;
+	if (dim->tuple_id[0] &&
+	    !(dup->tuple_id[0] = isl_id_copy(dim->tuple_id[0])))
+		goto error;
+	if (dim->tuple_id[1] &&
+	    !(dup->tuple_id[1] = isl_id_copy(dim->tuple_id[1])))
+		goto error;
+	if (dim->nested[0] && !(dup->nested[0] = isl_space_copy(dim->nested[0])))
+		goto error;
+	if (dim->nested[1] && !(dup->nested[1] = isl_space_copy(dim->nested[1])))
+		goto error;
+	if (!dim->ids)
+		return dup;
+	dup = copy_ids(dup, isl_dim_param, 0, dim, isl_dim_param);
+	dup = copy_ids(dup, isl_dim_in, 0, dim, isl_dim_in);
+	dup = copy_ids(dup, isl_dim_out, 0, dim, isl_dim_out);
+	return dup;
+error:
+	isl_space_free(dup);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	if (dim->ref == 1)
+		return dim;
+	dim->ref--;
+	return isl_space_dup(dim);
+}
+
+__isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	dim->ref++;
+	return dim;
+}
+
+__isl_null isl_space *isl_space_free(__isl_take isl_space *space)
+{
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (--space->ref > 0)
+		return NULL;
+
+	isl_id_free(space->tuple_id[0]);
+	isl_id_free(space->tuple_id[1]);
+
+	isl_space_free(space->nested[0]);
+	isl_space_free(space->nested[1]);
+
+	for (i = 0; i < space->n_id; ++i)
+		isl_id_free(space->ids[i]);
+	free(space->ids);
+	isl_ctx_deref(space->ctx);
+	
+	free(space);
+
+	return NULL;
+}
+
+/* Check if "s" is a valid dimension or tuple name.
+ * We currently only forbid names that look like a number.
+ *
+ * s is assumed to be non-NULL.
+ */
+static int name_ok(isl_ctx *ctx, const char *s)
+{
+	char *p;
+	long dummy;
+
+	dummy = strtol(s, &p, 0);
+	if (p != s)
+		isl_die(ctx, isl_error_invalid, "name looks like a number",
+			return 0);
+
+	return 1;
+}
+
+/* Is it possible for the given dimension type to have a tuple id?
+ */
+static int space_can_have_id(__isl_keep isl_space *space,
+	enum isl_dim_type type)
+{
+	if (!space)
+		return 0;
+	if (isl_space_is_params(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"parameter spaces don't have tuple ids", return 0);
+	if (isl_space_is_set(space) && type != isl_dim_set)
+		isl_die(space->ctx, isl_error_invalid,
+			"set spaces can only have a set id", return 0);
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(space->ctx, isl_error_invalid,
+			"only input, output and set tuples can have ids",
+			return 0);
+
+	return 1;
+}
+
+/* Does the tuple have an id?
+ */
+int isl_space_has_tuple_id(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (!space_can_have_id(dim, type))
+		return -1;
+	return dim->tuple_id[type - isl_dim_in] != NULL;
+}
+
+__isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	int has_id;
+
+	if (!dim)
+		return NULL;
+	has_id = isl_space_has_tuple_id(dim, type);
+	if (has_id < 0)
+		return NULL;
+	if (!has_id)
+		isl_die(dim->ctx, isl_error_invalid,
+			"tuple has no id", return NULL);
+	return isl_id_copy(dim->tuple_id[type - isl_dim_in]);
+}
+
+__isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	dim = isl_space_cow(dim);
+	if (!dim || !id)
+		goto error;
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"only input, output and set tuples can have names",
+			goto error);
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = id;
+
+	return dim;
+error:
+	isl_id_free(id);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type)
+{
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"only input, output and set tuples can have names",
+			goto error);
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = NULL;
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Set the id of the given dimension of "space" to "id".
+ * If the dimension already has an id, then it is replaced.
+ * If the dimension is a parameter, then we need to change it
+ * in the nested spaces (if any) as well.
+ */
+__isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	space = isl_space_cow(space);
+	if (!space || !id)
+		goto error;
+
+	if (type == isl_dim_param) {
+		int i;
+
+		for (i = 0; i < 2; ++i) {
+			if (!space->nested[i])
+				continue;
+			space->nested[i] =
+				isl_space_set_dim_id(space->nested[i],
+						type, pos, isl_id_copy(id));
+			if (!space->nested[i])
+				goto error;
+		}
+	}
+
+	isl_id_free(get_id(space, type, pos));
+	return set_id(space, type, pos, id);
+error:
+	isl_id_free(id);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Reset the id of the given dimension of "space".
+ * If the dimension already has an id, then it is removed.
+ * If the dimension is a parameter, then we need to reset it
+ * in the nested spaces (if any) as well.
+ */
+__isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned pos)
+{
+	space = isl_space_cow(space);
+	if (!space)
+		goto error;
+
+	if (type == isl_dim_param) {
+		int i;
+
+		for (i = 0; i < 2; ++i) {
+			if (!space->nested[i])
+				continue;
+			space->nested[i] =
+				isl_space_reset_dim_id(space->nested[i],
+							type, pos);
+			if (!space->nested[i])
+				goto error;
+		}
+	}
+
+	isl_id_free(get_id(space, type, pos));
+	return set_id(space, type, pos, NULL);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+int isl_space_has_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return -1;
+	return get_id(dim, type, pos) != NULL;
+}
+
+__isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+	if (!get_id(dim, type, pos))
+		isl_die(dim->ctx, isl_error_invalid,
+			"dim has no id", return NULL);
+	return isl_id_copy(get_id(dim, type, pos));
+}
+
+__isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *s)
+{
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+
+	if (!s)
+		return isl_space_reset_tuple_id(dim, type);
+
+	if (!name_ok(dim->ctx, s))
+		goto error;
+
+	id = isl_id_alloc(dim->ctx, s, NULL);
+	return isl_space_set_tuple_id(dim, type, id);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Does the tuple have a name?
+ */
+int isl_space_has_tuple_name(__isl_keep isl_space *space,
+	enum isl_dim_type type)
+{
+	isl_id *id;
+
+	if (!space_can_have_id(space, type))
+		return -1;
+	id = space->tuple_id[type - isl_dim_in];
+	return id && id->name;
+}
+
+const char *isl_space_get_tuple_name(__isl_keep isl_space *dim,
+	 enum isl_dim_type type)
+{
+	isl_id *id;
+	if (!dim)
+		return NULL;
+	if (type != isl_dim_in && type != isl_dim_out)
+		return NULL;
+	id = dim->tuple_id[type - isl_dim_in];
+	return id ? id->name : NULL;
+}
+
+__isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim,
+				 enum isl_dim_type type, unsigned pos,
+				 const char *s)
+{
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+	if (!s)
+		return isl_space_reset_dim_id(dim, type, pos);
+	if (!name_ok(dim->ctx, s))
+		goto error;
+	id = isl_id_alloc(dim->ctx, s, NULL);
+	return isl_space_set_dim_id(dim, type, pos, id);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_space_has_dim_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_id *id;
+
+	if (!space)
+		return -1;
+	id = get_id(space, type, pos);
+	return id && id->name;
+}
+
+__isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	isl_id *id = get_id(dim, type, pos);
+	return id ? id->name : NULL;
+}
+
+int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	int i;
+	int offset;
+	int n;
+
+	if (!dim || !id)
+		return -1;
+
+	offset = isl_space_offset(dim, type);
+	n = isl_space_dim(dim, type);
+	for (i = 0; i < n && offset + i < dim->n_id; ++i)
+		if (dim->ids[offset + i] == id)
+			return i;
+
+	return -1;
+}
+
+int isl_space_find_dim_by_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, const char *name)
+{
+	int i;
+	int offset;
+	int n;
+
+	if (!space || !name)
+		return -1;
+
+	offset = isl_space_offset(space, type);
+	n = isl_space_dim(space, type);
+	for (i = 0; i < n && offset + i < space->n_id; ++i)
+		if (space->ids[offset + i]->name &&
+		    !strcmp(space->ids[offset + i]->name, name))
+			return i;
+
+	return -1;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of "space".
+ */
+__isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_id *id;
+	const char *name;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+
+	for (i = 0; i < space->nparam && i < space->n_id; ++i) {
+		if (!isl_id_get_user(space->ids[i]))
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		name = isl_id_get_name(space->ids[i]);
+		id = isl_id_alloc(ctx, name, NULL);
+		isl_id_free(space->ids[i]);
+		space->ids[i] = id;
+		if (!id)
+			return isl_space_free(space);
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if (!space->tuple_id[i])
+			continue;
+		if (!isl_id_get_user(space->tuple_id[i]))
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		name = isl_id_get_name(space->tuple_id[i]);
+		id = isl_id_alloc(ctx, name, NULL);
+		isl_id_free(space->tuple_id[i]);
+		space->tuple_id[i] = id;
+		if (!id)
+			return isl_space_free(space);
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if (!space->nested[i])
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		space->nested[i] = isl_space_reset_user(space->nested[i]);
+		if (!space->nested[i])
+			return isl_space_free(space);
+	}
+
+	return space;
+}
+
+static __isl_keep isl_id *tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!dim)
+		return NULL;
+	if (type == isl_dim_in)
+		return dim->tuple_id[0];
+	if (type == isl_dim_out)
+		return dim->tuple_id[1];
+	return NULL;
+}
+
+static __isl_keep isl_space *nested(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!dim)
+		return NULL;
+	if (type == isl_dim_in)
+		return dim->nested[0];
+	if (type == isl_dim_out)
+		return dim->nested[1];
+	return NULL;
+}
+
+/* Are the two spaces the same, apart from positions and names of parameters?
+ */
+static int isl_space_has_equal_tuples(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return -1;
+	if (space1 == space2)
+		return 1;
+	return isl_space_tuple_is_equal(space1, isl_dim_in,
+					space2, isl_dim_in) &&
+	       isl_space_tuple_is_equal(space1, isl_dim_out,
+					space2, isl_dim_out);
+}
+
+/* Check if the tuple of type "type1" of "space1" is the same as
+ * the tuple of type "type2" of "space2".
+ *
+ * That is, check if the tuples have the same identifier, the same dimension
+ * and the same internal structure.
+ * The identifiers of the dimensions inside the tuples do not affect the result.
+ *
+ * Note that this function only checks the tuples themselves.
+ * If nested tuples are involved, then we need to be careful not
+ * to have result affected by possibly differing parameters
+ * in those nested tuples.
+ */
+int isl_space_tuple_is_equal(__isl_keep isl_space *space1,
+	enum isl_dim_type type1, __isl_keep isl_space *space2,
+	enum isl_dim_type type2)
+{
+	isl_id *id1, *id2;
+	isl_space *nested1, *nested2;
+
+	if (!space1 || !space2)
+		return -1;
+
+	if (space1 == space2 && type1 == type2)
+		return 1;
+
+	if (n(space1, type1) != n(space2, type2))
+		return 0;
+	id1 = tuple_id(space1, type1);
+	id2 = tuple_id(space2, type2);
+	if (!id1 ^ !id2)
+		return 0;
+	if (id1 && id1 != id2)
+		return 0;
+	nested1 = nested(space1, type1);
+	nested2 = nested(space2, type2);
+	if (!nested1 ^ !nested2)
+		return 0;
+	if (nested1 && !isl_space_has_equal_tuples(nested1, nested2))
+		return 0;
+	return 1;
+}
+
+/* This is the old, undocumented, name for isl_space_tuple_is_equal.
+ * It will be removed at some point.
+ */
+int isl_space_tuple_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2)
+{
+	return isl_space_tuple_is_equal(space1, type1, space2, type2);
+}
+
+static int match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
+	__isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
+{
+	int i;
+
+	if (dim1 == dim2 && dim1_type == dim2_type)
+		return 1;
+
+	if (!isl_space_tuple_is_equal(dim1, dim1_type, dim2, dim2_type))
+		return 0;
+
+	if (!dim1->ids && !dim2->ids)
+		return 1;
+
+	for (i = 0; i < n(dim1, dim1_type); ++i) {
+		if (get_id(dim1, dim1_type, i) != get_id(dim2, dim2_type, i))
+			return 0;
+	}
+	return 1;
+}
+
+int isl_space_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
+	__isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
+{
+	if (!dim1 || !dim2)
+		return -1;
+
+	return match(dim1, dim1_type, dim2, dim2_type);
+}
+
+static void get_ids(__isl_keep isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, __isl_keep isl_id **ids)
+{
+	int i;
+
+	for (i = 0; i < n ; ++i)
+		ids[i] = get_id(dim, type, first + i);
+}
+
+__isl_give isl_space *isl_space_extend(__isl_take isl_space *dim,
+			unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	isl_id **ids = NULL;
+
+	if (!dim)
+		return NULL;
+	if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
+		return dim;
+
+	isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
+	isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
+	isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error;
+
+	if (dim->ids) {
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+					 nparam + n_in + n_out);
+		if (!ids)
+			goto error;
+		get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
+		get_ids(dim, isl_dim_in, 0, dim->n_in, ids + nparam);
+		get_ids(dim, isl_dim_out, 0, dim->n_out, ids + nparam + n_in);
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = nparam + n_in + n_out;
+	}
+	dim->nparam = nparam;
+	dim->n_in = n_in;
+	dim->n_out = n_out;
+
+	return dim;
+error:
+	free(ids);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_add_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned n)
+{
+	if (!dim)
+		return NULL;
+	dim = isl_space_reset(dim, type);
+	switch (type) {
+	case isl_dim_param:
+		dim = isl_space_extend(dim,
+					dim->nparam + n, dim->n_in, dim->n_out);
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_add_dims(dim->nested[0],
+						    isl_dim_param, n)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_add_dims(dim->nested[1],
+						    isl_dim_param, n)))
+			goto error;
+		return dim;
+	case isl_dim_in:
+		return isl_space_extend(dim,
+					dim->nparam, dim->n_in + n, dim->n_out);
+	case isl_dim_out:
+		return isl_space_extend(dim,
+					dim->nparam, dim->n_in, dim->n_out + n);
+	default:
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot add dimensions of specified type", goto error);
+	}
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+static int valid_dim_type(enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/* Insert "n" dimensions of type "type" at position "pos".
+ * If we are inserting parameters, then they are also inserted in
+ * any nested spaces.
+ */
+__isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	isl_id **ids = NULL;
+
+	if (!dim)
+		return NULL;
+	if (n == 0)
+		return isl_space_reset(dim, type);
+
+	if (!valid_dim_type(type))
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot insert dimensions of specified type",
+			goto error);
+
+	isl_assert(dim->ctx, pos <= isl_space_dim(dim, type), goto error);
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	if (dim->ids) {
+		enum isl_dim_type t, o = isl_dim_param;
+		int off;
+		int s[3];
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+				     dim->nparam + dim->n_in + dim->n_out + n);
+		if (!ids)
+			goto error;
+		off = 0;
+		s[isl_dim_param - o] = dim->nparam;
+		s[isl_dim_in - o] = dim->n_in;
+		s[isl_dim_out - o] = dim->n_out;
+		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+			if (t != type) {
+				get_ids(dim, t, 0, s[t - o], ids + off);
+				off += s[t - o];
+			} else {
+				get_ids(dim, t, 0, pos, ids + off);
+				off += pos + n;
+				get_ids(dim, t, pos, s[t - o] - pos, ids + off);
+				off += s[t - o] - pos;
+			}
+		}
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_in + dim->n_out + n;
+	}
+	switch (type) {
+	case isl_dim_param:	dim->nparam += n; break;
+	case isl_dim_in:	dim->n_in += n; break;
+	case isl_dim_out:	dim->n_out += n; break;
+	default:		;
+	}
+	dim = isl_space_reset(dim, type);
+
+	if (type == isl_dim_param) {
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_insert_dims(dim->nested[0],
+						    isl_dim_param, pos, n)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_insert_dims(dim->nested[1],
+						    isl_dim_param, pos, n)))
+			goto error;
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_move_dims(__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)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+	if (n == 0) {
+		dim = isl_space_reset(dim, src_type);
+		return isl_space_reset(dim, dst_type);
+	}
+
+	isl_assert(dim->ctx, src_pos + n <= isl_space_dim(dim, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return dim;
+
+	isl_assert(dim->ctx, dst_type != src_type, goto error);
+
+	dim = isl_space_reset(dim, src_type);
+	dim = isl_space_reset(dim, dst_type);
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	if (dim->ids) {
+		isl_id **ids;
+		enum isl_dim_type t, o = isl_dim_param;
+		int off;
+		int s[3];
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+					 dim->nparam + dim->n_in + dim->n_out);
+		if (!ids)
+			goto error;
+		off = 0;
+		s[isl_dim_param - o] = dim->nparam;
+		s[isl_dim_in - o] = dim->n_in;
+		s[isl_dim_out - o] = dim->n_out;
+		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+			if (t == dst_type) {
+				get_ids(dim, t, 0, dst_pos, ids + off);
+				off += dst_pos;
+				get_ids(dim, src_type, src_pos, n, ids + off);
+				off += n;
+				get_ids(dim, t, dst_pos, s[t - o] - dst_pos,
+						ids + off);
+				off += s[t - o] - dst_pos;
+			} else if (t == src_type) {
+				get_ids(dim, t, 0, src_pos, ids + off);
+				off += src_pos;
+				get_ids(dim, t, src_pos + n,
+					    s[t - o] - src_pos - n, ids + off);
+				off += s[t - o] - src_pos - n;
+			} else {
+				get_ids(dim, t, 0, s[t - o], ids + off);
+				off += s[t - o];
+			}
+		}
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_in + dim->n_out;
+	}
+
+	switch (dst_type) {
+	case isl_dim_param:	dim->nparam += n; break;
+	case isl_dim_in:	dim->n_in += n; break;
+	case isl_dim_out:	dim->n_out += n; break;
+	default:		;
+	}
+
+	switch (src_type) {
+	case isl_dim_param:	dim->nparam -= n; break;
+	case isl_dim_in:	dim->n_in -= n; break;
+	case isl_dim_out:	dim->n_out -= n; break;
+	default:		;
+	}
+
+	if (dst_type != isl_dim_param && src_type != isl_dim_param)
+		return dim;
+
+	for (i = 0; i < 2; ++i) {
+		if (!dim->nested[i])
+			continue;
+		dim->nested[i] = isl_space_replace(dim->nested[i],
+						 isl_dim_param, dim);
+		if (!dim->nested[i])
+			goto error;
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dim;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			goto error);
+	isl_assert(left->ctx,
+		isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in),
+		goto error);
+
+	dim = isl_space_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
+	if (!dim)
+		goto error;
+
+	dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param);
+	dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in);
+	dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out);
+
+	if (dim && left->tuple_id[0] &&
+	    !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
+		goto error;
+	if (dim && right->tuple_id[1] &&
+	    !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
+		goto error;
+	if (dim && left->nested[0] &&
+	    !(dim->nested[0] = isl_space_copy(left->nested[0])))
+		goto error;
+	if (dim && right->nested[1] &&
+	    !(dim->nested[1] = isl_space_copy(right->nested[1])))
+		goto error;
+
+	isl_space_free(left);
+	isl_space_free(right);
+
+	return dim;
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given two map spaces { A -> C } and { B -> D }, construct the space
+ * { [A -> B] -> [C -> D] }.
+ * Given two set spaces { A } and { B }, construct the space { [A -> B] }.
+ */
+__isl_give isl_space *isl_space_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dom1, *dom2, *nest1, *nest2;
+	int is_set;
+
+	if (!left || !right)
+		goto error;
+
+	is_set = isl_space_is_set(left);
+	if (is_set != isl_space_is_set(right))
+		isl_die(isl_space_get_ctx(left), isl_error_invalid,
+			"expecting either two set spaces or two map spaces",
+			goto error);
+	if (is_set)
+		return isl_space_range_product(left, right);
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			goto error);
+
+	dom1 = isl_space_domain(isl_space_copy(left));
+	dom2 = isl_space_domain(isl_space_copy(right));
+	nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	dom1 = isl_space_range(left);
+	dom2 = isl_space_range(right);
+	nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	return isl_space_join(isl_space_reverse(nest1), nest2);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given two spaces { A -> C } and { B -> C }, construct the space
+ * { [A -> B] -> C }
+ */
+__isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *ran, *dom1, *dom2, *nest;
+
+	if (!left || !right)
+		goto error;
+
+	if (!match(left, isl_dim_param, right, isl_dim_param))
+		isl_die(left->ctx, isl_error_invalid,
+			"parameters need to match", goto error);
+	if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out))
+		isl_die(left->ctx, isl_error_invalid,
+			"ranges need to match", goto error);
+
+	ran = isl_space_range(isl_space_copy(left));
+
+	dom1 = isl_space_domain(left);
+	dom2 = isl_space_domain(right);
+	nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	return isl_space_join(isl_space_reverse(nest), ran);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dom, *ran1, *ran2, *nest;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			goto error);
+	if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in))
+		isl_die(left->ctx, isl_error_invalid,
+			"domains need to match", goto error);
+
+	dom = isl_space_domain(isl_space_copy(left));
+
+	ran1 = isl_space_range(left);
+	ran2 = isl_space_range(right);
+	nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
+
+	return isl_space_join(isl_space_reverse(dom), nest);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given a space of the form [A -> B] -> [C -> D], return the space A -> C.
+ */
+__isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space)
+{
+	space = isl_space_domain_factor_domain(space);
+	space = isl_space_range_factor_domain(space);
+	return space;
+}
+
+/* Given a space of the form [A -> B] -> [C -> D], return the space B -> D.
+ */
+__isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space)
+{
+	space = isl_space_domain_factor_range(space);
+	space = isl_space_range_factor_range(space);
+	return space;
+}
+
+/* Given a space of the form [A -> B] -> C, return the space A -> C.
+ */
+__isl_give isl_space *isl_space_domain_factor_domain(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *domain;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"domain not a product", return isl_space_free(space));
+
+	nested = space->nested[0];
+	domain = isl_space_copy(space);
+	domain = isl_space_drop_dims(space, isl_dim_in,
+					nested->n_in, nested->n_out);
+	if (!domain)
+		return isl_space_free(space);
+	if (nested->tuple_id[0]) {
+		domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]);
+		if (!domain->tuple_id[0])
+			goto error;
+	}
+	if (nested->nested[0]) {
+		domain->nested[0] = isl_space_copy(nested->nested[0]);
+		if (!domain->nested[0])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return domain;
+error:
+	isl_space_free(space);
+	isl_space_free(domain);
+	return NULL;
+}
+
+/* Given a space of the form [A -> B] -> C, return the space B -> C.
+ */
+__isl_give isl_space *isl_space_domain_factor_range(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *range;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"domain not a product", return isl_space_free(space));
+
+	nested = space->nested[0];
+	range = isl_space_copy(space);
+	range = isl_space_drop_dims(space, isl_dim_in, 0, nested->n_in);
+	if (!range)
+		return isl_space_free(space);
+	if (nested->tuple_id[1]) {
+		range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]);
+		if (!range->tuple_id[0])
+			goto error;
+	}
+	if (nested->nested[1]) {
+		range->nested[0] = isl_space_copy(nested->nested[1]);
+		if (!range->nested[0])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return range;
+error:
+	isl_space_free(space);
+	isl_space_free(range);
+	return NULL;
+}
+
+/* Given a space of the form A -> [B -> C], return the space A -> B.
+ */
+__isl_give isl_space *isl_space_range_factor_domain(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *domain;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_range_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"range not a product", return isl_space_free(space));
+
+	nested = space->nested[1];
+	domain = isl_space_copy(space);
+	domain = isl_space_drop_dims(space, isl_dim_out,
+					nested->n_in, nested->n_out);
+	if (!domain)
+		return isl_space_free(space);
+	if (nested->tuple_id[0]) {
+		domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]);
+		if (!domain->tuple_id[1])
+			goto error;
+	}
+	if (nested->nested[0]) {
+		domain->nested[1] = isl_space_copy(nested->nested[0]);
+		if (!domain->nested[1])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return domain;
+error:
+	isl_space_free(space);
+	isl_space_free(domain);
+	return NULL;
+}
+
+/* Given a space of the form A -> [B -> C], return the space A -> C.
+ */
+__isl_give isl_space *isl_space_range_factor_range(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *range;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_range_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"range not a product", return isl_space_free(space));
+
+	nested = space->nested[1];
+	range = isl_space_copy(space);
+	range = isl_space_drop_dims(space, isl_dim_out, 0, nested->n_in);
+	if (!range)
+		return isl_space_free(space);
+	if (nested->tuple_id[1]) {
+		range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]);
+		if (!range->tuple_id[1])
+			goto error;
+	}
+	if (nested->nested[1]) {
+		range->nested[1] = isl_space_copy(nested->nested[1]);
+		if (!range->nested[1])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return range;
+error:
+	isl_space_free(space);
+	isl_space_free(range);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *dim)
+{
+	isl_ctx *ctx;
+	isl_id **ids = NULL;
+
+	if (!dim)
+		return NULL;
+	ctx = isl_space_get_ctx(dim);
+	if (!isl_space_is_set(dim))
+		isl_die(ctx, isl_error_invalid, "not a set space", goto error);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	if (dim->ids) {
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+					dim->nparam + dim->n_out + dim->n_out);
+		if (!ids)
+			goto error;
+		get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
+		get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->nparam);
+	}
+	dim->n_in = dim->n_out;
+	if (ids) {
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_out + dim->n_out;
+		dim = copy_ids(dim, isl_dim_out, 0, dim, isl_dim_in);
+	}
+	isl_id_free(dim->tuple_id[0]);
+	dim->tuple_id[0] = isl_id_copy(dim->tuple_id[1]);
+	isl_space_free(dim->nested[0]);
+	dim->nested[0] = isl_space_copy(dim->nested[1]);
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_map_from_domain_and_range(
+	__isl_take isl_space *domain, __isl_take isl_space *range)
+{
+	if (!domain || !range)
+		goto error;
+	if (!isl_space_is_set(domain))
+		isl_die(isl_space_get_ctx(domain), isl_error_invalid,
+			"domain is not a set space", goto error);
+	if (!isl_space_is_set(range))
+		isl_die(isl_space_get_ctx(range), isl_error_invalid,
+			"range is not a set space", goto error);
+	return isl_space_join(isl_space_reverse(domain), range);
+error:
+	isl_space_free(domain);
+	isl_space_free(range);
+	return NULL;
+}
+
+static __isl_give isl_space *set_ids(__isl_take isl_space *dim,
+	enum isl_dim_type type,
+	unsigned first, unsigned n, __isl_take isl_id **ids)
+{
+	int i;
+
+	for (i = 0; i < n ; ++i)
+		dim = set_id(dim, type, first + i, ids[i]);
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim)
+{
+	unsigned t;
+	isl_space *nested;
+	isl_id **ids = NULL;
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+	if (match(dim, isl_dim_in, dim, isl_dim_out))
+		return dim;
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	id = dim->tuple_id[0];
+	dim->tuple_id[0] = dim->tuple_id[1];
+	dim->tuple_id[1] = id;
+
+	nested = dim->nested[0];
+	dim->nested[0] = dim->nested[1];
+	dim->nested[1] = nested;
+
+	if (dim->ids) {
+		int n_id = dim->n_in + dim->n_out;
+		ids = isl_alloc_array(dim->ctx, isl_id *, n_id);
+		if (n_id && !ids)
+			goto error;
+		get_ids(dim, isl_dim_in, 0, dim->n_in, ids);
+		get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in);
+	}
+
+	t = dim->n_in;
+	dim->n_in = dim->n_out;
+	dim->n_out = t;
+
+	if (dim->ids) {
+		dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids);
+		dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out);
+		free(ids);
+	}
+
+	return dim;
+error:
+	free(ids);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned first, unsigned num)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+
+	if (num == 0)
+		return isl_space_reset(dim, type);
+
+	if (!valid_dim_type(type))
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot drop dimensions of specified type", goto error);
+
+	if (first + num > n(dim, type) || first + num < first)
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"index out of bounds", return isl_space_free(dim));
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error;
+	if (dim->ids) {
+		dim = extend_ids(dim);
+		if (!dim)
+			goto error;
+		for (i = 0; i < num; ++i)
+			isl_id_free(get_id(dim, type, first + i));
+		for (i = first+num; i < n(dim, type); ++i)
+			set_id(dim, type, i - num, get_id(dim, type, i));
+		switch (type) {
+		case isl_dim_param:
+			get_ids(dim, isl_dim_in, 0, dim->n_in,
+				dim->ids + offset(dim, isl_dim_in) - num);
+		case isl_dim_in:
+			get_ids(dim, isl_dim_out, 0, dim->n_out,
+				dim->ids + offset(dim, isl_dim_out) - num);
+		default:
+			;
+		}
+		dim->n_id -= num;
+	}
+	switch (type) {
+	case isl_dim_param:	dim->nparam -= num; break;
+	case isl_dim_in:	dim->n_in -= num; break;
+	case isl_dim_out:	dim->n_out -= num; break;
+	default:		;
+	}
+	dim = isl_space_reset(dim, type);
+	if (type == isl_dim_param) {
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_drop_dims(dim->nested[0],
+						    isl_dim_param, first, num)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_drop_dims(dim->nested[1],
+						    isl_dim_param, first, num)))
+			goto error;
+	}
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n)
+{
+	if (!dim)
+		return NULL;
+	return isl_space_drop_dims(dim, isl_dim_in, first, n);
+}
+
+__isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n)
+{
+	if (!dim)
+		return NULL;
+	return isl_space_drop_dims(dim, isl_dim_out, first, n);
+}
+
+__isl_give isl_space *isl_space_domain(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	dim = isl_space_drop_outputs(dim, 0, dim->n_out);
+	dim = isl_space_reverse(dim);
+	dim = mark_as_set(dim);
+	return dim;
+}
+
+__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"not a set space", goto error);
+	dim = isl_space_reverse(dim);
+	dim = isl_space_reset(dim, isl_dim_out);
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_range(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	dim = isl_space_drop_inputs(dim, 0, dim->n_in);
+	dim = mark_as_set(dim);
+	return dim;
+}
+
+__isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"not a set space", goto error);
+	return isl_space_reset(dim, isl_dim_in);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Given a map space A -> B, return the map space [A -> B] -> A.
+ */
+__isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space)
+{
+	isl_space *domain;
+
+	domain = isl_space_from_range(isl_space_domain(isl_space_copy(space)));
+	space = isl_space_from_domain(isl_space_wrap(space));
+	space = isl_space_join(space, domain);
+
+	return space;
+}
+
+/* Given a map space A -> B, return the map space [A -> B] -> B.
+ */
+__isl_give isl_space *isl_space_range_map(__isl_take isl_space *space)
+{
+	isl_space *range;
+
+	range = isl_space_from_range(isl_space_range(isl_space_copy(space)));
+	space = isl_space_from_domain(isl_space_wrap(space));
+	space = isl_space_join(space, range);
+
+	return space;
+}
+
+__isl_give isl_space *isl_space_params(__isl_take isl_space *space)
+{
+	if (isl_space_is_params(space))
+		return space;
+	space = isl_space_drop_dims(space,
+			    isl_dim_in, 0, isl_space_dim(space, isl_dim_in));
+	space = isl_space_drop_dims(space,
+			    isl_dim_out, 0, isl_space_dim(space, isl_dim_out));
+	space = mark_as_params(space);
+	return space;
+}
+
+__isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	if (!isl_space_is_params(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"not a parameter space", goto error);
+	return isl_space_reset(space, isl_dim_set);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_as_set_space(__isl_take isl_space *dim)
+{
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	dim->n_out += dim->n_in;
+	dim->n_in = 0;
+	dim = isl_space_reset(dim, isl_dim_in);
+	dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
+	unsigned n_div)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+	if (n_div == 0 &&
+	    dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0)
+		return isl_space_reset(isl_space_reset(dim, isl_dim_in), isl_dim_out);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	dim->n_out += dim->nparam + dim->n_in + n_div;
+	dim->nparam = 0;
+	dim->n_in = 0;
+
+	for (i = 0; i < dim->n_id; ++i)
+		isl_id_free(get_id(dim, isl_dim_out, i));
+	dim->n_id = 0;
+	dim = isl_space_reset(dim, isl_dim_in);
+	dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+/* Are the two spaces the same, including positions and names of parameters?
+ */
+int isl_space_is_equal(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
+{
+	if (!dim1 || !dim2)
+		return -1;
+	if (dim1 == dim2)
+		return 1;
+	return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
+	       isl_space_tuple_is_equal(dim1, isl_dim_in, dim2, isl_dim_in) &&
+	       isl_space_tuple_is_equal(dim1, isl_dim_out, dim2, isl_dim_out);
+}
+
+/* Is space1 equal to the domain of space2?
+ *
+ * In the internal version we also allow space2 to be the space of a set,
+ * provided space1 is a parameter space.
+ */
+int isl_space_is_domain_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return -1;
+	if (!isl_space_is_set(space1))
+		return 0;
+	return match(space1, isl_dim_param, space2, isl_dim_param) &&
+	       isl_space_tuple_is_equal(space1, isl_dim_set,
+					space2, isl_dim_in);
+}
+
+/* Is space1 equal to the domain of space2?
+ */
+int isl_space_is_domain(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space2)
+		return -1;
+	if (!isl_space_is_map(space2))
+		return 0;
+	return isl_space_is_domain_internal(space1, space2);
+}
+
+/* Is space1 equal to the range of space2?
+ *
+ * In the internal version, space2 is allowed to be the space of a set,
+ * in which case it should be equal to space1.
+ */
+int isl_space_is_range_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return -1;
+	if (!isl_space_is_set(space1))
+		return 0;
+	return match(space1, isl_dim_param, space2, isl_dim_param) &&
+	       isl_space_tuple_is_equal(space1, isl_dim_set,
+					space2, isl_dim_out);
+}
+
+/* Is space1 equal to the range of space2?
+ */
+int isl_space_is_range(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space2)
+		return -1;
+	if (!isl_space_is_map(space2))
+		return 0;
+	return isl_space_is_range_internal(space1, space2);
+}
+
+int isl_space_compatible(__isl_keep isl_space *dim1,
+	__isl_keep isl_space *dim2)
+{
+	return dim1->nparam == dim2->nparam &&
+	       dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
+}
+
+static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_space *dim)
+{
+	int i;
+	isl_id *id;
+
+	if (!dim)
+		return hash;
+
+	isl_hash_byte(hash, dim->nparam % 256);
+	isl_hash_byte(hash, dim->n_in % 256);
+	isl_hash_byte(hash, dim->n_out % 256);
+
+	for (i = 0; i < dim->nparam; ++i) {
+		id = get_id(dim, isl_dim_param, i);
+		hash = isl_hash_id(hash, id);
+	}
+
+	id = tuple_id(dim, isl_dim_in);
+	hash = isl_hash_id(hash, id);
+	id = tuple_id(dim, isl_dim_out);
+	hash = isl_hash_id(hash, id);
+
+	hash = isl_hash_dim(hash, dim->nested[0]);
+	hash = isl_hash_dim(hash, dim->nested[1]);
+
+	return hash;
+}
+
+uint32_t isl_space_get_hash(__isl_keep isl_space *dim)
+{
+	uint32_t hash;
+
+	if (!dim)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_hash_dim(hash, dim);
+
+	return hash;
+}
+
+int isl_space_is_wrapping(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return -1;
+
+	if (!isl_space_is_set(dim))
+		return 0;
+
+	return dim->nested[1] != NULL;
+}
+
+/* Is "space" the space of a map where the domain is a wrapped map space?
+ */
+int isl_space_domain_is_wrapping(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+
+	if (isl_space_is_set(space))
+		return 0;
+
+	return space->nested[0] != NULL;
+}
+
+/* Is "space" the space of a map where the range is a wrapped map space?
+ */
+int isl_space_range_is_wrapping(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+
+	if (isl_space_is_set(space))
+		return 0;
+
+	return space->nested[1] != NULL;
+}
+
+__isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim)
+{
+	isl_space *wrap;
+
+	if (!dim)
+		return NULL;
+
+	wrap = isl_space_set_alloc(dim->ctx,
+				    dim->nparam, dim->n_in + dim->n_out);
+
+	wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param);
+	wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in);
+	wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
+
+	if (!wrap)
+		goto error;
+
+	wrap->nested[1] = dim;
+
+	return wrap;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim)
+{
+	isl_space *unwrap;
+
+	if (!dim)
+		return NULL;
+
+	if (!isl_space_is_wrapping(dim))
+		isl_die(dim->ctx, isl_error_invalid, "not a wrapping space",
+			goto error);
+
+	unwrap = isl_space_copy(dim->nested[1]);
+	isl_space_free(dim);
+
+	return unwrap;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (type != isl_dim_in && type != isl_dim_out)
+		return 0;
+	if (!dim)
+		return -1;
+	if (dim->tuple_id[type - isl_dim_in])
+		return 1;
+	if (dim->nested[type - isl_dim_in])
+		return 1;
+	return 0;
+}
+
+int isl_space_may_be_set(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return -1;
+	if (isl_space_is_set(dim))
+		return 1;
+	if (isl_space_dim(dim, isl_dim_in) != 0)
+		return 0;
+	if (isl_space_is_named_or_nested(dim, isl_dim_in))
+		return 0;
+	return 1;
+}
+
+__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!isl_space_is_named_or_nested(dim, type))
+		return dim;
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = NULL;
+	isl_space_free(dim->nested[type - isl_dim_in]);
+	dim->nested[type - isl_dim_in] = NULL;
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[0] && !dim->nested[1])
+		return dim;
+
+	if (dim->nested[0])
+		dim = isl_space_reset(dim, isl_dim_in);
+	if (dim && dim->nested[1])
+		dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[0])
+		return dim;
+
+	return isl_space_reset(dim, isl_dim_in);
+}
+
+__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[1])
+		return dim;
+
+	return isl_space_reset(dim, isl_dim_out);
+}
+
+/* Replace the dimensions of the given type of dst by those of src.
+ */
+__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
+	enum isl_dim_type type, __isl_keep isl_space *src)
+{
+	dst = isl_space_cow(dst);
+
+	if (!dst || !src)
+		goto error;
+
+	dst = isl_space_drop_dims(dst, type, 0, isl_space_dim(dst, type));
+	dst = isl_space_add_dims(dst, type, isl_space_dim(src, type));
+	dst = copy_ids(dst, type, 0, src, type);
+
+	if (dst && type == isl_dim_param) {
+		int i;
+		for (i = 0; i <= 1; ++i) {
+			if (!dst->nested[i])
+				continue;
+			dst->nested[i] = isl_space_replace(dst->nested[i],
+							 type, src);
+			if (!dst->nested[i])
+				goto error;
+		}
+	}
+
+	return dst;
+error:
+	isl_space_free(dst);
+	return NULL;
+}
+
+/* Given a dimension specification "dim" of a set, create a dimension
+ * specification for the lift of the set.  In particular, the result
+ * is of the form [dim -> local[..]], with n_local variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local)
+{
+	isl_space *local_dim;
+
+	if (!dim)
+		return NULL;
+
+	local_dim = isl_space_dup(dim);
+	local_dim = isl_space_drop_dims(local_dim, isl_dim_set, 0, dim->n_out);
+	local_dim = isl_space_add_dims(local_dim, isl_dim_set, n_local);
+	local_dim = isl_space_set_tuple_name(local_dim, isl_dim_set, "local");
+	dim = isl_space_join(isl_space_from_domain(dim),
+			    isl_space_from_range(local_dim));
+	dim = isl_space_wrap(dim);
+	dim = isl_space_set_tuple_name(dim, isl_dim_set, "lifted");
+
+	return dim;
+}
+
+int isl_space_can_zip(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return -1;
+
+	return dim->nested[0] && dim->nested[1];
+}
+
+__isl_give isl_space *isl_space_zip(__isl_take isl_space *dim)
+{
+	isl_space *dom, *ran;
+	isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
+
+	if (!isl_space_can_zip(dim))
+		isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
+			goto error);
+
+	if (!dim)
+		return NULL;
+	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(dim)));
+	ran = isl_space_unwrap(isl_space_range(dim));
+	dom_dom = isl_space_domain(isl_space_copy(dom));
+	dom_ran = isl_space_range(dom);
+	ran_dom = isl_space_domain(isl_space_copy(ran));
+	ran_ran = isl_space_range(ran);
+	dom = isl_space_join(isl_space_from_domain(dom_dom),
+			   isl_space_from_range(ran_dom));
+	ran = isl_space_join(isl_space_from_domain(dom_ran),
+			   isl_space_from_range(ran_ran));
+	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
+			    isl_space_from_range(isl_space_wrap(ran)));
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Can we apply isl_space_curry to "space"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_space_can_curry(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+
+	return !!space->nested[0];
+}
+
+/* Given a space (A -> B) -> C, return the corresponding space
+ * A -> (B -> C).
+ */
+__isl_give isl_space *isl_space_curry(__isl_take isl_space *space)
+{
+	isl_space *dom, *ran;
+	isl_space *dom_dom, *dom_ran;
+
+	if (!space)
+		return NULL;
+
+	if (!isl_space_can_curry(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"space cannot be curried", goto error);
+
+	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
+	ran = isl_space_range(space);
+	dom_dom = isl_space_domain(isl_space_copy(dom));
+	dom_ran = isl_space_range(dom);
+	ran = isl_space_join(isl_space_from_domain(dom_ran),
+			   isl_space_from_range(ran));
+	return isl_space_join(isl_space_from_domain(dom_dom),
+			    isl_space_from_range(isl_space_wrap(ran)));
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Can we apply isl_space_uncurry to "space"?
+ * That is, does it have a nested relation in its range?
+ */
+int isl_space_can_uncurry(__isl_keep isl_space *space)
+{
+	if (!space)
+		return -1;
+
+	return !!space->nested[1];
+}
+
+/* Given a space A -> (B -> C), return the corresponding space
+ * (A -> B) -> C.
+ */
+__isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space)
+{
+	isl_space *dom, *ran;
+	isl_space *ran_dom, *ran_ran;
+
+	if (!space)
+		return NULL;
+
+	if (!isl_space_can_uncurry(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"space cannot be uncurried",
+			return isl_space_free(space));
+
+	dom = isl_space_domain(isl_space_copy(space));
+	ran = isl_space_unwrap(isl_space_range(space));
+	ran_dom = isl_space_domain(isl_space_copy(ran));
+	ran_ran = isl_space_range(ran);
+	dom = isl_space_join(isl_space_from_domain(dom),
+			   isl_space_from_range(ran_dom));
+	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
+			    isl_space_from_range(ran_ran));
+}
+
+int isl_space_has_named_params(__isl_keep isl_space *dim)
+{
+	int i;
+	unsigned off;
+
+	if (!dim)
+		return -1;
+	if (dim->nparam == 0)
+		return 1;
+	off = isl_space_offset(dim, isl_dim_param);
+	if (off + dim->nparam > dim->n_id)
+		return 0;
+	for (i = 0; i < dim->nparam; ++i)
+		if (!dim->ids[off + i])
+			return 0;
+	return 1;
+}
+
+/* Align the initial parameters of dim1 to match the order in dim2.
+ */
+__isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1,
+	__isl_take isl_space *dim2)
+{
+	isl_reordering *exp;
+
+	if (!isl_space_has_named_params(dim1) || !isl_space_has_named_params(dim2))
+		isl_die(isl_space_get_ctx(dim1), isl_error_invalid,
+			"parameter alignment requires named parameters",
+			goto error);
+
+	dim2 = isl_space_params(dim2);
+	exp = isl_parameter_alignment_reordering(dim1, dim2);
+	exp = isl_reordering_extend_space(exp, dim1);
+	isl_space_free(dim2);
+	if (!exp)
+		return NULL;
+	dim1 = isl_space_copy(exp->dim);
+	isl_reordering_free(exp);
+	return dim1;
+error:
+	isl_space_free(dim1);
+	isl_space_free(dim2);
+	return NULL;
+}
+
+/* Given the space of set (domain), construct a space for a map
+ * with as domain the given space and as range the range of "model".
+ */
+__isl_give isl_space *isl_space_extend_domain_with_range(
+	__isl_take isl_space *space, __isl_take isl_space *model)
+{
+	if (!model)
+		goto error;
+
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out,
+				    isl_space_dim(model, isl_dim_out));
+	if (isl_space_has_tuple_id(model, isl_dim_out))
+		space = isl_space_set_tuple_id(space, isl_dim_out,
+				isl_space_get_tuple_id(model, isl_dim_out));
+	if (!space)
+		goto error;
+	if (model->nested[1]) {
+		isl_space *nested = isl_space_copy(model->nested[1]);
+		int n_nested, n_space;
+		nested = isl_space_align_params(nested, isl_space_copy(space));
+		n_nested = isl_space_dim(nested, isl_dim_param);
+		n_space = isl_space_dim(space, isl_dim_param);
+		if (n_nested > n_space)
+			nested = isl_space_drop_dims(nested, isl_dim_param,
+						n_space, n_nested - n_space);
+		if (!nested)
+			goto error;
+		space->nested[1] = nested;
+	}
+	isl_space_free(model);
+	return space;
+error:
+	isl_space_free(model);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Compare the "type" dimensions of two isl_spaces.
+ *
+ * The order is fairly arbitrary.
+ */
+static int isl_space_cmp_type(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2, enum isl_dim_type type)
+{
+	int cmp;
+	isl_space *nested1, *nested2;
+
+	if (isl_space_dim(space1, type) != isl_space_dim(space2, type))
+		return isl_space_dim(space1, type) -
+			isl_space_dim(space2, type);
+
+	cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type));
+	if (cmp != 0)
+		return cmp;
+
+	nested1 = nested(space1, type);
+	nested2 = nested(space2, type);
+	if (!nested1 != !nested2)
+		return !nested1 - !nested2;
+
+	if (nested1)
+		return isl_space_cmp(nested1, nested2);
+
+	return 0;
+}
+
+/* Compare two isl_spaces.
+ *
+ * The order is fairly arbitrary.
+ */
+int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2)
+{
+	int i;
+	int cmp;
+
+	if (space1 == space2)
+		return 0;
+	if (!space1)
+		return -1;
+	if (!space2)
+		return 1;
+
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_param);
+	if (cmp != 0)
+		return cmp;
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_in);
+	if (cmp != 0)
+		return cmp;
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_out);
+	if (cmp != 0)
+		return cmp;
+
+	if (!space1->ids && !space2->ids)
+		return 0;
+
+	for (i = 0; i < n(space1, isl_dim_param); ++i) {
+		cmp = isl_id_cmp(get_id(space1, isl_dim_param, i),
+				 get_id(space2, isl_dim_param, i));
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}

Added: polly/trunk/lib/External/isl/isl_space_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_space_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_space_private.h (added)
+++ polly/trunk/lib/External/isl/isl_space_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,60 @@
+#ifndef ISL_SPACE_PRIVATE
+#define ISL_SPACE_PRIVATE
+
+#include <isl/space.h>
+#include <isl/hash.h>
+#include <isl/id.h>
+
+struct isl_name;
+struct isl_space {
+	int ref;
+
+	struct isl_ctx *ctx;
+
+	unsigned nparam;
+	unsigned n_in;		/* zero for sets */
+	unsigned n_out;		/* dim for sets */
+
+	isl_id *tuple_id[2];
+	isl_space *nested[2];
+
+	unsigned n_id;
+	isl_id **ids;
+};
+
+__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim);
+
+__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
+	unsigned n_div);
+
+uint32_t isl_space_get_hash(__isl_keep isl_space *dim);
+
+int isl_space_is_domain_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+int isl_space_is_range_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+
+__isl_give isl_space *isl_space_as_set_space(__isl_take isl_space *dim);
+
+unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type);
+
+int isl_space_may_be_set(__isl_keep isl_space *dim);
+int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type);
+int isl_space_has_named_params(__isl_keep isl_space *dim);
+__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
+	enum isl_dim_type type);
+__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim);
+
+__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
+	enum isl_dim_type type, __isl_keep isl_space *src);
+
+__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local);
+
+__isl_give isl_space *isl_space_extend_domain_with_range(
+	__isl_take isl_space *domain, __isl_take isl_space *model);
+
+int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2);
+
+#endif

Added: polly/trunk/lib/External/isl/isl_stream.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_stream.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_stream.c (added)
+++ polly/trunk/lib/External/isl/isl_stream.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,778 @@
+/*
+ * 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 <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <isl/ctx.h>
+#include <isl_stream_private.h>
+#include <isl/map.h>
+#include <isl/aff.h>
+#include <isl_val_private.h>
+
+struct isl_keyword {
+	char			*name;
+	enum isl_token_type	type;
+};
+
+static int same_name(const void *entry, const void *val)
+{
+	const struct isl_keyword *keyword = (const struct isl_keyword *)entry;
+
+	return !strcmp(keyword->name, val);
+}
+
+enum isl_token_type isl_stream_register_keyword(struct isl_stream *s,
+	const char *name)
+{
+	struct isl_hash_table_entry *entry;
+	struct isl_keyword *keyword;
+	uint32_t name_hash;
+
+	if (!s->keywords) {
+		s->keywords = isl_hash_table_alloc(s->ctx, 10);
+		if (!s->keywords)
+			return ISL_TOKEN_ERROR;
+		s->next_type = ISL_TOKEN_LAST;
+	}
+
+	name_hash = isl_hash_string(isl_hash_init(), name);
+
+	entry = isl_hash_table_find(s->ctx, s->keywords, name_hash,
+					same_name, name, 1);
+	if (!entry)
+		return ISL_TOKEN_ERROR;
+	if (entry->data) {
+		keyword = entry->data;
+		return keyword->type;
+	}
+
+	keyword = isl_calloc_type(s->ctx, struct isl_keyword);
+	if (!keyword)
+		return ISL_TOKEN_ERROR;
+	keyword->type = s->next_type++;
+	keyword->name = strdup(name);
+	if (!keyword->name) {
+		free(keyword);
+		return ISL_TOKEN_ERROR;
+	}
+	entry->data = keyword;
+
+	return keyword->type;
+}
+
+struct isl_token *isl_token_new(isl_ctx *ctx,
+	int line, int col, unsigned on_new_line)
+{
+	struct isl_token *tok = isl_alloc_type(ctx, struct isl_token);
+	if (!tok)
+		return NULL;
+	tok->line = line;
+	tok->col = col;
+	tok->on_new_line = on_new_line;
+	tok->is_keyword = 0;
+	tok->u.s = NULL;
+	return tok;
+}
+
+/* Return the type of "tok".
+ */
+int isl_token_get_type(struct isl_token *tok)
+{
+	return tok ? tok->type : ISL_TOKEN_ERROR;
+}
+
+/* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
+ */
+__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok)
+{
+	if (!tok)
+		return NULL;
+	if (tok->type != ISL_TOKEN_VALUE)
+		isl_die(ctx, isl_error_invalid, "not a value token",
+			return NULL);
+
+	return isl_val_int_from_isl_int(ctx, tok->u.v);
+}
+
+/* Given a token of type ISL_TOKEN_STRING, return the string it represents.
+ */
+__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok)
+{
+	if (!tok)
+		return NULL;
+	if (tok->type != ISL_TOKEN_STRING)
+		isl_die(ctx, isl_error_invalid, "not a string token",
+			return NULL);
+
+	return strdup(tok->u.s);
+}
+
+void isl_token_free(struct isl_token *tok)
+{
+	if (!tok)
+		return;
+	if (tok->type == ISL_TOKEN_VALUE)
+		isl_int_clear(tok->u.v);
+	else if (tok->type == ISL_TOKEN_MAP)
+		isl_map_free(tok->u.map);
+	else if (tok->type == ISL_TOKEN_AFF)
+		isl_pw_aff_free(tok->u.pwaff);
+	else
+		free(tok->u.s);
+	free(tok);
+}
+
+void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg)
+{
+	int line = tok ? tok->line : s->line;
+	int col = tok ? tok->col : s->col;
+	fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
+	if (tok) {
+		if (tok->type < 256)
+			fprintf(stderr, "got '%c'\n", tok->type);
+		else if (tok->type == ISL_TOKEN_IDENT)
+			fprintf(stderr, "got ident '%s'\n", tok->u.s);
+		else if (tok->is_keyword)
+			fprintf(stderr, "got keyword '%s'\n", tok->u.s);
+		else if (tok->type == ISL_TOKEN_VALUE) {
+			fprintf(stderr, "got value '");
+			isl_int_print(stderr, tok->u.v, 0);
+			fprintf(stderr, "'\n");
+		} else if (tok->type == ISL_TOKEN_MAP) {
+			isl_printer *p;
+			fprintf(stderr, "got map '");
+			p = isl_printer_to_file(s->ctx, stderr);
+			p = isl_printer_print_map(p, tok->u.map);
+			isl_printer_free(p);
+			fprintf(stderr, "'\n");
+		} else if (tok->type == ISL_TOKEN_AFF) {
+			isl_printer *p;
+			fprintf(stderr, "got affine expression '");
+			p = isl_printer_to_file(s->ctx, stderr);
+			p = isl_printer_print_pw_aff(p, tok->u.pwaff);
+			isl_printer_free(p);
+			fprintf(stderr, "'\n");
+		} else if (tok->u.s)
+			fprintf(stderr, "got token '%s'\n", tok->u.s);
+		else
+			fprintf(stderr, "got token type %d\n", tok->type);
+	}
+}
+
+static struct isl_stream* isl_stream_new(struct isl_ctx *ctx)
+{
+	int i;
+	struct isl_stream *s = isl_alloc_type(ctx, struct isl_stream);
+	if (!s)
+		return NULL;
+	s->ctx = ctx;
+	isl_ctx_ref(s->ctx);
+	s->file = NULL;
+	s->str = NULL;
+	s->len = 0;
+	s->line = 1;
+	s->col = 0;
+	s->eof = 0;
+	s->c = -1;
+	s->n_un = 0;
+	for (i = 0; i < 5; ++i)
+		s->tokens[i] = NULL;
+	s->n_token = 0;
+	s->keywords = NULL;
+	s->size = 256;
+	s->buffer = isl_alloc_array(ctx, char, s->size);
+	if (!s->buffer)
+		goto error;
+	return s;
+error:
+	isl_stream_free(s);
+	return NULL;
+}
+
+struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)
+{
+	struct isl_stream *s = isl_stream_new(ctx);
+	if (!s)
+		return NULL;
+	s->file = file;
+	return s;
+}
+
+struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)
+{
+	struct isl_stream *s;
+	if (!str)
+		return NULL;
+	s = isl_stream_new(ctx);
+	if (!s)
+		return NULL;
+	s->str = str;
+	return s;
+}
+
+static int stream_getc(struct isl_stream *s)
+{
+	int c;
+	if (s->eof)
+		return -1;
+	if (s->n_un)
+		return s->c = s->un[--s->n_un];
+	if (s->file)
+		c = fgetc(s->file);
+	else {
+		c = *s->str++;
+		if (c == '\0')
+			c = -1;
+	}
+	if (c == -1)
+		s->eof = 1;
+	if (!s->eof) {
+		if (s->c == '\n') {
+			s->line++;
+			s->col = 0;
+		} else
+			s->col++;
+	}
+	s->c = c;
+	return c;
+}
+
+static void isl_stream_ungetc(struct isl_stream *s, int c)
+{
+	isl_assert(s->ctx, s->n_un < 5, return);
+	s->un[s->n_un++] = c;
+	s->c = -1;
+}
+
+static int isl_stream_getc(struct isl_stream *s)
+{
+	int c;
+
+	do {
+		c = stream_getc(s);
+		if (c != '\\')
+			return c;
+		c = stream_getc(s);
+	} while (c == '\n');
+
+	isl_stream_ungetc(s, c);
+
+	return '\\';
+}
+
+static int isl_stream_push_char(struct isl_stream *s, int c)
+{
+	if (s->len >= s->size) {
+		char *buffer;
+		s->size = (3*s->size)/2;
+		buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);
+		if (!buffer)
+			return -1;
+		s->buffer = buffer;
+	}
+	s->buffer[s->len++] = c;
+	return 0;
+}
+
+void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok)
+{
+	isl_assert(s->ctx, s->n_token < 5, return);
+	s->tokens[s->n_token++] = tok;
+}
+
+static enum isl_token_type check_keywords(struct isl_stream *s)
+{
+	struct isl_hash_table_entry *entry;
+	struct isl_keyword *keyword;
+	uint32_t name_hash;
+
+	if (!strcasecmp(s->buffer, "exists"))
+		return ISL_TOKEN_EXISTS;
+	if (!strcasecmp(s->buffer, "and"))
+		return ISL_TOKEN_AND;
+	if (!strcasecmp(s->buffer, "or"))
+		return ISL_TOKEN_OR;
+	if (!strcasecmp(s->buffer, "implies"))
+		return ISL_TOKEN_IMPLIES;
+	if (!strcasecmp(s->buffer, "not"))
+		return ISL_TOKEN_NOT;
+	if (!strcasecmp(s->buffer, "infty"))
+		return ISL_TOKEN_INFTY;
+	if (!strcasecmp(s->buffer, "infinity"))
+		return ISL_TOKEN_INFTY;
+	if (!strcasecmp(s->buffer, "NaN"))
+		return ISL_TOKEN_NAN;
+	if (!strcasecmp(s->buffer, "min"))
+		return ISL_TOKEN_MIN;
+	if (!strcasecmp(s->buffer, "max"))
+		return ISL_TOKEN_MAX;
+	if (!strcasecmp(s->buffer, "rat"))
+		return ISL_TOKEN_RAT;
+	if (!strcasecmp(s->buffer, "true"))
+		return ISL_TOKEN_TRUE;
+	if (!strcasecmp(s->buffer, "false"))
+		return ISL_TOKEN_FALSE;
+	if (!strcasecmp(s->buffer, "ceild"))
+		return ISL_TOKEN_CEILD;
+	if (!strcasecmp(s->buffer, "floord"))
+		return ISL_TOKEN_FLOORD;
+	if (!strcasecmp(s->buffer, "mod"))
+		return ISL_TOKEN_MOD;
+	if (!strcasecmp(s->buffer, "ceil"))
+		return ISL_TOKEN_CEIL;
+	if (!strcasecmp(s->buffer, "floor"))
+		return ISL_TOKEN_FLOOR;
+
+	if (!s->keywords)
+		return ISL_TOKEN_IDENT;
+
+	name_hash = isl_hash_string(isl_hash_init(), s->buffer);
+	entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
+					s->buffer, 0);
+	if (entry) {
+		keyword = entry->data;
+		return keyword->type;
+	}
+
+	return ISL_TOKEN_IDENT;
+}
+
+int isl_stream_skip_line(struct isl_stream *s)
+{
+	int c;
+
+	while ((c = isl_stream_getc(s)) != -1 && c != '\n')
+		/* nothing */
+		;
+
+	return c == -1 ? -1 : 0;
+}
+
+static struct isl_token *next_token(struct isl_stream *s, int same_line)
+{
+	int c;
+	struct isl_token *tok = NULL;
+	int line, col;
+	int old_line = s->line;
+
+	if (s->n_token) {
+		if (same_line && s->tokens[s->n_token - 1]->on_new_line)
+			return NULL;
+		return s->tokens[--s->n_token];
+	}
+
+	if (same_line && s->c == '\n')
+		return NULL;
+
+	s->len = 0;
+
+	/* skip spaces and comment lines */
+	while ((c = isl_stream_getc(s)) != -1) {
+		if (c == '#') {
+			if (isl_stream_skip_line(s) < 0)
+				break;
+			c = '\n';
+			if (same_line)
+				break;
+		} else if (!isspace(c) || (same_line && c == '\n'))
+			break;
+	}
+
+	line = s->line;
+	col = s->col;
+
+	if (c == -1 || (same_line && c == '\n'))
+		return NULL;
+	if (c == '(' ||
+	    c == ')' ||
+	    c == '+' ||
+	    c == '*' ||
+	    c == '%' ||
+	    c == '?' ||
+	    c == '^' ||
+	    c == '@' ||
+	    c == '$' ||
+	    c == ',' ||
+	    c == '.' ||
+	    c == ';' ||
+	    c == '[' ||
+	    c == ']' ||
+	    c == '{' ||
+	    c == '}') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = (enum isl_token_type)c;
+		return tok;
+	}
+	if (c == '-') {
+		int c;
+		if ((c = isl_stream_getc(s)) == '>') {
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->u.s = strdup("->");
+			tok->type = ISL_TOKEN_TO;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		if (!isdigit(c)) {
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->type = (enum isl_token_type) '-';
+			return tok;
+		}
+	}
+	if (c == '-' || isdigit(c)) {
+		int minus = c == '-';
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_VALUE;
+		isl_int_init(tok->u.v);
+		if (isl_stream_push_char(s, c))
+			goto error;
+		while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
+			if (isl_stream_push_char(s, c))
+				goto error;
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		isl_stream_push_char(s, '\0');
+		isl_int_read(tok->u.v, s->buffer);
+		if (minus && isl_int_is_zero(tok->u.v)) {
+			tok->col++;
+			tok->on_new_line = 0;
+			isl_stream_push_token(s, tok);
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->type = (enum isl_token_type) '-';
+		}
+		return tok;
+	}
+	if (isalpha(c) || c == '_') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		isl_stream_push_char(s, c);
+		while ((c = isl_stream_getc(s)) != -1 &&
+				(isalnum(c) || c == '_'))
+			isl_stream_push_char(s, c);
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		while ((c = isl_stream_getc(s)) != -1 && c == '\'')
+			isl_stream_push_char(s, c);
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		isl_stream_push_char(s, '\0');
+		tok->type = check_keywords(s);
+		if (tok->type != ISL_TOKEN_IDENT)
+			tok->is_keyword = 1;
+		tok->u.s = strdup(s->buffer);
+		if (!tok->u.s)
+			goto error;
+		return tok;
+	}
+	if (c == '"') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_STRING;
+		tok->u.s = NULL;
+		while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
+			isl_stream_push_char(s, c);
+		if (c != '"') {
+			isl_stream_error(s, NULL, "unterminated string");
+			goto error;
+		}
+		isl_stream_push_char(s, '\0');
+		tok->u.s = strdup(s->buffer);
+		return tok;
+	}
+	if (c == '=') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("==");
+			tok->type = ISL_TOKEN_EQ_EQ;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		tok->type = (enum isl_token_type) '=';
+		return tok;
+	}
+	if (c == ':') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup(":=");
+			tok->type = ISL_TOKEN_DEF;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		tok->type = (enum isl_token_type) ':';
+		return tok;
+	}
+	if (c == '>') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup(">=");
+			tok->type = ISL_TOKEN_GE;
+			return tok;
+		} else if (c == '>') {
+			if ((c = isl_stream_getc(s)) == '=') {
+				tok->u.s = strdup(">>=");
+				tok->type = ISL_TOKEN_LEX_GE;
+				return tok;
+			}
+			tok->u.s = strdup(">>");
+			tok->type = ISL_TOKEN_LEX_GT;
+		} else {
+			tok->u.s = strdup(">");
+			tok->type = ISL_TOKEN_GT;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+	if (c == '<') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("<=");
+			tok->type = ISL_TOKEN_LE;
+			return tok;
+		} else if (c == '<') {
+			if ((c = isl_stream_getc(s)) == '=') {
+				tok->u.s = strdup("<<=");
+				tok->type = ISL_TOKEN_LEX_LE;
+				return tok;
+			}
+			tok->u.s = strdup("<<");
+			tok->type = ISL_TOKEN_LEX_LT;
+		} else {
+			tok->u.s = strdup("<");
+			tok->type = ISL_TOKEN_LT;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+	if (c == '&') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_AND;
+		if ((c = isl_stream_getc(s)) != '&' && c != -1) {
+			tok->u.s = strdup("&");
+			isl_stream_ungetc(s, c);
+		} else
+			tok->u.s = strdup("&&");
+		return tok;
+	}
+	if (c == '|') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_OR;
+		if ((c = isl_stream_getc(s)) != '|' && c != -1) {
+			tok->u.s = strdup("|");
+			isl_stream_ungetc(s, c);
+		} else
+			tok->u.s = strdup("||");
+		return tok;
+	}
+	if (c == '/') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
+			tok->type = (enum isl_token_type) '/';
+			isl_stream_ungetc(s, c);
+		} else {
+			tok->u.s = strdup("/\\");
+			tok->type = ISL_TOKEN_AND;
+		}
+		return tok;
+	}
+	if (c == '\\') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) != '/' && c != -1) {
+			tok->type = (enum isl_token_type) '\\';
+			isl_stream_ungetc(s, c);
+		} else {
+			tok->u.s = strdup("\\/");
+			tok->type = ISL_TOKEN_OR;
+		}
+		return tok;
+	}
+	if (c == '!') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("!=");
+			tok->type = ISL_TOKEN_NE;
+			return tok;
+		} else {
+			tok->type = ISL_TOKEN_NOT;
+			tok->u.s = strdup("!");
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+
+	tok = isl_token_new(s->ctx, line, col, old_line != line);
+	if (!tok)
+		return NULL;
+	tok->type = ISL_TOKEN_UNKNOWN;
+	return tok;
+error:
+	isl_token_free(tok);
+	return NULL;
+}
+
+struct isl_token *isl_stream_next_token(struct isl_stream *s)
+{
+	return next_token(s, 0);
+}
+
+struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s)
+{
+	return next_token(s, 1);
+}
+
+int isl_stream_eat_if_available(struct isl_stream *s, int type)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == type) {
+		isl_token_free(tok);
+		return 1;
+	}
+	isl_stream_push_token(s, tok);
+	return 0;
+}
+
+int isl_stream_next_token_is(struct isl_stream *s, int type)
+{
+	struct isl_token *tok;
+	int r;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	r = tok->type == type;
+	isl_stream_push_token(s, tok);
+	return r;
+}
+
+char *isl_stream_read_ident_if_available(struct isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return NULL;
+	if (tok->type == ISL_TOKEN_IDENT) {
+		char *ident = strdup(tok->u.s);
+		isl_token_free(tok);
+		return ident;
+	}
+	isl_stream_push_token(s, tok);
+	return NULL;
+}
+
+int isl_stream_eat(struct isl_stream *s, int type)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return -1;
+	if (tok->type == type) {
+		isl_token_free(tok);
+		return 0;
+	}
+	isl_stream_error(s, tok, "expecting other token");
+	isl_stream_push_token(s, tok);
+	return -1;
+}
+
+int isl_stream_is_empty(struct isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+
+	if (!tok)
+		return 1;
+
+	isl_stream_push_token(s, tok);
+	return 0;
+}
+
+static int free_keyword(void **p, void *user)
+{
+	struct isl_keyword *keyword = *p;
+
+	free(keyword->name);
+	free(keyword);
+
+	return 0;
+}
+
+void isl_stream_flush_tokens(struct isl_stream *s)
+{
+	int i;
+
+	if (!s)
+		return;
+	for (i = 0; i < s->n_token; ++i)
+		isl_token_free(s->tokens[i]);
+	s->n_token = 0;
+}
+
+void isl_stream_free(struct isl_stream *s)
+{
+	if (!s)
+		return;
+	free(s->buffer);
+	if (s->n_token != 0) {
+		struct isl_token *tok = isl_stream_next_token(s);
+		isl_stream_error(s, tok, "unexpected token");
+		isl_token_free(tok);
+	}
+	if (s->keywords) {
+		isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
+		isl_hash_table_free(s->ctx, s->keywords);
+	}
+	isl_ctx_deref(s->ctx);
+	free(s);
+}

Added: polly/trunk/lib/External/isl/isl_stream_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_stream_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_stream_private.h (added)
+++ polly/trunk/lib/External/isl/isl_stream_private.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,21 @@
+#include <isl_int.h>
+#include <isl/stream.h>
+
+struct isl_token {
+	int type;
+
+	unsigned int on_new_line : 1;
+	unsigned is_keyword : 1;
+	int line;
+	int col;
+
+	union {
+		isl_int	v;
+		char	*s;
+		isl_map *map;
+		isl_pw_aff *pwaff;
+	} u;
+};
+
+struct isl_token *isl_token_new(isl_ctx *ctx,
+	int line, int col, unsigned on_new_line);

Added: polly/trunk/lib/External/isl/isl_tab.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_tab.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_tab.c (added)
+++ polly/trunk/lib/External/isl/isl_tab.c Wed Feb  4 14:55:43 2015
@@ -0,0 +1,3509 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 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 Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include "isl_map_private.h"
+#include "isl_tab.h"
+#include <isl_seq.h>
+#include <isl_config.h>
+
+/*
+ * The implementation of tableaus in this file was inspired by Section 8
+ * of David Detlefs, Greg Nelson and James B. Saxe, "Simplify: a theorem
+ * prover for program checking".
+ */
+
+struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_var, unsigned M)
+{
+	int i;
+	struct isl_tab *tab;
+	unsigned off = 2 + M;
+
+	tab = isl_calloc_type(ctx, struct isl_tab);
+	if (!tab)
+		return NULL;
+	tab->mat = isl_mat_alloc(ctx, n_row, off + n_var);
+	if (!tab->mat)
+		goto error;
+	tab->var = isl_alloc_array(ctx, struct isl_tab_var, n_var);
+	if (n_var && !tab->var)
+		goto error;
+	tab->con = isl_alloc_array(ctx, struct isl_tab_var, n_row);
+	if (n_row && !tab->con)
+		goto error;
+	tab->col_var = isl_alloc_array(ctx, int, n_var);
+	if (n_var && !tab->col_var)
+		goto error;
+	tab->row_var = isl_alloc_array(ctx, int, n_row);
+	if (n_row && !tab->row_var)
+		goto error;
+	for (i = 0; i < n_var; ++i) {
+		tab->var[i].index = i;
+		tab->var[i].is_row = 0;
+		tab->var[i].is_nonneg = 0;
+		tab->var[i].is_zero = 0;
+		tab->var[i].is_redundant = 0;
+		tab->var[i].frozen = 0;
+		tab->var[i].negated = 0;
+		tab->col_var[i] = i;
+	}
+	tab->n_row = 0;
+	tab->n_con = 0;
+	tab->n_eq = 0;
+	tab->max_con = n_row;
+	tab->n_col = n_var;
+	tab->n_var = n_var;
+	tab->max_var = n_var;
+	tab->n_param = 0;
+	tab->n_div = 0;
+	tab->n_dead = 0;
+	tab->n_redundant = 0;
+	tab->strict_redundant = 0;
+	tab->need_undo = 0;
+	tab->rational = 0;
+	tab->empty = 0;
+	tab->in_undo = 0;
+	tab->M = M;
+	tab->cone = 0;
+	tab->bottom.type = isl_tab_undo_bottom;
+	tab->bottom.next = NULL;
+	tab->top = &tab->bottom;
+
+	tab->n_zero = 0;
+	tab->n_unbounded = 0;
+	tab->basis = NULL;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab)
+{
+	return tab ? isl_mat_get_ctx(tab->mat) : NULL;
+}
+
+int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new)
+{
+	unsigned off;
+
+	if (!tab)
+		return -1;
+
+	off = 2 + tab->M;
+
+	if (tab->max_con < tab->n_con + n_new) {
+		struct isl_tab_var *con;
+
+		con = isl_realloc_array(tab->mat->ctx, tab->con,
+				    struct isl_tab_var, tab->max_con + n_new);
+		if (!con)
+			return -1;
+		tab->con = con;
+		tab->max_con += n_new;
+	}
+	if (tab->mat->n_row < tab->n_row + n_new) {
+		int *row_var;
+
+		tab->mat = isl_mat_extend(tab->mat,
+					tab->n_row + n_new, off + tab->n_col);
+		if (!tab->mat)
+			return -1;
+		row_var = isl_realloc_array(tab->mat->ctx, tab->row_var,
+					    int, tab->mat->n_row);
+		if (!row_var)
+			return -1;
+		tab->row_var = row_var;
+		if (tab->row_sign) {
+			enum isl_tab_row_sign *s;
+			s = isl_realloc_array(tab->mat->ctx, tab->row_sign,
+					enum isl_tab_row_sign, tab->mat->n_row);
+			if (!s)
+				return -1;
+			tab->row_sign = s;
+		}
+	}
+	return 0;
+}
+
+/* Make room for at least n_new extra variables.
+ * Return -1 if anything went wrong.
+ */
+int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new)
+{
+	struct isl_tab_var *var;
+	unsigned off = 2 + tab->M;
+
+	if (tab->max_var < tab->n_var + n_new) {
+		var = isl_realloc_array(tab->mat->ctx, tab->var,
+				    struct isl_tab_var, tab->n_var + n_new);
+		if (!var)
+			return -1;
+		tab->var = var;
+		tab->max_var += n_new;
+	}
+
+	if (tab->mat->n_col < off + tab->n_col + n_new) {
+		int *p;
+
+		tab->mat = isl_mat_extend(tab->mat,
+				    tab->mat->n_row, off + tab->n_col + n_new);
+		if (!tab->mat)
+			return -1;
+		p = isl_realloc_array(tab->mat->ctx, tab->col_var,
+					    int, tab->n_col + n_new);
+		if (!p)
+			return -1;
+		tab->col_var = p;
+	}
+
+	return 0;
+}
+
+static void free_undo_record(struct isl_tab_undo *undo)
+{
+	switch (undo->type) {
+	case isl_tab_undo_saved_basis:
+		free(undo->u.col_var);
+		break;
+	default:;
+	}
+	free(undo);
+}
+
+static void free_undo(struct isl_tab *tab)
+{
+	struct isl_tab_undo *undo, *next;
+
+	for (undo = tab->top; undo && undo != &tab->bottom; undo = next) {
+		next = undo->next;
+		free_undo_record(undo);
+	}
+	tab->top = undo;
+}
+
+void isl_tab_free(struct isl_tab *tab)
+{
+	if (!tab)
+		return;
+	free_undo(tab);
+	isl_mat_free(tab->mat);
+	isl_vec_free(tab->dual);
+	isl_basic_map_free(tab->bmap);
+	free(tab->var);
+	free(tab->con);
+	free(tab->row_var);
+	free(tab->col_var);
+	free(tab->row_sign);
+	isl_mat_free(tab->samples);
+	free(tab->sample_index);
+	isl_mat_free(tab->basis);
+	free(tab);
+}
+
+struct isl_tab *isl_tab_dup(struct isl_tab *tab)
+{
+	int i;
+	struct isl_tab *dup;
+	unsigned off;
+
+	if (!tab)
+		return NULL;
+
+	off = 2 + tab->M;
+	dup = isl_calloc_type(tab->mat->ctx, struct isl_tab);
+	if (!dup)
+		return NULL;
+	dup->mat = isl_mat_dup(tab->mat);
+	if (!dup->mat)
+		goto error;
+	dup->var = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_var);
+	if (tab->max_var && !dup->var)
+		goto error;
+	for (i = 0; i < tab->n_var; ++i)
+		dup->var[i] = tab->var[i];
+	dup->con = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_con);
+	if (tab->max_con && !dup->con)
+		goto error;
+	for (i = 0; i < tab->n_con; ++i)
+		dup->con[i] = tab->con[i];
+	dup->col_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_col - off);
+	if ((tab->mat->n_col - off) && !dup->col_var)
+		goto error;
+	for (i = 0; i < tab->n_col; ++i)
+		dup->col_var[i] = tab->col_var[i];
+	dup->row_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_row);
+	if (tab->mat->n_row && !dup->row_var)
+		goto error;
+	for (i = 0; i < tab->n_row; ++i)
+		dup->row_var[i] = tab->row_var[i];
+	if (tab->row_sign) {
+		dup->row_sign = isl_alloc_array(tab->mat->ctx, enum isl_tab_row_sign,
+						tab->mat->n_row);
+		if (tab->mat->n_row && !dup->row_sign)
+			goto error;
+		for (i = 0; i < tab->n_row; ++i)
+			dup->row_sign[i] = tab->row_sign[i];
+	}
+	if (tab->samples) {
+		dup->samples = isl_mat_dup(tab->samples);
+		if (!dup->samples)
+			goto error;
+		dup->sample_index = isl_alloc_array(tab->mat->ctx, int,
+							tab->samples->n_row);
+		if (tab->samples->n_row && !dup->sample_index)
+			goto error;
+		dup->n_sample = tab->n_sample;
+		dup->n_outside = tab->n_outside;
+	}
+	dup->n_row = tab->n_row;
+	dup->n_con = tab->n_con;
+	dup->n_eq = tab->n_eq;
+	dup->max_con = tab->max_con;
+	dup->n_col = tab->n_col;
+	dup->n_var = tab->n_var;
+	dup->max_var = tab->max_var;
+	dup->n_param = tab->n_param;
+	dup->n_div = tab->n_div;
+	dup->n_dead = tab->n_dead;
+	dup->n_redundant = tab->n_redundant;
+	dup->rational = tab->rational;
+	dup->empty = tab->empty;
+	dup->strict_redundant = 0;
+	dup->need_undo = 0;
+	dup->in_undo = 0;
+	dup->M = tab->M;
+	tab->cone = tab->cone;
+	dup->bottom.type = isl_tab_undo_bottom;
+	dup->bottom.next = NULL;
+	dup->top = &dup->bottom;
+
+	dup->n_zero = tab->n_zero;
+	dup->n_unbounded = tab->n_unbounded;
+	dup->basis = isl_mat_dup(tab->basis);
+
+	return dup;
+error:
+	isl_tab_free(dup);
+	return NULL;
+}
+
+/* Construct the coefficient matrix of the product tableau
+ * of two tableaus.
+ * mat{1,2} is the coefficient matrix of tableau {1,2}
+ * row{1,2} is the number of rows in tableau {1,2}
+ * col{1,2} is the number of columns in tableau {1,2}
+ * off is the offset to the coefficient column (skipping the
+ *	denominator, the constant term and the big parameter if any)
+ * r{1,2} is the number of redundant rows in tableau {1,2}
+ * d{1,2} is the number of dead columns in tableau {1,2}
+ *
+ * The order of the rows and columns in the result is as explained
+ * in isl_tab_product.
+ */
+static struct isl_mat *tab_mat_product(struct isl_mat *mat1,
+	struct isl_mat *mat2, unsigned row1, unsigned row2,
+	unsigned col1, unsigned col2,
+	unsigned off, unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	int i;
+	struct isl_mat *prod;
+	unsigned n;
+
+	prod = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
+					off + col1 + col2);
+	if (!prod)
+		return NULL;
+
+	n = 0;
+	for (i = 0; i < r1; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat1->row[i], off + d1);
+		isl_seq_clr(prod->row[n + i] + off + d1, d2);
+		isl_seq_cpy(prod->row[n + i] + off + d1 + d2,
+				mat1->row[i] + off + d1, col1 - d1);
+		isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2);
+	}
+
+	n += r1;
+	for (i = 0; i < r2; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat2->row[i], off);
+		isl_seq_clr(prod->row[n + i] + off, d1);
+		isl_seq_cpy(prod->row[n + i] + off + d1,
+			    mat2->row[i] + off, d2);
+		isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1);
+		isl_seq_cpy(prod->row[n + i] + off + col1 + d1,
+			    mat2->row[i] + off + d2, col2 - d2);
+	}
+
+	n += r2;
+	for (i = 0; i < row1 - r1; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat1->row[r1 + i], off + d1);
+		isl_seq_clr(prod->row[n + i] + off + d1, d2);
+		isl_seq_cpy(prod->row[n + i] + off + d1 + d2,
+				mat1->row[r1 + i] + off + d1, col1 - d1);
+		isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2);
+	}
+
+	n += row1 - r1;
+	for (i = 0; i < row2 - r2; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat2->row[r2 + i], off);
+		isl_seq_clr(prod->row[n + i] + off, d1);
+		isl_seq_cpy(prod->row[n + i] + off + d1,
+			    mat2->row[r2 + i] + off, d2);
+		isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1);
+		isl_seq_cpy(prod->row[n + i] + off + col1 + d1,
+			    mat2->row[r2 + i] + off + d2, col2 - d2);
+	}
+
+	return prod;
+}
+
+/* Update the row or column index of a variable that corresponds
+ * to a variable in the first input tableau.
+ */
+static void update_index1(struct isl_tab_var *var,
+	unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	if (var->index == -1)
+		return;
+	if (var->is_row && var->index >= r1)
+		var->index += r2;
+	if (!var->is_row && var->index >= d1)
+		var->index += d2;
+}
+
+/* Update the row or column index of a variable that corresponds
+ * to a variable in the second input tableau.
+ */
+static void update_index2(struct isl_tab_var *var,
+	unsigned row1, unsigned col1,
+	unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	if (var->index == -1)
+		return;
+	if (var->is_row) {
+		if (var->index < r2)
+			var->index += r1;
+		else
+			var->index += row1;
+	} else {
+		if (var->index < d2)
+			var->index += d1;
+		else
+			var->index += col1;
+	}
+}
+
+/* Create a tableau that represents the Cartesian product of the sets
+ * represented by tableaus tab1 and tab2.
+ * The order of the rows in the product is
+ *	- redundant rows of tab1
+ *	- redundant rows of tab2
+ *	- non-redundant rows of tab1
+ *	- non-redundant rows of tab2
+ * The order of the columns is
+ *	- denominator
+ *	- constant term
+ *	- coefficient of big parameter, if any
+ *	- dead columns of tab1
+ *	- dead columns of tab2
+ *	- live columns of tab1
+ *	- live columns of tab2
+ * The order of the variables and the constraints is a concatenation
+ * of order in the two input tableaus.
+ */
+struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2)
+{
+	int i;
+	struct isl_tab *prod;
+	unsigned off;
+	unsigned r1, r2, d1, d2;
+
+	if (!tab1 || !tab2)
+		return NULL;
+
+	isl_assert(tab1->mat->ctx, tab1->M == tab2->M, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->rational == tab2->rational, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->cone == tab2->cone, return NULL);
+	isl_assert(tab1->mat->ctx, !tab1->row_sign, return NULL);
+	isl_assert(tab1->mat->ctx, !tab2->row_sign, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->n_param == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab2->n_param == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->n_div == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab2->n_div == 0, return NULL);
+
+	off = 2 + tab1->M;
+	r1 = tab1->n_redundant;
+	r2 = tab2->n_redundant;
+	d1 = tab1->n_dead;
+	d2 = tab2->n_dead;
+	prod = isl_calloc_type(tab1->mat->ctx, struct isl_tab);
+	if (!prod)
+		return NULL;
+	prod->mat = tab_mat_product(tab1->mat, tab2->mat,
+				tab1->n_row, tab2->n_row,
+				tab1->n_col, tab2->n_col, off, r1, r2, d1, d2);
+	if (!prod->mat)
+		goto error;
+	prod->var = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var,
+					tab1->max_var + tab2->max_var);
+	if ((tab1->max_var + tab2->max_var) && !prod->var)
+		goto error;
+	for (i = 0; i < tab1->n_var; ++i) {
+		prod->var[i] = tab1->var[i];
+		update_index1(&prod->var[i], r1, r2, d1, d2);
+	}
+	for (i = 0; i < tab2->n_var; ++i) {
+		prod->var[tab1->n_var + i] = tab2->var[i];
+		update_index2(&prod->var[tab1->n_var + i],
+				tab1->n_row, tab1->n_col,
+				r1, r2, d1, d2);
+	}
+	prod->con = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var,
+					tab1->max_con +  tab2->max_con);
+	if ((tab1->max_con + tab2->max_con) && !prod->con)
+		goto error;
+	for (i = 0; i < tab1->n_con; ++i) {
+		prod->con[i] = tab1->con[i];
+		update_index1(&prod->con[i], r1, r2, d1, d2);
+	}
+	for (i = 0; i < tab2->n_con; ++i) {
+		prod->con[tab1->n_con + i] = tab2->con[i];
+		update_index2(&prod->con[tab1->n_con + i],
+				tab1->n_row, tab1->n_col,
+				r1, r2, d1, d2);
+	}
+	prod->col_var = isl_alloc_array(tab1->mat->ctx, int,
+					tab1->n_col + tab2->n_col);
+	if ((tab1->n_col + tab2->n_col) && !prod->col_var)
+		goto error;
+	for (i = 0; i < tab1->n_col; ++i) {
+		int pos = i < d1 ? i : i + d2;
+		prod->col_var[pos] = tab1->col_var[i];
+	}
+	for (i = 0; i < tab2->n_col; ++i) {
+		int pos = i < d2 ? d1 + i : tab1->n_col + i;
+		int t = tab2->col_var[i];
+		if (t >= 0)
+			t += tab1->n_var;
+		else
+			t -= tab1->n_con;
+		prod->col_var[pos] = t;
+	}
+	prod->row_var = isl_alloc_array(tab1->mat->ctx, int,
+					tab1->mat->n_row + tab2->mat->n_row);
+	if ((tab1->mat->n_row + tab2->mat->n_row) && !prod->row_var)
+		goto error;
+	for (i = 0; i < tab1->n_row; ++i) {
+		int pos = i < r1 ? i : i + r2;
+		prod->row_var[pos] = tab1->row_var[i];
+	}
+	for (i = 0; i < tab2->n_row; ++i) {
+		int pos = i < r2 ? r1 + i : tab1->n_row + i;
+		int t = tab2->row_var[i];
+		if (t >= 0)
+			t += tab1->n_var;
+		else
+			t -= tab1->n_con;
+		prod->row_var[pos] = t;
+	}
+	prod->samples = NULL;
+	prod->sample_index = NULL;
+	prod->n_row = tab1->n_row + tab2->n_row;
+	prod->n_con = tab1->n_con + tab2->n_con;
+	prod->n_eq = 0;
+	prod->max_con = tab1->max_con + tab2->max_con;
+	prod->n_col = tab1->n_col + tab2->n_col;
+	prod->n_var = tab1->n_var + tab2->n_var;
+	prod->max_var = tab1->max_var + tab2->max_var;
+	prod->n_param = 0;
+	prod->n_div = 0;
+	prod->n_dead = tab1->n_dead + tab2->n_dead;
+	prod->n_redundant = tab1->n_redundant + tab2->n_redundant;
+	prod->rational = tab1->rational;
+	prod->empty = tab1->empty || tab2->empty;
+	prod->strict_redundant = tab1->strict_redundant || tab2->strict_redundant;
+	prod->need_undo = 0;
+	prod->in_undo = 0;
+	prod->M = tab1->M;
+	prod->cone = tab1->cone;
+	prod->bottom.type = isl_tab_undo_bottom;
+	prod->bottom.next = NULL;
+	prod->top = &prod->bottom;
+
+	prod->n_zero = 0;
+	prod->n_unbounded = 0;
+	prod->basis = NULL;
+
+	return prod;
+error:
+	isl_tab_free(prod);
+	return NULL;
+}
+
+static struct isl_tab_var *var_from_index(struct isl_tab *tab, int i)
+{
+	if (i >= 0)
+		return &tab->var[i];
+	else
+		return &tab->con[~i];
+}
+
+struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i)
+{
+	return var_from_index(tab, tab->row_var[i]);
+}
+
+static struct isl_tab_var *var_from_col(struct isl_tab *tab, int i)
+{
+	return var_from_index(tab, tab->col_var[i]);
+}
+
+/* Check if there are any upper bounds on column variable "var",
+ * i.e., non-negative rows where var appears with a negative coefficient.
+ * Return 1 if there are no such bounds.
+ */
+static int max_is_manifestly_unbounded(struct isl_tab *tab,
+	struct isl_tab_var *var)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (!isl_int_is_neg(tab->mat->row[i][off + var->index]))
+			continue;
+		if (isl_tab_var_from_row(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if there are any lower bounds on column variable "var",
+ * i.e., non-negative rows where var appears with a positive coefficient.
+ * Return 1 if there are no such bounds.
+ */
+static int min_is_manifestly_unbounded(struct isl_tab *tab,
+	struct isl_tab_var *var)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (!isl_int_is_pos(tab->mat->row[i][off + var->index]))
+			continue;
+		if (isl_tab_var_from_row(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+static int row_cmp(struct isl_tab *tab, int r1, int r2, int c, isl_int t)
+{
+	unsigned off = 2 + tab->M;
+
+	if (tab->M) {
+		int s;
+		isl_int_mul(t, tab->mat->row[r1][2], tab->mat->row[r2][off+c]);
+		isl_int_submul(t, tab->mat->row[r2][2], tab->mat->row[r1][off+c]);
+		s = isl_int_sgn(t);
+		if (s)
+			return s;
+	}
+	isl_int_mul(t, tab->mat->row[r1][1], tab->mat->row[r2][off + c]);
+	isl_int_submul(t, tab->mat->row[r2][1], tab->mat->row[r1][off + c]);
+	return isl_int_sgn(t);
+}
+
+/* Given the index of a column "c", return the index of a row
+ * that can be used to pivot the column in, with either an increase
+ * (sgn > 0) or a decrease (sgn < 0) of the corresponding variable.
+ * If "var" is not NULL, then the row returned will be different from
+ * the one associated with "var".
+ *
+ * Each row in the tableau is of the form
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * Only rows with x_r >= 0 and with the sign of a_ri opposite to "sgn"
+ * impose any limit on the increase or decrease in the value of x_c
+ * and this bound is equal to a_r0 / |a_rc|.  We are therefore looking
+ * for the row with the smallest (most stringent) such bound.
+ * Note that the common denominator of each row drops out of the fraction.
+ * To check if row j has a smaller bound than row r, i.e.,
+ * a_j0 / |a_jc| < a_r0 / |a_rc| or a_j0 |a_rc| < a_r0 |a_jc|,
+ * we check if -sign(a_jc) (a_j0 a_rc - a_r0 a_jc) < 0,
+ * where -sign(a_jc) is equal to "sgn".
+ */
+static int pivot_row(struct isl_tab *tab,
+	struct isl_tab_var *var, int sgn, int c)
+{
+	int j, r, tsgn;
+	isl_int t;
+	unsigned off = 2 + tab->M;
+
+	isl_int_init(t);
+	r = -1;
+	for (j = tab->n_redundant; j < tab->n_row; ++j) {
+		if (var && j == var->index)
+			continue;
+		if (!isl_tab_var_from_row(tab, j)->is_nonneg)
+			continue;
+		if (sgn * isl_int_sgn(tab->mat->row[j][off + c]) >= 0)
+			continue;
+		if (r < 0) {
+			r = j;
+			continue;
+		}
+		tsgn = sgn * row_cmp(tab, r, j, c, t);
+		if (tsgn < 0 || (tsgn == 0 &&
+					    tab->row_var[j] < tab->row_var[r]))
+			r = j;
+	}
+	isl_int_clear(t);
+	return r;
+}
+
+/* Find a pivot (row and col) that will increase (sgn > 0) or decrease
+ * (sgn < 0) the value of row variable var.
+ * If not NULL, then skip_var is a row variable that should be ignored
+ * while looking for a pivot row.  It is usually equal to var.
+ *
+ * As the given row in the tableau is of the form
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * we need to find a column such that the sign of a_ri is equal to "sgn"
+ * (such that an increase in x_i will have the desired effect) or a
+ * column with a variable that may attain negative values.
+ * If a_ri is positive, then we need to move x_i in the same direction
+ * to obtain the desired effect.  Otherwise, x_i has to move in the
+ * opposite direction.
+ */
+static void find_pivot(struct isl_tab *tab,
+	struct isl_tab_var *var, struct isl_tab_var *skip_var,
+	int sgn, int *row, int *col)
+{
+	int j, r, c;
+	isl_int *tr;
+
+	*row = *col = -1;
+
+	isl_assert(tab->mat->ctx, var->is_row, return);
+	tr = tab->mat->row[var->index] + 2 + tab->M;
+
+	c = -1;
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		if (isl_int_is_zero(tr[j]))
+			continue;
+		if (isl_int_sgn(tr[j]) != sgn &&
+		    var_from_col(tab, j)->is_nonneg)
+			continue;
+		if (c < 0 || tab->col_var[j] < tab->col_var[c])
+			c = j;
+	}
+	if (c < 0)
+		return;
+
+	sgn *= isl_int_sgn(tr[c]);
+	r = pivot_row(tab, skip_var, sgn, c);
+	*row = r < 0 ? var->index : r;
+	*col = c;
+}
+
+/* Return 1 if row "row" represents an obviously redundant inequality.
+ * This means
+ *	- it represents an inequality or a variable
+ *	- that is the sum of a non-negative sample value and a positive
+ *	  combination of zero or more non-negative constraints.
+ */
+int isl_tab_row_is_redundant(struct isl_tab *tab, int row)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (tab->row_var[row] < 0 && !isl_tab_var_from_row(tab, row)->is_nonneg)
+		return 0;
+
+	if (isl_int_is_neg(tab->mat->row[row][1]))
+		return 0;
+	if (tab->strict_redundant && isl_int_is_zero(tab->mat->row[row][1]))
+		return 0;
+	if (tab->M && isl_int_is_neg(tab->mat->row[row][2]))
+		return 0;
+
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		if (isl_int_is_zero(tab->mat->row[row][off + i]))
+			continue;
+		if (tab->col_var[i] >= 0)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][off + i]))
+			return 0;
+		if (!var_from_col(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+static void swap_rows(struct isl_tab *tab, int row1, int row2)
+{
+	int t;
+	enum isl_tab_row_sign s;
+
+	t = tab->row_var[row1];
+	tab->row_var[row1] = tab->row_var[row2];
+	tab->row_var[row2] = t;
+	isl_tab_var_from_row(tab, row1)->index = row1;
+	isl_tab_var_from_row(tab, row2)->index = row2;
+	tab->mat = isl_mat_swap_rows(tab->mat, row1, row2);
+
+	if (!tab->row_sign)
+		return;
+	s = tab->row_sign[row1];
+	tab->row_sign[row1] = tab->row_sign[row2];
+	tab->row_sign[row2] = s;
+}
+
+static int push_union(struct isl_tab *tab,
+	enum isl_tab_undo_type type, union isl_tab_undo_val u) WARN_UNUSED;
+static int push_union(struct isl_tab *tab,
+	enum isl_tab_undo_type type, union isl_tab_undo_val u)
+{
+	struct isl_tab_undo *undo;
+
+	if (!tab)
+		return -1;
+	if (!tab->need_undo)
+		return 0;
+
+	undo = isl_alloc_type(tab->mat->ctx, struct isl_tab_undo);
+	if (!undo)
+		return -1;
+	undo->type = type;
+	undo->u = u;
+	undo->next = tab->top;
+	tab->top = undo;
+
+	return 0;
+}
+
+int isl_tab_push_var(struct isl_tab *tab,
+	enum isl_tab_undo_type type, struct isl_tab_var *var)
+{
+	union isl_tab_undo_val u;
+	if (var->is_row)
+		u.var_index = tab->row_var[var->index];
+	else
+		u.var_index = tab->col_var[var->index];
+	return push_union(tab, type, u);
+}
+
+int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type)
+{
+	union isl_tab_undo_val u = { 0 };
+	return push_union(tab, type, u);
+}
+
+/* Push a record on the undo stack describing the current basic
+ * variables, so that the this state can be restored during rollback.
+ */
+int isl_tab_push_basis(struct isl_tab *tab)
+{
+	int i;
+	union isl_tab_undo_val u;
+
+	u.col_var = isl_alloc_array(tab->mat->ctx, int, tab->n_col);
+	if (tab->n_col && !u.col_var)
+		return -1;
+	for (i = 0; i < tab->n_col; ++i)
+		u.col_var[i] = tab->col_var[i];
+	return push_union(tab, isl_tab_undo_saved_basis, u);
+}
+
+int isl_tab_push_callback(struct isl_tab *tab, struct isl_tab_callback *callback)
+{
+	union isl_tab_undo_val u;
+	u.callback = callback;
+	return push_union(tab, isl_tab_undo_callback, u);
+}
+
+struct isl_tab *isl_tab_init_samples(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+
+	tab->n_sample = 0;
+	tab->n_outside = 0;
+	tab->samples = isl_mat_alloc(tab->mat->ctx, 1, 1 + tab->n_var);
+	if (!tab->samples)
+		goto error;
+	tab->sample_index = isl_alloc_array(tab->mat->ctx, int, 1);
+	if (!tab->sample_index)
+		goto error;
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+int isl_tab_add_sample(struct isl_tab *tab, __isl_take isl_vec *sample)
+{
+	if (!tab || !sample)
+		goto error;
+
+	if (tab->n_sample + 1 > tab->samples->n_row) {
+		int *t = isl_realloc_array(tab->mat->ctx,
+			    tab->sample_index, int, tab->n_sample + 1);
+		if (!t)
+			goto error;
+		tab->sample_index = t;
+	}
+
+	tab->samples = isl_mat_extend(tab->samples,
+				tab->n_sample + 1, tab->samples->n_col);
+	if (!tab->samples)
+		goto error;
+
+	isl_seq_cpy(tab->samples->row[tab->n_sample], sample->el, sample->size);
+	isl_vec_free(sample);
+	tab->sample_index[tab->n_sample] = tab->n_sample;
+	tab->n_sample++;
+
+	return 0;
+error:
+	isl_vec_free(sample);
+	return -1;
+}
+
+struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s)
+{
+	if (s != tab->n_outside) {
+		int t = tab->sample_index[tab->n_outside];
+		tab->sample_index[tab->n_outside] = tab->sample_index[s];
+		tab->sample_index[s] = t;
+		isl_mat_swap_rows(tab->samples, tab->n_outside, s);
+	}
+	tab->n_outside++;
+	if (isl_tab_push(tab, isl_tab_undo_drop_sample) < 0) {
+		isl_tab_free(tab);
+		return NULL;
+	}
+
+	return tab;
+}
+
+/* Record the current number of samples so that we can remove newer
+ * samples during a rollback.
+ */
+int isl_tab_save_samples(struct isl_tab *tab)
+{
+	union isl_tab_undo_val u;
+
+	if (!tab)
+		return -1;
+
+	u.n = tab->n_sample;
+	return push_union(tab, isl_tab_undo_saved_samples, u);
+}
+
+/* Mark row with index "row" as being redundant.
+ * If we may need to undo the operation or if the row represents
+ * a variable of the original problem, the row is kept,
+ * but no longer considered when looking for a pivot row.
+ * Otherwise, the row is simply removed.
+ *
+ * The row may be interchanged with some other row.  If it
+ * is interchanged with a later row, return 1.  Otherwise return 0.
+ * If the rows are checked in order in the calling function,
+ * then a return value of 1 means that the row with the given
+ * row number may now contain a different row that hasn't been checked yet.
+ */
+int isl_tab_mark_redundant(struct isl_tab *tab, int row)
+{
+	struct isl_tab_var *var = isl_tab_var_from_row(tab, row);
+	var->is_redundant = 1;
+	isl_assert(tab->mat->ctx, row >= tab->n_redundant, return -1);
+	if (tab->preserve || tab->need_undo || tab->row_var[row] >= 0) {
+		if (tab->row_var[row] >= 0 && !var->is_nonneg) {
+			var->is_nonneg = 1;
+			if (isl_tab_push_var(tab, isl_tab_undo_nonneg, var) < 0)
+				return -1;
+		}
+		if (row != tab->n_redundant)
+			swap_rows(tab, row, tab->n_redundant);
+		tab->n_redundant++;
+		return isl_tab_push_var(tab, isl_tab_undo_redundant, var);
+	} else {
+		if (row != tab->n_row - 1)
+			swap_rows(tab, row, tab->n_row - 1);
+		isl_tab_var_from_row(tab, tab->n_row - 1)->index = -1;
+		tab->n_row--;
+		return 1;
+	}
+}
+
+int isl_tab_mark_empty(struct isl_tab *tab)
+{
+	if (!tab)
+		return -1;
+	if (!tab->empty && tab->need_undo)
+		if (isl_tab_push(tab, isl_tab_undo_empty) < 0)
+			return -1;
+	tab->empty = 1;
+	return 0;
+}
+
+int isl_tab_freeze_constraint(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+
+	var = &tab->con[con];
+	if (var->frozen)
+		return 0;
+	if (var->index < 0)
+		return 0;
+	var->frozen = 1;
+
+	if (tab->need_undo)
+		return isl_tab_push_var(tab, isl_tab_undo_freeze, var);
+
+	return 0;
+}
+
+/* Update the rows signs after a pivot of "row" and "col", with "row_sgn"
+ * the original sign of the pivot element.
+ * We only keep track of row signs during PILP solving and in this case
+ * we only pivot a row with negative sign (meaning the value is always
+ * non-positive) using a positive pivot element.
+ *
+ * For each row j, the new value of the parametric constant is equal to
+ *
+ *	a_j0 - a_jc a_r0/a_rc
+ *
+ * where a_j0 is the original parametric constant, a_rc is the pivot element,
+ * a_r0 is the parametric constant of the pivot row and a_jc is the
+ * pivot column entry of the row j.
+ * Since a_r0 is non-positive and a_rc is positive, the sign of row j
+ * remains the same if a_jc has the same sign as the row j or if
+ * a_jc is zero.  In all other cases, we reset the sign to "unknown".
+ */
+static void update_row_sign(struct isl_tab *tab, int row, int col, int row_sgn)
+{
+	int i;
+	struct isl_mat *mat = tab->mat;
+	unsigned off = 2 + tab->M;
+
+	if (!tab->row_sign)
+		return;
+
+	if (tab->row_sign[row] == 0)
+		return;
+	isl_assert(mat->ctx, row_sgn > 0, return);
+	isl_assert(mat->ctx, tab->row_sign[row] == isl_tab_row_neg, return);
+	tab->row_sign[row] = isl_tab_row_pos;
+	for (i = 0; i < tab->n_row; ++i) {
+		int s;
+		if (i == row)
+			continue;
+		s = isl_int_sgn(mat->row[i][off + col]);
+		if (!s)
+			continue;
+		if (!tab->row_sign[i])
+			continue;
+		if (s < 0 && tab->row_sign[i] == isl_tab_row_neg)
+			continue;
+		if (s > 0 && tab->row_sign[i] == isl_tab_row_pos)
+			continue;
+		tab->row_sign[i] = isl_tab_row_unknown;
+	}
+}
+
+/* Given a row number "row" and a column number "col", pivot the tableau
+ * such that the associated variables are interchanged.
+ * The given row in the tableau expresses
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * or
+ *
+ *	x_c = 1/a_rc x_r - a_r0/a_rc + sum_{i \ne r} -a_ri/a_rc
+ *
+ * Substituting this equality into the other rows
+ *
+ *	x_j = a_j0 + \sum_i a_ji x_i
+ *
+ * with a_jc \ne 0, we obtain
+ *
+ *	x_j = a_jc/a_rc x_r + a_j0 - a_jc a_r0/a_rc + sum a_ji - a_jc a_ri/a_rc 
+ *
+ * The tableau
+ *
+ *	n_rc/d_r		n_ri/d_r
+ *	n_jc/d_j		n_ji/d_j
+ *
+ * where i is any other column and j is any other row,
+ * is therefore transformed into
+ *
+ * s(n_rc)d_r/|n_rc|		-s(n_rc)n_ri/|n_rc|
+ * s(n_rc)d_r n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ * The transformation is performed along the following steps
+ *
+ *	d_r/n_rc		n_ri/n_rc
+ *	n_jc/d_j		n_ji/d_j
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/d_j		n_ji/d_j
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	n_ji/(|n_rc| d_j)
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	(n_ji |n_rc|)/(|n_rc| d_j)
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ * s(n_rc)d_r/|n_rc|		-s(n_rc)n_ri/|n_rc|
+ * s(n_rc)d_r n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ */
+int isl_tab_pivot(struct isl_tab *tab, int row, int col)
+{
+	int i, j;
+	int sgn;
+	int t;
+	isl_ctx *ctx;
+	struct isl_mat *mat = tab->mat;
+	struct isl_tab_var *var;
+	unsigned off = 2 + tab->M;
+
+	ctx = isl_tab_get_ctx(tab);
+	if (isl_ctx_next_operation(ctx) < 0)
+		return -1;
+
+	isl_int_swap(mat->row[row][0], mat->row[row][off + col]);
+	sgn = isl_int_sgn(mat->row[row][0]);
+	if (sgn < 0) {
+		isl_int_neg(mat->row[row][0], mat->row[row][0]);
+		isl_int_neg(mat->row[row][off + col], mat->row[row][off + col]);
+	} else
+		for (j = 0; j < off - 1 + tab->n_col; ++j) {
+			if (j == off - 1 + col)
+				continue;
+			isl_int_neg(mat->row[row][1 + j], mat->row[row][1 + j]);
+		}
+	if (!isl_int_is_one(mat->row[row][0]))
+		isl_seq_normalize(mat->ctx, mat->row[row], off + tab->n_col);
+	for (i = 0; i < tab->n_row; ++i) {
+		if (i == row)
+			continue;
+		if (isl_int_is_zero(mat->row[i][off + col]))
+			continue;
+		isl_int_mul(mat->row[i][0], mat->row[i][0], mat->row[row][0]);
+		for (j = 0; j < off - 1 + tab->n_col; ++j) {
+			if (j == off - 1 + col)
+				continue;
+			isl_int_mul(mat->row[i][1 + j],
+				    mat->row[i][1 + j], mat->row[row][0]);
+			isl_int_addmul(mat->row[i][1 + j],
+				    mat->row[i][off + col], mat->row[row][1 + j]);
+		}
+		isl_int_mul(mat->row[i][off + col],
+			    mat->row[i][off + col], mat->row[row][off + col]);
+		if (!isl_int_is_one(mat->row[i][0]))
+			isl_seq_normalize(mat->ctx, mat->row[i], off + tab->n_col);
+	}
+	t = tab->row_var[row];
+	tab->row_var[row] = tab->col_var[col];
+	tab->col_var[col] = t;
+	var = isl_tab_var_from_row(tab, row);
+	var->is_row = 1;
+	var->index = row;
+	var = var_from_col(tab, col);
+	var->is_row = 0;
+	var->index = col;
+	update_row_sign(tab, row, col, sgn);
+	if (tab->in_undo)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (isl_int_is_zero(mat->row[i][off + col]))
+			continue;
+		if (!isl_tab_var_from_row(tab, i)->frozen &&
+		    isl_tab_row_is_redundant(tab, i)) {
+			int redo = isl_tab_mark_redundant(tab, i);
+			if (redo < 0)
+				return -1;
+			if (redo)
+				--i;
+		}
+	}
+	return 0;
+}
+
+/* If "var" represents a column variable, then pivot is up (sgn > 0)
+ * or down (sgn < 0) to a row.  The variable is assumed not to be
+ * unbounded in the specified direction.
+ * If sgn = 0, then the variable is unbounded in both directions,
+ * and we pivot with any row we can find.
+ */
+static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign) WARN_UNUSED;
+static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign)
+{
+	int r;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+
+	if (sign == 0) {
+		for (r = tab->n_redundant; r < tab->n_row; ++r)
+			if (!isl_int_is_zero(tab->mat->row[r][off+var->index]))
+				break;
+		isl_assert(tab->mat->ctx, r < tab->n_row, return -1);
+	} else {
+		r = pivot_row(tab, NULL, sign, var->index);
+		isl_assert(tab->mat->ctx, r >= 0, return -1);
+	}
+
+	return isl_tab_pivot(tab, r, var->index);
+}
+
+/* Check whether all variables that are marked as non-negative
+ * also have a non-negative sample value.  This function is not
+ * called from the current code but is useful during debugging.
+ */
+static void check_table(struct isl_tab *tab) __attribute__ ((unused));
+static void check_table(struct isl_tab *tab)
+{
+	int i;
+
+	if (tab->empty)
+		return;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var;
+		var = isl_tab_var_from_row(tab, i);
+		if (!var->is_nonneg)
+			continue;
+		if (tab->M) {
+			isl_assert(tab->mat->ctx,
+				!isl_int_is_neg(tab->mat->row[i][2]), abort());
+			if (isl_int_is_pos(tab->mat->row[i][2]))
+				continue;
+		}
+		isl_assert(tab->mat->ctx, !isl_int_is_neg(tab->mat->row[i][1]),
+				abort());
+	}
+}
+
+/* Return the sign of the maximal value of "var".
+ * If the sign is not negative, then on return from this function,
+ * the sample value will also be non-negative.
+ *
+ * If "var" is manifestly unbounded wrt positive values, we are done.
+ * Otherwise, we pivot the variable up to a row if needed
+ * Then we continue pivoting down until either
+ *	- no more down pivots can be performed
+ *	- the sample value is positive
+ *	- the variable is pivoted into a manifestly unbounded column
+ */
+static int sign_of_max(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	if (max_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (to_row(tab, var, 1) < 0)
+		return -2;
+	while (!isl_int_is_pos(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			return isl_int_sgn(tab->mat->row[var->index][1]);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (!var->is_row) /* manifestly unbounded */
+			return 1;
+	}
+	return 1;
+}
+
+int isl_tab_sign_of_max(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -2;
+
+	var = &tab->con[con];
+	isl_assert(tab->mat->ctx, !var->is_redundant, return -2);
+	isl_assert(tab->mat->ctx, !var->is_zero, return -2);
+
+	return sign_of_max(tab, var);
+}
+
+static int row_is_neg(struct isl_tab *tab, int row)
+{
+	if (!tab->M)
+		return isl_int_is_neg(tab->mat->row[row][1]);
+	if (isl_int_is_pos(tab->mat->row[row][2]))
+		return 0;
+	if (isl_int_is_neg(tab->mat->row[row][2]))
+		return 1;
+	return isl_int_is_neg(tab->mat->row[row][1]);
+}
+
+static int row_sgn(struct isl_tab *tab, int row)
+{
+	if (!tab->M)
+		return isl_int_sgn(tab->mat->row[row][1]);
+	if (!isl_int_is_zero(tab->mat->row[row][2]))
+		return isl_int_sgn(tab->mat->row[row][2]);
+	else
+		return isl_int_sgn(tab->mat->row[row][1]);
+}
+
+/* Perform pivots until the row variable "var" has a non-negative
+ * sample value or until no more upward pivots can be performed.
+ * Return the sign of the sample value after the pivots have been
+ * performed.
+ */
+static int restore_row(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	while (row_is_neg(tab, var->index)) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			break;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (!var->is_row) /* manifestly unbounded */
+			return 1;
+	}
+	return row_sgn(tab, var->index);
+}
+
+/* Perform pivots until we are sure that the row variable "var"
+ * can attain non-negative values.  After return from this
+ * function, "var" is still a row variable, but its sample
+ * value may not be non-negative, even if the function returns 1.
+ */
+static int at_least_zero(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	while (isl_int_is_neg(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			break;
+		if (row == var->index) /* manifestly unbounded */
+			return 1;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+	}
+	return !isl_int_is_neg(tab->mat->row[var->index][1]);
+}
+
+/* Return a negative value if "var" can attain negative values.
+ * Return a non-negative value otherwise.
+ *
+ * If "var" is manifestly unbounded wrt negative values, we are done.
+ * Otherwise, if var is in a column, we can pivot it down to a row.
+ * Then we continue pivoting down until either
+ *	- the pivot would result in a manifestly unbounded column
+ *	  => we don't perform the pivot, but simply return -1
+ *	- no more down pivots can be performed
+ *	- the sample value is negative
+ * If the sample value becomes negative and the variable is supposed
+ * to be nonnegative, then we undo the last pivot.
+ * However, if the last pivot has made the pivoting variable
+ * obviously redundant, then it may have moved to another row.
+ * In that case we look for upward pivots until we reach a non-negative
+ * value again.
+ */
+static int sign_of_min(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	struct isl_tab_var *pivot_var = NULL;
+
+	if (min_is_manifestly_unbounded(tab, var))
+		return -1;
+	if (!var->is_row) {
+		col = var->index;
+		row = pivot_row(tab, NULL, -1, col);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (var->is_redundant)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[var->index][1])) {
+			if (var->is_nonneg) {
+				if (!pivot_var->is_redundant &&
+				    pivot_var->index == row) {
+					if (isl_tab_pivot(tab, row, col) < 0)
+						return -2;
+				} else
+					if (restore_row(tab, var) < -1)
+						return -2;
+			}
+			return -1;
+		}
+	}
+	if (var->is_redundant)
+		return 0;
+	while (!isl_int_is_neg(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index)
+			return -1;
+		if (row == -1)
+			return isl_int_sgn(tab->mat->row[var->index][1]);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (var->is_redundant)
+			return 0;
+	}
+	if (pivot_var && var->is_nonneg) {
+		/* pivot back to non-negative value */
+		if (!pivot_var->is_redundant && pivot_var->index == row) {
+			if (isl_tab_pivot(tab, row, col) < 0)
+				return -2;
+		} else
+			if (restore_row(tab, var) < -1)
+				return -2;
+	}
+	return -1;
+}
+
+static int row_at_most_neg_one(struct isl_tab *tab, int row)
+{
+	if (tab->M) {
+		if (isl_int_is_pos(tab->mat->row[row][2]))
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][2]))
+			return 1;
+	}
+	return isl_int_is_neg(tab->mat->row[row][1]) &&
+	       isl_int_abs_ge(tab->mat->row[row][1],
+			      tab->mat->row[row][0]);
+}
+
+/* Return 1 if "var" can attain values <= -1.
+ * Return 0 otherwise.
+ *
+ * The sample value of "var" is assumed to be non-negative when the
+ * the function is called.  If 1 is returned then the constraint
+ * is not redundant and the sample value is made non-negative again before
+ * the function returns.
+ */
+int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	struct isl_tab_var *pivot_var;
+
+	if (min_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (!var->is_row) {
+		col = var->index;
+		row = pivot_row(tab, NULL, -1, col);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (var->is_redundant)
+			return 0;
+		if (row_at_most_neg_one(tab, var->index)) {
+			if (var->is_nonneg) {
+				if (!pivot_var->is_redundant &&
+				    pivot_var->index == row) {
+					if (isl_tab_pivot(tab, row, col) < 0)
+						return -1;
+				} else
+					if (restore_row(tab, var) < -1)
+						return -1;
+			}
+			return 1;
+		}
+	}
+	if (var->is_redundant)
+		return 0;
+	do {
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index) {
+			if (restore_row(tab, var) < -1)
+				return -1;
+			return 1;
+		}
+		if (row == -1)
+			return 0;
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (var->is_redundant)
+			return 0;
+	} while (!row_at_most_neg_one(tab, var->index));
+	if (var->is_nonneg) {
+		/* pivot back to non-negative value */
+		if (!pivot_var->is_redundant && pivot_var->index == row)
+			if (isl_tab_pivot(tab, row, col) < 0)
+				return -1;
+		if (restore_row(tab, var) < -1)
+			return -1;
+	}
+	return 1;
+}
+
+/* Return 1 if "var" can attain values >= 1.
+ * Return 0 otherwise.
+ */
+static int at_least_one(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	isl_int *r;
+
+	if (max_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (to_row(tab, var, 1) < 0)
+		return -1;
+	r = tab->mat->row[var->index];
+	while (isl_int_lt(r[1], r[0])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			return isl_int_ge(r[1], r[0]);
+		if (row == var->index) /* manifestly unbounded */
+			return 1;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+	}
+	return 1;
+}
+
+static void swap_cols(struct isl_tab *tab, int col1, int col2)
+{
+	int t;
+	unsigned off = 2 + tab->M;
+	t = tab->col_var[col1];
+	tab->col_var[col1] = tab->col_var[col2];
+	tab->col_var[col2] = t;
+	var_from_col(tab, col1)->index = col1;
+	var_from_col(tab, col2)->index = col2;
+	tab->mat = isl_mat_swap_cols(tab->mat, off + col1, off + col2);
+}
+
+/* Mark column with index "col" as representing a zero variable.
+ * If we may need to undo the operation the column is kept,
+ * but no longer considered.
+ * Otherwise, the column is simply removed.
+ *
+ * The column may be interchanged with some other column.  If it
+ * is interchanged with a later column, return 1.  Otherwise return 0.
+ * If the columns are checked in order in the calling function,
+ * then a return value of 1 means that the column with the given
+ * column number may now contain a different column that
+ * hasn't been checked yet.
+ */
+int isl_tab_kill_col(struct isl_tab *tab, int col)
+{
+	var_from_col(tab, col)->is_zero = 1;
+	if (tab->need_undo) {
+		if (isl_tab_push_var(tab, isl_tab_undo_zero,
+					    var_from_col(tab, col)) < 0)
+			return -1;
+		if (col != tab->n_dead)
+			swap_cols(tab, col, tab->n_dead);
+		tab->n_dead++;
+		return 0;
+	} else {
+		if (col != tab->n_col - 1)
+			swap_cols(tab, col, tab->n_col - 1);
+		var_from_col(tab, tab->n_col - 1)->index = -1;
+		tab->n_col--;
+		return 1;
+	}
+}
+
+static int row_is_manifestly_non_integral(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+
+	if (tab->M && !isl_int_eq(tab->mat->row[row][2],
+				  tab->mat->row[row][0]))
+		return 0;
+	if (isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+				    tab->n_col - tab->n_dead) != -1)
+		return 0;
+
+	return !isl_int_is_divisible_by(tab->mat->row[row][1],
+					tab->mat->row[row][0]);
+}
+
+/* For integer tableaus, check if any of the coordinates are stuck
+ * at a non-integral value.
+ */
+static int tab_is_manifestly_empty(struct isl_tab *tab)
+{
+	int i;
+
+	if (tab->empty)
+		return 1;
+	if (tab->rational)
+		return 0;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		if (!tab->var[i].is_row)
+			continue;
+		if (row_is_manifestly_non_integral(tab, tab->var[i].index))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Row variable "var" is non-negative and cannot attain any values
+ * larger than zero.  This means that the coefficients of the unrestricted
+ * column variables are zero and that the coefficients of the non-negative
+ * column variables are zero or negative.
+ * Each of the non-negative variables with a negative coefficient can
+ * then also be written as the negative sum of non-negative variables
+ * and must therefore also be zero.
+ */
+static int close_row(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int close_row(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int j;
+	struct isl_mat *mat = tab->mat;
+	unsigned off = 2 + tab->M;
+
+	isl_assert(tab->mat->ctx, var->is_nonneg, return -1);
+	var->is_zero = 1;
+	if (tab->need_undo)
+		if (isl_tab_push_var(tab, isl_tab_undo_zero, var) < 0)
+			return -1;
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		int recheck;
+		if (isl_int_is_zero(mat->row[var->index][off + j]))
+			continue;
+		isl_assert(tab->mat->ctx,
+		    isl_int_is_neg(mat->row[var->index][off + j]), return -1);
+		recheck = isl_tab_kill_col(tab, j);
+		if (recheck < 0)
+			return -1;
+		if (recheck)
+			--j;
+	}
+	if (isl_tab_mark_redundant(tab, var->index) < 0)
+		return -1;
+	if (tab_is_manifestly_empty(tab) && isl_tab_mark_empty(tab) < 0)
+		return -1;
+	return 0;
+}
+
+/* Add a constraint to the tableau and allocate a row for it.
+ * Return the index into the constraint array "con".
+ */
+int isl_tab_allocate_con(struct isl_tab *tab)
+{
+	int r;
+
+	isl_assert(tab->mat->ctx, tab->n_row < tab->mat->n_row, return -1);
+	isl_assert(tab->mat->ctx, tab->n_con < tab->max_con, return -1);
+
+	r = tab->n_con;
+	tab->con[r].index = tab->n_row;
+	tab->con[r].is_row = 1;
+	tab->con[r].is_nonneg = 0;
+	tab->con[r].is_zero = 0;
+	tab->con[r].is_redundant = 0;
+	tab->con[r].frozen = 0;
+	tab->con[r].negated = 0;
+	tab->row_var[tab->n_row] = ~r;
+
+	tab->n_row++;
+	tab->n_con++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->con[r]) < 0)
+		return -1;
+
+	return r;
+}
+
+/* Add a variable to the tableau and allocate a column for it.
+ * Return the index into the variable array "var".
+ */
+int isl_tab_allocate_var(struct isl_tab *tab)
+{
+	int r;
+	int i;
+	unsigned off = 2 + tab->M;
+
+	isl_assert(tab->mat->ctx, tab->n_col < tab->mat->n_col, return -1);
+	isl_assert(tab->mat->ctx, tab->n_var < tab->max_var, return -1);
+
+	r = tab->n_var;
+	tab->var[r].index = tab->n_col;
+	tab->var[r].is_row = 0;
+	tab->var[r].is_nonneg = 0;
+	tab->var[r].is_zero = 0;
+	tab->var[r].is_redundant = 0;
+	tab->var[r].frozen = 0;
+	tab->var[r].negated = 0;
+	tab->col_var[tab->n_col] = r;
+
+	for (i = 0; i < tab->n_row; ++i)
+		isl_int_set_si(tab->mat->row[i][off + tab->n_col], 0);
+
+	tab->n_var++;
+	tab->n_col++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->var[r]) < 0)
+		return -1;
+
+	return r;
+}
+
+/* Add a row to the tableau.  The row is given as an affine combination
+ * of the original variables and needs to be expressed in terms of the
+ * column variables.
+ *
+ * We add each term in turn.
+ * If r = n/d_r is the current sum and we need to add k x, then
+ * 	if x is a column variable, we increase the numerator of
+ *		this column by k d_r
+ *	if x = f/d_x is a row variable, then the new representation of r is
+ *
+ *		 n    k f   d_x/g n + d_r/g k f   m/d_r n + m/d_g k f
+ *		--- + --- = ------------------- = -------------------
+ *		d_r   d_r        d_r d_x/g                m
+ *
+ *	with g the gcd of d_r and d_x and m the lcm of d_r and d_x.
+ *
+ * If tab->M is set, then, internally, each variable x is represented
+ * as x' - M.  We then also need no subtract k d_r from the coefficient of M.
+ */
+int isl_tab_add_row(struct isl_tab *tab, isl_int *line)
+{
+	int i;
+	int r;
+	isl_int *row;
+	isl_int a, b;
+	unsigned off = 2 + tab->M;
+
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	row = tab->mat->row[tab->con[r].index];
+	isl_int_set_si(row[0], 1);
+	isl_int_set(row[1], line[0]);
+	isl_seq_clr(row + 2, tab->M + tab->n_col);
+	for (i = 0; i < tab->n_var; ++i) {
+		if (tab->var[i].is_zero)
+			continue;
+		if (tab->var[i].is_row) {
+			isl_int_lcm(a,
+				row[0], tab->mat->row[tab->var[i].index][0]);
+			isl_int_swap(a, row[0]);
+			isl_int_divexact(a, row[0], a);
+			isl_int_divexact(b,
+				row[0], tab->mat->row[tab->var[i].index][0]);
+			isl_int_mul(b, b, line[1 + i]);
+			isl_seq_combine(row + 1, a, row + 1,
+			    b, tab->mat->row[tab->var[i].index] + 1,
+			    1 + tab->M + tab->n_col);
+		} else
+			isl_int_addmul(row[off + tab->var[i].index],
+							line[1 + i], row[0]);
+		if (tab->M && i >= tab->n_param && i < tab->n_var - tab->n_div)
+			isl_int_submul(row[2], line[1 + i], row[0]);
+	}
+	isl_seq_normalize(tab->mat->ctx, row, off + tab->n_col);
+	isl_int_clear(a);
+	isl_int_clear(b);
+
+	if (tab->row_sign)
+		tab->row_sign[tab->con[r].index] = isl_tab_row_unknown;
+
+	return r;
+}
+
+static int drop_row(struct isl_tab *tab, int row)
+{
+	isl_assert(tab->mat->ctx, ~tab->row_var[row] == tab->n_con - 1, return -1);
+	if (row != tab->n_row - 1)
+		swap_rows(tab, row, tab->n_row - 1);
+	tab->n_row--;
+	tab->n_con--;
+	return 0;
+}
+
+static int drop_col(struct isl_tab *tab, int col)
+{
+	isl_assert(tab->mat->ctx, tab->col_var[col] == tab->n_var - 1, return -1);
+	if (col != tab->n_col - 1)
+		swap_cols(tab, col, tab->n_col - 1);
+	tab->n_col--;
+	tab->n_var--;
+	return 0;
+}
+
+/* Add inequality "ineq" and check if it conflicts with the
+ * previously added constraints or if it is obviously redundant.
+ */
+int isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq)
+{
+	int r;
+	int sgn;
+	isl_int cst;
+
+	if (!tab)
+		return -1;
+	if (tab->bmap) {
+		struct isl_basic_map *bmap = tab->bmap;
+
+		isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, return -1);
+		isl_assert(tab->mat->ctx,
+			    tab->n_con == bmap->n_eq + bmap->n_ineq, return -1);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		if (!tab->bmap)
+			return -1;
+	}
+	if (tab->cone) {
+		isl_int_init(cst);
+		isl_int_swap(ineq[0], cst);
+	}
+	r = isl_tab_add_row(tab, ineq);
+	if (tab->cone) {
+		isl_int_swap(ineq[0], cst);
+		isl_int_clear(cst);
+	}
+	if (r < 0)
+		return -1;
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	if (isl_tab_row_is_redundant(tab, tab->con[r].index)) {
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			return -1;
+		return 0;
+	}
+
+	sgn = restore_row(tab, &tab->con[r]);
+	if (sgn < -1)
+		return -1;
+	if (sgn < 0)
+		return isl_tab_mark_empty(tab);
+	if (tab->con[r].is_row && isl_tab_row_is_redundant(tab, tab->con[r].index))
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			return -1;
+	return 0;
+}
+
+/* Pivot a non-negative variable down until it reaches the value zero
+ * and then pivot the variable into a column position.
+ */
+static int to_col(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int to_col(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int i;
+	int row, col;
+	unsigned off = 2 + tab->M;
+
+	if (!var->is_row)
+		return 0;
+
+	while (isl_int_is_pos(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, NULL, -1, &row, &col);
+		isl_assert(tab->mat->ctx, row != -1, return -1);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (!var->is_row)
+			return 0;
+	}
+
+	for (i = tab->n_dead; i < tab->n_col; ++i)
+		if (!isl_int_is_zero(tab->mat->row[var->index][off + i]))
+			break;
+
+	isl_assert(tab->mat->ctx, i < tab->n_col, return -1);
+	if (isl_tab_pivot(tab, var->index, i) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* We assume Gaussian elimination has been performed on the equalities.
+ * The equalities can therefore never conflict.
+ * Adding the equalities is currently only really useful for a later call
+ * to isl_tab_ineq_type.
+ */
+static struct isl_tab *add_eq(struct isl_tab *tab, isl_int *eq)
+{
+	int i;
+	int r;
+
+	if (!tab)
+		return NULL;
+	r = isl_tab_add_row(tab, eq);
+	if (r < 0)
+		goto error;
+
+	r = tab->con[r].index;
+	i = isl_seq_first_non_zero(tab->mat->row[r] + 2 + tab->M + tab->n_dead,
+					tab->n_col - tab->n_dead);
+	isl_assert(tab->mat->ctx, i >= 0, goto error);
+	i += tab->n_dead;
+	if (isl_tab_pivot(tab, r, i) < 0)
+		goto error;
+	if (isl_tab_kill_col(tab, i) < 0)
+		goto error;
+	tab->n_eq++;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+static int row_is_manifestly_zero(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+
+	if (!isl_int_is_zero(tab->mat->row[row][1]))
+		return 0;
+	if (tab->M && !isl_int_is_zero(tab->mat->row[row][2]))
+		return 0;
+	return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead) == -1;
+}
+
+/* Add an equality that is known to be valid for the given tableau.
+ */
+int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq)
+{
+	struct isl_tab_var *var;
+	int r;
+
+	if (!tab)
+		return -1;
+	r = isl_tab_add_row(tab, eq);
+	if (r < 0)
+		return -1;
+
+	var = &tab->con[r];
+	r = var->index;
+	if (row_is_manifestly_zero(tab, r)) {
+		var->is_zero = 1;
+		if (isl_tab_mark_redundant(tab, r) < 0)
+			return -1;
+		return 0;
+	}
+
+	if (isl_int_is_neg(tab->mat->row[r][1])) {
+		isl_seq_neg(tab->mat->row[r] + 1, tab->mat->row[r] + 1,
+			    1 + tab->n_col);
+		var->negated = 1;
+	}
+	var->is_nonneg = 1;
+	if (to_col(tab, var) < 0)
+		return -1;
+	var->is_nonneg = 0;
+	if (isl_tab_kill_col(tab, var->index) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int add_zero_row(struct isl_tab *tab)
+{
+	int r;
+	isl_int *row;
+
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	row = tab->mat->row[tab->con[r].index];
+	isl_seq_clr(row + 1, 1 + tab->M + tab->n_col);
+	isl_int_set_si(row[0], 1);
+
+	return r;
+}
+
+/* Add equality "eq" and check if it conflicts with the
+ * previously added constraints or if it is obviously redundant.
+ */
+int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq)
+{
+	struct isl_tab_undo *snap = NULL;
+	struct isl_tab_var *var;
+	int r;
+	int row;
+	int sgn;
+	isl_int cst;
+
+	if (!tab)
+		return -1;
+	isl_assert(tab->mat->ctx, !tab->M, return -1);
+
+	if (tab->need_undo)
+		snap = isl_tab_snap(tab);
+
+	if (tab->cone) {
+		isl_int_init(cst);
+		isl_int_swap(eq[0], cst);
+	}
+	r = isl_tab_add_row(tab, eq);
+	if (tab->cone) {
+		isl_int_swap(eq[0], cst);
+		isl_int_clear(cst);
+	}
+	if (r < 0)
+		return -1;
+
+	var = &tab->con[r];
+	row = var->index;
+	if (row_is_manifestly_zero(tab, row)) {
+		if (snap) {
+			if (isl_tab_rollback(tab, snap) < 0)
+				return -1;
+		} else
+			drop_row(tab, row);
+		return 0;
+	}
+
+	if (tab->bmap) {
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		if (!tab->bmap)
+			return -1;
+		if (add_zero_row(tab) < 0)
+			return -1;
+	}
+
+	sgn = isl_int_sgn(tab->mat->row[row][1]);
+
+	if (sgn > 0) {
+		isl_seq_neg(tab->mat->row[row] + 1, tab->mat->row[row] + 1,
+			    1 + tab->n_col);
+		var->negated = 1;
+		sgn = -1;
+	}
+
+	if (sgn < 0) {
+		sgn = sign_of_max(tab, var);
+		if (sgn < -1)
+			return -1;
+		if (sgn < 0) {
+			if (isl_tab_mark_empty(tab) < 0)
+				return -1;
+			return 0;
+		}
+	}
+
+	var->is_nonneg = 1;
+	if (to_col(tab, var) < 0)
+		return -1;
+	var->is_nonneg = 0;
+	if (isl_tab_kill_col(tab, var->index) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Construct and return an inequality that expresses an upper bound
+ * on the given div.
+ * In particular, if the div is given by
+ *
+ *	d = floor(e/m)
+ *
+ * then the inequality expresses
+ *
+ *	m d <= e
+ */
+static struct isl_vec *ineq_for_div(struct isl_basic_map *bmap, unsigned div)
+{
+	unsigned total;
+	unsigned div_pos;
+	struct isl_vec *ineq;
+
+	if (!bmap)
+		return NULL;
+
+	total = isl_basic_map_total_dim(bmap);
+	div_pos = 1 + total - bmap->n_div + div;
+
+	ineq = isl_vec_alloc(bmap->ctx, 1 + total);
+	if (!ineq)
+		return NULL;
+
+	isl_seq_cpy(ineq->el, bmap->div[div] + 1, 1 + total);
+	isl_int_neg(ineq->el[div_pos], bmap->div[div][0]);
+	return ineq;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ *		f - m d >= m
+ *
+ * If add_ineq is not NULL, then this function is used
+ * instead of isl_tab_add_ineq to effectively add the inequalities.
+ */
+static int add_div_constraints(struct isl_tab *tab, unsigned div,
+	int (*add_ineq)(void *user, isl_int *), void *user)
+{
+	unsigned total;
+	unsigned div_pos;
+	struct isl_vec *ineq;
+
+	total = isl_basic_map_total_dim(tab->bmap);
+	div_pos = 1 + total - tab->bmap->n_div + div;
+
+	ineq = ineq_for_div(tab->bmap, div);
+	if (!ineq)
+		goto error;
+
+	if (add_ineq) {
+		if (add_ineq(user, ineq->el) < 0)
+			goto error;
+	} else {
+		if (isl_tab_add_ineq(tab, ineq->el) < 0)
+			goto error;
+	}
+
+	isl_seq_neg(ineq->el, tab->bmap->div[div] + 1, 1 + total);
+	isl_int_set(ineq->el[div_pos], tab->bmap->div[div][0]);
+	isl_int_add(ineq->el[0], ineq->el[0], ineq->el[div_pos]);
+	isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+	if (add_ineq) {
+		if (add_ineq(user, ineq->el) < 0)
+			goto error;
+	} else {
+		if (isl_tab_add_ineq(tab, ineq->el) < 0)
+			goto error;
+	}
+
+	isl_vec_free(ineq);
+
+	return 0;
+error:
+	isl_vec_free(ineq);
+	return -1;
+}
+
+/* Check whether the div described by "div" is obviously non-negative.
+ * If we are using a big parameter, then we will encode the div
+ * as div' = M + div, which is always non-negative.
+ * Otherwise, we check whether div is a non-negative affine combination
+ * of non-negative variables.
+ */
+static int div_is_nonneg(struct isl_tab *tab, __isl_keep isl_vec *div)
+{
+	int i;
+
+	if (tab->M)
+		return 1;
+
+	if (isl_int_is_neg(div->el[1]))
+		return 0;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		if (isl_int_is_neg(div->el[2 + i]))
+			return 0;
+		if (isl_int_is_zero(div->el[2 + i]))
+			continue;
+		if (!tab->var[i].is_nonneg)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Add an extra div, prescribed by "div" to the tableau and
+ * the associated bmap (which is assumed to be non-NULL).
+ *
+ * If add_ineq is not NULL, then this function is used instead
+ * of isl_tab_add_ineq to add the div constraints.
+ * This complication is needed because the code in isl_tab_pip
+ * wants to perform some extra processing when an inequality
+ * is added to the tableau.
+ */
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div,
+	int (*add_ineq)(void *user, isl_int *), void *user)
+{
+	int r;
+	int k;
+	int nonneg;
+
+	if (!tab || !div)
+		return -1;
+
+	isl_assert(tab->mat->ctx, tab->bmap, return -1);
+
+	nonneg = div_is_nonneg(tab, div);
+
+	if (isl_tab_extend_cons(tab, 3) < 0)
+		return -1;
+	if (isl_tab_extend_vars(tab, 1) < 0)
+		return -1;
+	r = isl_tab_allocate_var(tab);
+	if (r < 0)
+		return -1;
+
+	if (nonneg)
+		tab->var[r].is_nonneg = 1;
+
+	tab->bmap = isl_basic_map_extend_space(tab->bmap,
+		isl_basic_map_get_space(tab->bmap), 1, 0, 2);
+	k = isl_basic_map_alloc_div(tab->bmap);
+	if (k < 0)
+		return -1;
+	isl_seq_cpy(tab->bmap->div[k], div->el, div->size);
+	if (isl_tab_push(tab, isl_tab_undo_bmap_div) < 0)
+		return -1;
+
+	if (add_div_constraints(tab, k, add_ineq, user) < 0)
+		return -1;
+
+	return r;
+}
+
+/* If "track" is set, then we want to keep track of all constraints in tab
+ * in its bmap field.  This field is initialized from a copy of "bmap",
+ * so we need to make sure that all constraints in "bmap" also appear
+ * in the constructed tab.
+ */
+__isl_give struct isl_tab *isl_tab_from_basic_map(
+	__isl_keep isl_basic_map *bmap, int track)
+{
+	int i;
+	struct isl_tab *tab;
+
+	if (!bmap)
+		return NULL;
+	tab = isl_tab_alloc(bmap->ctx,
+			    isl_basic_map_total_dim(bmap) + bmap->n_ineq + 1,
+			    isl_basic_map_total_dim(bmap), 0);
+	if (!tab)
+		return NULL;
+	tab->preserve = track;
+	tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) {
+		if (isl_tab_mark_empty(tab) < 0)
+			goto error;
+		goto done;
+	}
+	for (i = 0; i < bmap->n_eq; ++i) {
+		tab = add_eq(tab, bmap->eq[i]);
+		if (!tab)
+			return tab;
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0)
+			goto error;
+		if (tab->empty)
+			goto done;
+	}
+done:
+	if (track && isl_tab_track_bmap(tab, isl_basic_map_copy(bmap)) < 0)
+		goto error;
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+__isl_give struct isl_tab *isl_tab_from_basic_set(
+	__isl_keep isl_basic_set *bset, int track)
+{
+	return isl_tab_from_basic_map(bset, track);
+}
+
+/* Construct a tableau corresponding to the recession cone of "bset".
+ */
+struct isl_tab *isl_tab_from_recession_cone(__isl_keep isl_basic_set *bset,
+	int parametric)
+{
+	isl_int cst;
+	int i;
+	struct isl_tab *tab;
+	unsigned offset = 0;
+
+	if (!bset)
+		return NULL;
+	if (parametric)
+		offset = isl_basic_set_dim(bset, isl_dim_param);
+	tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq,
+				isl_basic_set_total_dim(bset) - offset, 0);
+	if (!tab)
+		return NULL;
+	tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL);
+	tab->cone = 1;
+
+	isl_int_init(cst);
+	for (i = 0; i < bset->n_eq; ++i) {
+		isl_int_swap(bset->eq[i][offset], cst);
+		if (offset > 0) {
+			if (isl_tab_add_eq(tab, bset->eq[i] + offset) < 0)
+				goto error;
+		} else
+			tab = add_eq(tab, bset->eq[i]);
+		isl_int_swap(bset->eq[i][offset], cst);
+		if (!tab)
+			goto done;
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		int r;
+		isl_int_swap(bset->ineq[i][offset], cst);
+		r = isl_tab_add_row(tab, bset->ineq[i] + offset);
+		isl_int_swap(bset->ineq[i][offset], cst);
+		if (r < 0)
+			goto error;
+		tab->con[r].is_nonneg = 1;
+		if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+			goto error;
+	}
+done:
+	isl_int_clear(cst);
+	return tab;
+error:
+	isl_int_clear(cst);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Assuming "tab" is the tableau of a cone, check if the cone is
+ * bounded, i.e., if it is empty or only contains the origin.
+ */
+int isl_tab_cone_is_bounded(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 1;
+	if (tab->n_dead == tab->n_col)
+		return 1;
+
+	for (;;) {
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			struct isl_tab_var *var;
+			int sgn;
+			var = isl_tab_var_from_row(tab, i);
+			if (!var->is_nonneg)
+				continue;
+			sgn = sign_of_max(tab, var);
+			if (sgn < -1)
+				return -1;
+			if (sgn != 0)
+				return 0;
+			if (close_row(tab, var) < 0)
+				return -1;
+			break;
+		}
+		if (tab->n_dead == tab->n_col)
+			return 1;
+		if (i == tab->n_row)
+			return 0;
+	}
+}
+
+int isl_tab_sample_is_integer(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return -1;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		int row;
+		if (!tab->var[i].is_row)
+			continue;
+		row = tab->var[i].index;
+		if (!isl_int_is_divisible_by(tab->mat->row[row][1],
+						tab->mat->row[row][0]))
+			return 0;
+	}
+	return 1;
+}
+
+static struct isl_vec *extract_integer_sample(struct isl_tab *tab)
+{
+	int i;
+	struct isl_vec *vec;
+
+	vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!vec)
+		return NULL;
+
+	isl_int_set_si(vec->block.data[0], 1);
+	for (i = 0; i < tab->n_var; ++i) {
+		if (!tab->var[i].is_row)
+			isl_int_set_si(vec->block.data[1 + i], 0);
+		else {
+			int row = tab->var[i].index;
+			isl_int_divexact(vec->block.data[1 + i],
+				tab->mat->row[row][1], tab->mat->row[row][0]);
+		}
+	}
+
+	return vec;
+}
+
+struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab)
+{
+	int i;
+	struct isl_vec *vec;
+	isl_int m;
+
+	if (!tab)
+		return NULL;
+
+	vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!vec)
+		return NULL;
+
+	isl_int_init(m);
+
+	isl_int_set_si(vec->block.data[0], 1);
+	for (i = 0; i < tab->n_var; ++i) {
+		int row;
+		if (!tab->var[i].is_row) {
+			isl_int_set_si(vec->block.data[1 + i], 0);
+			continue;
+		}
+		row = tab->var[i].index;
+		isl_int_gcd(m, vec->block.data[0], tab->mat->row[row][0]);
+		isl_int_divexact(m, tab->mat->row[row][0], m);
+		isl_seq_scale(vec->block.data, vec->block.data, m, 1 + i);
+		isl_int_divexact(m, vec->block.data[0], tab->mat->row[row][0]);
+		isl_int_mul(vec->block.data[1 + i], m, tab->mat->row[row][1]);
+	}
+	vec = isl_vec_normalize(vec);
+
+	isl_int_clear(m);
+	return vec;
+}
+
+/* Update "bmap" based on the results of the tableau "tab".
+ * In particular, implicit equalities are made explicit, redundant constraints
+ * are removed and if the sample value happens to be integer, it is stored
+ * in "bmap" (unless "bmap" already had an integer sample).
+ *
+ * The tableau is assumed to have been created from "bmap" using
+ * isl_tab_from_basic_map.
+ */
+struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap,
+	struct isl_tab *tab)
+{
+	int i;
+	unsigned n_eq;
+
+	if (!bmap)
+		return NULL;
+	if (!tab)
+		return bmap;
+
+	n_eq = tab->n_eq;
+	if (tab->empty)
+		bmap = isl_basic_map_set_to_empty(bmap);
+	else
+		for (i = bmap->n_ineq - 1; i >= 0; --i) {
+			if (isl_tab_is_equality(tab, n_eq + i))
+				isl_basic_map_inequality_to_equality(bmap, i);
+			else if (isl_tab_is_redundant(tab, n_eq + i))
+				isl_basic_map_drop_inequality(bmap, i);
+		}
+	if (bmap->n_eq != n_eq)
+		isl_basic_map_gauss(bmap, NULL);
+	if (!tab->rational &&
+	    !bmap->sample && isl_tab_sample_is_integer(tab))
+		bmap->sample = extract_integer_sample(tab);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset,
+	struct isl_tab *tab)
+{
+	return (struct isl_basic_set *)isl_basic_map_update_from_tab(
+		(struct isl_basic_map *)bset, tab);
+}
+
+/* Given a non-negative variable "var", add a new non-negative variable
+ * that is the opposite of "var", ensuring that var can only attain the
+ * value zero.
+ * If var = n/d is a row variable, then the new variable = -n/d.
+ * If var is a column variables, then the new variable = -var.
+ * If the new variable cannot attain non-negative values, then
+ * the resulting tableau is empty.
+ * Otherwise, we know the value will be zero and we close the row.
+ */
+static int cut_to_hyperplane(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	unsigned r;
+	isl_int *row;
+	int sgn;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_zero)
+		return 0;
+	isl_assert(tab->mat->ctx, !var->is_redundant, return -1);
+	isl_assert(tab->mat->ctx, var->is_nonneg, return -1);
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return -1;
+
+	r = tab->n_con;
+	tab->con[r].index = tab->n_row;
+	tab->con[r].is_row = 1;
+	tab->con[r].is_nonneg = 0;
+	tab->con[r].is_zero = 0;
+	tab->con[r].is_redundant = 0;
+	tab->con[r].frozen = 0;
+	tab->con[r].negated = 0;
+	tab->row_var[tab->n_row] = ~r;
+	row = tab->mat->row[tab->n_row];
+
+	if (var->is_row) {
+		isl_int_set(row[0], tab->mat->row[var->index][0]);
+		isl_seq_neg(row + 1,
+			    tab->mat->row[var->index] + 1, 1 + tab->n_col);
+	} else {
+		isl_int_set_si(row[0], 1);
+		isl_seq_clr(row + 1, 1 + tab->n_col);
+		isl_int_set_si(row[off + var->index], -1);
+	}
+
+	tab->n_row++;
+	tab->n_con++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->con[r]) < 0)
+		return -1;
+
+	sgn = sign_of_max(tab, &tab->con[r]);
+	if (sgn < -1)
+		return -1;
+	if (sgn < 0) {
+		if (isl_tab_mark_empty(tab) < 0)
+			return -1;
+		return 0;
+	}
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	/* sgn == 0 */
+	if (close_row(tab, &tab->con[r]) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Given a tableau "tab" and an inequality constraint "con" of the tableau,
+ * relax the inequality by one.  That is, the inequality r >= 0 is replaced
+ * by r' = r + 1 >= 0.
+ * If r is a row variable, we simply increase the constant term by one
+ * (taking into account the denominator).
+ * If r is a column variable, then we need to modify each row that
+ * refers to r = r' - 1 by substituting this equality, effectively
+ * subtracting the coefficient of the column from the constant.
+ * We should only do this if the minimum is manifestly unbounded,
+ * however.  Otherwise, we may end up with negative sample values
+ * for non-negative variables.
+ * So, if r is a column variable with a minimum that is not
+ * manifestly unbounded, then we need to move it to a row.
+ * However, the sample value of this row may be negative,
+ * even after the relaxation, so we need to restore it.
+ * We therefore prefer to pivot a column up to a row, if possible.
+ */
+struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+	unsigned off = 2 + tab->M;
+
+	if (!tab)
+		return NULL;
+
+	var = &tab->con[con];
+
+	if (var->is_row && (var->index < 0 || var->index < tab->n_redundant))
+		isl_die(tab->mat->ctx, isl_error_invalid,
+			"cannot relax redundant constraint", goto error);
+	if (!var->is_row && (var->index < 0 || var->index < tab->n_dead))
+		isl_die(tab->mat->ctx, isl_error_invalid,
+			"cannot relax dead constraint", goto error);
+
+	if (!var->is_row && !max_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, 1) < 0)
+			goto error;
+	if (!var->is_row && !min_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, -1) < 0)
+			goto error;
+
+	if (var->is_row) {
+		isl_int_add(tab->mat->row[var->index][1],
+		    tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
+		if (restore_row(tab, var) < 0)
+			goto error;
+	} else {
+		int i;
+
+		for (i = 0; i < tab->n_row; ++i) {
+			if (isl_int_is_zero(tab->mat->row[i][off + var->index]))
+				continue;
+			isl_int_sub(tab->mat->row[i][1], tab->mat->row[i][1],
+			    tab->mat->row[i][off + var->index]);
+		}
+
+	}
+
+	if (isl_tab_push_var(tab, isl_tab_undo_relax, var) < 0)
+		goto error;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Remove the sign constraint from constraint "con".
+ *
+ * If the constraint variable was originally marked non-negative,
+ * then we make sure we mark it non-negative again during rollback.
+ */
+int isl_tab_unrestrict(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+
+	var = &tab->con[con];
+	if (!var->is_nonneg)
+		return 0;
+
+	var->is_nonneg = 0;
+	if (isl_tab_push_var(tab, isl_tab_undo_unrestrict, var) < 0)
+		return -1;
+
+	return 0;
+}
+
+int isl_tab_select_facet(struct isl_tab *tab, int con)
+{
+	if (!tab)
+		return -1;
+
+	return cut_to_hyperplane(tab, &tab->con[con]);
+}
+
+static int may_be_equality(struct isl_tab *tab, int row)
+{
+	return tab->rational ? isl_int_is_zero(tab->mat->row[row][1])
+			     : isl_int_lt(tab->mat->row[row][1],
+					    tab->mat->row[row][0]);
+}
+
+/* Check for (near) equalities among the constraints.
+ * A constraint is an equality if it is non-negative and if
+ * its maximal value is either
+ *	- zero (in case of rational tableaus), or
+ *	- strictly less than 1 (in case of integer tableaus)
+ *
+ * We first mark all non-redundant and non-dead variables that
+ * are not frozen and not obviously not an equality.
+ * Then we iterate over all marked variables if they can attain
+ * any values larger than zero or at least one.
+ * If the maximal value is zero, we mark any column variables
+ * that appear in the row as being zero and mark the row as being redundant.
+ * Otherwise, if the maximal value is strictly less than one (and the
+ * tableau is integer), then we restrict the value to being zero
+ * by adding an opposite non-negative variable.
+ */
+int isl_tab_detect_implicit_equalities(struct isl_tab *tab)
+{
+	int i;
+	unsigned n_marked;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 0;
+	if (tab->n_dead == tab->n_col)
+		return 0;
+
+	n_marked = 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var = isl_tab_var_from_row(tab, i);
+		var->marked = !var->frozen && var->is_nonneg &&
+			may_be_equality(tab, i);
+		if (var->marked)
+			n_marked++;
+	}
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		struct isl_tab_var *var = var_from_col(tab, i);
+		var->marked = !var->frozen && var->is_nonneg;
+		if (var->marked)
+			n_marked++;
+	}
+	while (n_marked) {
+		struct isl_tab_var *var;
+		int sgn;
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (var->marked)
+				break;
+		}
+		if (i == tab->n_row) {
+			for (i = tab->n_dead; i < tab->n_col; ++i) {
+				var = var_from_col(tab, i);
+				if (var->marked)
+					break;
+			}
+			if (i == tab->n_col)
+				break;
+		}
+		var->marked = 0;
+		n_marked--;
+		sgn = sign_of_max(tab, var);
+		if (sgn < 0)
+			return -1;
+		if (sgn == 0) {
+			if (close_row(tab, var) < 0)
+				return -1;
+		} else if (!tab->rational && !at_least_one(tab, var)) {
+			if (cut_to_hyperplane(tab, var) < 0)
+				return -1;
+			return isl_tab_detect_implicit_equalities(tab);
+		}
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (!var->marked)
+				continue;
+			if (may_be_equality(tab, i))
+				continue;
+			var->marked = 0;
+			n_marked--;
+		}
+	}
+
+	return 0;
+}
+
+/* Update the element of row_var or col_var that corresponds to
+ * constraint tab->con[i] to a move from position "old" to position "i".
+ */
+static int update_con_after_move(struct isl_tab *tab, int i, int old)
+{
+	int *p;
+	int index;
+
+	index = tab->con[i].index;
+	if (index == -1)
+		return 0;
+	p = tab->con[i].is_row ? tab->row_var : tab->col_var;
+	if (p[index] != ~old)
+		isl_die(tab->mat->ctx, isl_error_internal,
+			"broken internal state", return -1);
+	p[index] = ~i;
+
+	return 0;
+}
+
+/* Rotate the "n" constraints starting at "first" to the right,
+ * putting the last constraint in the position of the first constraint.
+ */
+static int rotate_constraints(struct isl_tab *tab, int first, int n)
+{
+	int i, last;
+	struct isl_tab_var var;
+
+	if (n <= 1)
+		return 0;
+
+	last = first + n - 1;
+	var = tab->con[last];
+	for (i = last; i > first; --i) {
+		tab->con[i] = tab->con[i - 1];
+		if (update_con_after_move(tab, i, i - 1) < 0)
+			return -1;
+	}
+	tab->con[first] = var;
+	if (update_con_after_move(tab, first, last) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Make the equalities that are implicit in "bmap" but that have been
+ * detected in the corresponding "tab" explicit in "bmap" and update
+ * "tab" to reflect the new order of the constraints.
+ *
+ * In particular, if inequality i is an implicit equality then
+ * isl_basic_map_inequality_to_equality will move the inequality
+ * in front of the other equality and it will move the last inequality
+ * in the position of inequality i.
+ * In the tableau, the inequalities of "bmap" are stored after the equalities
+ * and so the original order
+ *
+ *		E E E E E A A A I B B B B L
+ *
+ * is changed into
+ *
+ *		I E E E E E A A A L B B B B
+ *
+ * where I is the implicit equality, the E are equalities,
+ * the A inequalities before I, the B inequalities after I and
+ * L the last inequality.
+ * We therefore need to rotate to the right two sets of constraints,
+ * those up to and including I and those after I.
+ *
+ * If "tab" contains any constraints that are not in "bmap" then they
+ * appear after those in "bmap" and they should be left untouched.
+ *
+ * Note that this function leaves "bmap" in a temporary state
+ * as it does not call isl_basic_map_gauss.  Calling this function
+ * is the responsibility of the caller.
+ */
+__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab,
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!tab || !bmap)
+		return isl_basic_map_free(bmap);
+	if (tab->empty)
+		return bmap;
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		if (!isl_tab_is_equality(tab, bmap->n_eq + i))
+			continue;
+		isl_basic_map_inequality_to_equality(bmap, i);
+		if (rotate_constraints(tab, 0, tab->n_eq + i + 1) < 0)
+			return isl_basic_map_free(bmap);
+		if (rotate_constraints(tab, tab->n_eq + i + 1,
+					bmap->n_ineq - i) < 0)
+			return isl_basic_map_free(bmap);
+		tab->n_eq++;
+	}
+
+	return bmap;
+}
+
+static int con_is_redundant(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	if (!tab)
+		return -1;
+	if (tab->rational) {
+		int sgn = sign_of_min(tab, var);
+		if (sgn < -1)
+			return -1;
+		return sgn >= 0;
+	} else {
+		int irred = isl_tab_min_at_most_neg_one(tab, var);
+		if (irred < 0)
+			return -1;
+		return !irred;
+	}
+}
+
+/* Check for (near) redundant constraints.
+ * A constraint is redundant if it is non-negative and if
+ * its minimal value (temporarily ignoring the non-negativity) is either
+ *	- zero (in case of rational tableaus), or
+ *	- strictly larger than -1 (in case of integer tableaus)
+ *
+ * We first mark all non-redundant and non-dead variables that
+ * are not frozen and not obviously negatively unbounded.
+ * Then we iterate over all marked variables if they can attain
+ * any values smaller than zero or at most negative one.
+ * If not, we mark the row as being redundant (assuming it hasn't
+ * been detected as being obviously redundant in the mean time).
+ */
+int isl_tab_detect_redundant(struct isl_tab *tab)
+{
+	int i;
+	unsigned n_marked;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 0;
+	if (tab->n_redundant == tab->n_row)
+		return 0;
+
+	n_marked = 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var = isl_tab_var_from_row(tab, i);
+		var->marked = !var->frozen && var->is_nonneg;
+		if (var->marked)
+			n_marked++;
+	}
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		struct isl_tab_var *var = var_from_col(tab, i);
+		var->marked = !var->frozen && var->is_nonneg &&
+			!min_is_manifestly_unbounded(tab, var);
+		if (var->marked)
+			n_marked++;
+	}
+	while (n_marked) {
+		struct isl_tab_var *var;
+		int red;
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (var->marked)
+				break;
+		}
+		if (i == tab->n_row) {
+			for (i = tab->n_dead; i < tab->n_col; ++i) {
+				var = var_from_col(tab, i);
+				if (var->marked)
+					break;
+			}
+			if (i == tab->n_col)
+				break;
+		}
+		var->marked = 0;
+		n_marked--;
+		red = con_is_redundant(tab, var);
+		if (red < 0)
+			return -1;
+		if (red && !var->is_redundant)
+			if (isl_tab_mark_redundant(tab, var->index) < 0)
+				return -1;
+		for (i = tab->n_dead; i < tab->n_col; ++i) {
+			var = var_from_col(tab, i);
+			if (!var->marked)
+				continue;
+			if (!min_is_manifestly_unbounded(tab, var))
+				continue;
+			var->marked = 0;
+			n_marked--;
+		}
+	}
+
+	return 0;
+}
+
+int isl_tab_is_equality(struct isl_tab *tab, int con)
+{
+	int row;
+	unsigned off;
+
+	if (!tab)
+		return -1;
+	if (tab->con[con].is_zero)
+		return 1;
+	if (tab->con[con].is_redundant)
+		return 0;
+	if (!tab->con[con].is_row)
+		return tab->con[con].index < tab->n_dead;
+
+	row = tab->con[con].index;
+
+	off = 2 + tab->M;
+	return isl_int_is_zero(tab->mat->row[row][1]) &&
+		(!tab->M || isl_int_is_zero(tab->mat->row[row][2])) &&
+		isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead) == -1;
+}
+
+/* Return the minimal value of the affine expression "f" with denominator
+ * "denom" in *opt, *opt_denom, assuming the tableau is not empty and
+ * the expression cannot attain arbitrarily small values.
+ * If opt_denom is NULL, then *opt is rounded up to the nearest integer.
+ * The return value reflects the nature of the result (empty, unbounded,
+ * minimal value returned in *opt).
+ */
+enum isl_lp_result isl_tab_min(struct isl_tab *tab,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	unsigned flags)
+{
+	int r;
+	enum isl_lp_result res = isl_lp_ok;
+	struct isl_tab_var *var;
+	struct isl_tab_undo *snap;
+
+	if (!tab)
+		return isl_lp_error;
+
+	if (tab->empty)
+		return isl_lp_empty;
+
+	snap = isl_tab_snap(tab);
+	r = isl_tab_add_row(tab, f);
+	if (r < 0)
+		return isl_lp_error;
+	var = &tab->con[r];
+	for (;;) {
+		int row, col;
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index) {
+			res = isl_lp_unbounded;
+			break;
+		}
+		if (row == -1)
+			break;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return isl_lp_error;
+	}
+	isl_int_mul(tab->mat->row[var->index][0],
+		    tab->mat->row[var->index][0], denom);
+	if (ISL_FL_ISSET(flags, ISL_TAB_SAVE_DUAL)) {
+		int i;
+
+		isl_vec_free(tab->dual);
+		tab->dual = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_con);
+		if (!tab->dual)
+			return isl_lp_error;
+		isl_int_set(tab->dual->el[0], tab->mat->row[var->index][0]);
+		for (i = 0; i < tab->n_con; ++i) {
+			int pos;
+			if (tab->con[i].is_row) {
+				isl_int_set_si(tab->dual->el[1 + i], 0);
+				continue;
+			}
+			pos = 2 + tab->M + tab->con[i].index;
+			if (tab->con[i].negated)
+				isl_int_neg(tab->dual->el[1 + i],
+					    tab->mat->row[var->index][pos]);
+			else
+				isl_int_set(tab->dual->el[1 + i],
+					    tab->mat->row[var->index][pos]);
+		}
+	}
+	if (opt && res == isl_lp_ok) {
+		if (opt_denom) {
+			isl_int_set(*opt, tab->mat->row[var->index][1]);
+			isl_int_set(*opt_denom, tab->mat->row[var->index][0]);
+		} else
+			isl_int_cdiv_q(*opt, tab->mat->row[var->index][1],
+					     tab->mat->row[var->index][0]);
+	}
+	if (isl_tab_rollback(tab, snap) < 0)
+		return isl_lp_error;
+	return res;
+}
+
+int isl_tab_is_redundant(struct isl_tab *tab, int con)
+{
+	if (!tab)
+		return -1;
+	if (tab->con[con].is_zero)
+		return 0;
+	if (tab->con[con].is_redundant)
+		return 1;
+	return tab->con[con].is_row && tab->con[con].index < tab->n_redundant;
+}
+
+/* Take a snapshot of the tableau that can be restored by s call to
+ * isl_tab_rollback.
+ */
+struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+	tab->need_undo = 1;
+	return tab->top;
+}
+
+/* Undo the operation performed by isl_tab_relax.
+ */
+static int unrelax(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int unrelax(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	unsigned off = 2 + tab->M;
+
+	if (!var->is_row && !max_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, 1) < 0)
+			return -1;
+
+	if (var->is_row) {
+		isl_int_sub(tab->mat->row[var->index][1],
+		    tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
+		if (var->is_nonneg) {
+			int sgn = restore_row(tab, var);
+			isl_assert(tab->mat->ctx, sgn >= 0, return -1);
+		}
+	} else {
+		int i;
+
+		for (i = 0; i < tab->n_row; ++i) {
+			if (isl_int_is_zero(tab->mat->row[i][off + var->index]))
+				continue;
+			isl_int_add(tab->mat->row[i][1], tab->mat->row[i][1],
+			    tab->mat->row[i][off + var->index]);
+		}
+
+	}
+
+	return 0;
+}
+
+/* Undo the operation performed by isl_tab_unrestrict.
+ *
+ * In particular, mark the variable as being non-negative and make
+ * sure the sample value respects this constraint.
+ */
+static int ununrestrict(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	var->is_nonneg = 1;
+
+	if (var->is_row && restore_row(tab, var) < -1)
+		return -1;
+
+	return 0;
+}
+
+static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNUSED;
+static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo)
+{
+	struct isl_tab_var *var = var_from_index(tab, undo->u.var_index);
+	switch (undo->type) {
+	case isl_tab_undo_nonneg:
+		var->is_nonneg = 0;
+		break;
+	case isl_tab_undo_redundant:
+		var->is_redundant = 0;
+		tab->n_redundant--;
+		restore_row(tab, isl_tab_var_from_row(tab, tab->n_redundant));
+		break;
+	case isl_tab_undo_freeze:
+		var->frozen = 0;
+		break;
+	case isl_tab_undo_zero:
+		var->is_zero = 0;
+		if (!var->is_row)
+			tab->n_dead--;
+		break;
+	case isl_tab_undo_allocate:
+		if (undo->u.var_index >= 0) {
+			isl_assert(tab->mat->ctx, !var->is_row, return -1);
+			drop_col(tab, var->index);
+			break;
+		}
+		if (!var->is_row) {
+			if (!max_is_manifestly_unbounded(tab, var)) {
+				if (to_row(tab, var, 1) < 0)
+					return -1;
+			} else if (!min_is_manifestly_unbounded(tab, var)) {
+				if (to_row(tab, var, -1) < 0)
+					return -1;
+			} else
+				if (to_row(tab, var, 0) < 0)
+					return -1;
+		}
+		drop_row(tab, var->index);
+		break;
+	case isl_tab_undo_relax:
+		return unrelax(tab, var);
+	case isl_tab_undo_unrestrict:
+		return ununrestrict(tab, var);
+	default:
+		isl_die(tab->mat->ctx, isl_error_internal,
+			"perform_undo_var called on invalid undo record",
+			return -1);
+	}
+
+	return 0;
+}
+
+/* Restore the tableau to the state where the basic variables
+ * are those in "col_var".
+ * We first construct a list of variables that are currently in
+ * the basis, but shouldn't.  Then we iterate over all variables
+ * that should be in the basis and for each one that is currently
+ * not in the basis, we exchange it with one of the elements of the
+ * list constructed before.
+ * We can always find an appropriate variable to pivot with because
+ * the current basis is mapped to the old basis by a non-singular
+ * matrix and so we can never end up with a zero row.
+ */
+static int restore_basis(struct isl_tab *tab, int *col_var)
+{
+	int i, j;
+	int n_extra = 0;
+	int *extra = NULL;	/* current columns that contain bad stuff */
+	unsigned off = 2 + tab->M;
+
+	extra = isl_alloc_array(tab->mat->ctx, int, tab->n_col);
+	if (tab->n_col && !extra)
+		goto error;
+	for (i = 0; i < tab->n_col; ++i) {
+		for (j = 0; j < tab->n_col; ++j)
+			if (tab->col_var[i] == col_var[j])
+				break;
+		if (j < tab->n_col)
+			continue;
+		extra[n_extra++] = i;
+	}
+	for (i = 0; i < tab->n_col && n_extra > 0; ++i) {
+		struct isl_tab_var *var;
+		int row;
+
+		for (j = 0; j < tab->n_col; ++j)
+			if (col_var[i] == tab->col_var[j])
+				break;
+		if (j < tab->n_col)
+			continue;
+		var = var_from_index(tab, col_var[i]);
+		row = var->index;
+		for (j = 0; j < n_extra; ++j)
+			if (!isl_int_is_zero(tab->mat->row[row][off+extra[j]]))
+				break;
+		isl_assert(tab->mat->ctx, j < n_extra, goto error);
+		if (isl_tab_pivot(tab, row, extra[j]) < 0)
+			goto error;
+		extra[j] = extra[--n_extra];
+	}
+
+	free(extra);
+	return 0;
+error:
+	free(extra);
+	return -1;
+}
+
+/* Remove all samples with index n or greater, i.e., those samples
+ * that were added since we saved this number of samples in
+ * isl_tab_save_samples.
+ */
+static void drop_samples_since(struct isl_tab *tab, int n)
+{
+	int i;
+
+	for (i = tab->n_sample - 1; i >= 0 && tab->n_sample > n; --i) {
+		if (tab->sample_index[i] < n)
+			continue;
+
+		if (i != tab->n_sample - 1) {
+			int t = tab->sample_index[tab->n_sample-1];
+			tab->sample_index[tab->n_sample-1] = tab->sample_index[i];
+			tab->sample_index[i] = t;
+			isl_mat_swap_rows(tab->samples, tab->n_sample-1, i);
+		}
+		tab->n_sample--;
+	}
+}
+
+static int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNUSED;
+static int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo)
+{
+	switch (undo->type) {
+	case isl_tab_undo_empty:
+		tab->empty = 0;
+		break;
+	case isl_tab_undo_nonneg:
+	case isl_tab_undo_redundant:
+	case isl_tab_undo_freeze:
+	case isl_tab_undo_zero:
+	case isl_tab_undo_allocate:
+	case isl_tab_undo_relax:
+	case isl_tab_undo_unrestrict:
+		return perform_undo_var(tab, undo);
+	case isl_tab_undo_bmap_eq:
+		return isl_basic_map_free_equality(tab->bmap, 1);
+	case isl_tab_undo_bmap_ineq:
+		return isl_basic_map_free_inequality(tab->bmap, 1);
+	case isl_tab_undo_bmap_div:
+		if (isl_basic_map_free_div(tab->bmap, 1) < 0)
+			return -1;
+		if (tab->samples)
+			tab->samples->n_col--;
+		break;
+	case isl_tab_undo_saved_basis:
+		if (restore_basis(tab, undo->u.col_var) < 0)
+			return -1;
+		break;
+	case isl_tab_undo_drop_sample:
+		tab->n_outside--;
+		break;
+	case isl_tab_undo_saved_samples:
+		drop_samples_since(tab, undo->u.n);
+		break;
+	case isl_tab_undo_callback:
+		return undo->u.callback->run(undo->u.callback);
+	default:
+		isl_assert(tab->mat->ctx, 0, return -1);
+	}
+	return 0;
+}
+
+/* Return the tableau to the state it was in when the snapshot "snap"
+ * was taken.
+ */
+int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap)
+{
+	struct isl_tab_undo *undo, *next;
+
+	if (!tab)
+		return -1;
+
+	tab->in_undo = 1;
+	for (undo = tab->top; undo && undo != &tab->bottom; undo = next) {
+		next = undo->next;
+		if (undo == snap)
+			break;
+		if (perform_undo(tab, undo) < 0) {
+			tab->top = undo;
+			free_undo(tab);
+			tab->in_undo = 0;
+			return -1;
+		}
+		free_undo_record(undo);
+	}
+	tab->in_undo = 0;
+	tab->top = undo;
+	if (!undo)
+		return -1;
+	return 0;
+}
+
+/* The given row "row" represents an inequality violated by all
+ * points in the tableau.  Check for some special cases of such
+ * separating constraints.
+ * In particular, if the row has been reduced to the constant -1,
+ * then we know the inequality is adjacent (but opposite) to
+ * an equality in the tableau.
+ * If the row has been reduced to r = c*(-1 -r'), with r' an inequality
+ * of the tableau and c a positive constant, then the inequality
+ * is adjacent (but opposite) to the inequality r'.
+ */
+static enum isl_ineq_type separation_type(struct isl_tab *tab, unsigned row)
+{
+	int pos;
+	unsigned off = 2 + tab->M;
+
+	if (tab->rational)
+		return isl_ineq_separate;
+
+	if (!isl_int_is_one(tab->mat->row[row][0]))
+		return isl_ineq_separate;
+
+	pos = isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead);
+	if (pos == -1) {
+		if (isl_int_is_negone(tab->mat->row[row][1]))
+			return isl_ineq_adj_eq;
+		else
+			return isl_ineq_separate;
+	}
+
+	if (!isl_int_eq(tab->mat->row[row][1],
+			tab->mat->row[row][off + tab->n_dead + pos]))
+		return isl_ineq_separate;
+
+	pos = isl_seq_first_non_zero(
+			tab->mat->row[row] + off + tab->n_dead + pos + 1,
+			tab->n_col - tab->n_dead - pos - 1);
+
+	return pos == -1 ? isl_ineq_adj_ineq : isl_ineq_separate;
+}
+
+/* Check the effect of inequality "ineq" on the tableau "tab".
+ * The result may be
+ *	isl_ineq_redundant:	satisfied by all points in the tableau
+ *	isl_ineq_separate:	satisfied by no point in the tableau
+ *	isl_ineq_cut:		satisfied by some by not all points
+ *	isl_ineq_adj_eq:	adjacent to an equality
+ *	isl_ineq_adj_ineq:	adjacent to an inequality.
+ */
+enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq)
+{
+	enum isl_ineq_type type = isl_ineq_error;
+	struct isl_tab_undo *snap = NULL;
+	int con;
+	int row;
+
+	if (!tab)
+		return isl_ineq_error;
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return isl_ineq_error;
+
+	snap = isl_tab_snap(tab);
+
+	con = isl_tab_add_row(tab, ineq);
+	if (con < 0)
+		goto error;
+
+	row = tab->con[con].index;
+	if (isl_tab_row_is_redundant(tab, row))
+		type = isl_ineq_redundant;
+	else if (isl_int_is_neg(tab->mat->row[row][1]) &&
+		 (tab->rational ||
+		    isl_int_abs_ge(tab->mat->row[row][1],
+				   tab->mat->row[row][0]))) {
+		int nonneg = at_least_zero(tab, &tab->con[con]);
+		if (nonneg < 0)
+			goto error;
+		if (nonneg)
+			type = isl_ineq_cut;
+		else
+			type = separation_type(tab, row);
+	} else {
+		int red = con_is_redundant(tab, &tab->con[con]);
+		if (red < 0)
+			goto error;
+		if (!red)
+			type = isl_ineq_cut;
+		else
+			type = isl_ineq_redundant;
+	}
+
+	if (isl_tab_rollback(tab, snap))
+		return isl_ineq_error;
+	return type;
+error:
+	return isl_ineq_error;
+}
+
+int isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!tab || !bmap)
+		goto error;
+
+	if (tab->empty) {
+		bmap = isl_basic_map_set_to_empty(bmap);
+		if (!bmap)
+			goto error;
+		tab->bmap = bmap;
+		return 0;
+	}
+
+	isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, goto error);
+	isl_assert(tab->mat->ctx,
+		    tab->n_con == bmap->n_eq + bmap->n_ineq, goto error);
+
+	tab->bmap = bmap;
+
+	return 0;
+error:
+	isl_basic_map_free(bmap);
+	return -1;
+}
+
+int isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset)
+{
+	return isl_tab_track_bmap(tab, (isl_basic_map *)bset);
+}
+
+__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+
+	return (isl_basic_set *)tab->bmap;
+}
+
+static void isl_tab_print_internal(__isl_keep struct isl_tab *tab,
+	FILE *out, int indent)
+{
+	unsigned r, c;
+	int i;
+
+	if (!tab) {
+		fprintf(out, "%*snull tab\n", indent, "");
+		return;
+	}
+	fprintf(out, "%*sn_redundant: %d, n_dead: %d", indent, "",
+		tab->n_redundant, tab->n_dead);
+	if (tab->rational)
+		fprintf(out, ", rational");
+	if (tab->empty)
+		fprintf(out, ", empty");
+	fprintf(out, "\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_var; ++i) {
+		if (i)
+			fprintf(out, (i == tab->n_param ||
+				      i == tab->n_var - tab->n_div) ? "; "
+								    : ", ");
+		fprintf(out, "%c%d%s", tab->var[i].is_row ? 'r' : 'c',
+					tab->var[i].index,
+					tab->var[i].is_zero ? " [=0]" :
+					tab->var[i].is_redundant ? " [R]" : "");
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_con; ++i) {
+		if (i)
+			fprintf(out, ", ");
+		fprintf(out, "%c%d%s", tab->con[i].is_row ? 'r' : 'c',
+					tab->con[i].index,
+					tab->con[i].is_zero ? " [=0]" :
+					tab->con[i].is_redundant ? " [R]" : "");
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_row; ++i) {
+		const char *sign = "";
+		if (i)
+			fprintf(out, ", ");
+		if (tab->row_sign) {
+			if (tab->row_sign[i] == isl_tab_row_unknown)
+				sign = "?";
+			else if (tab->row_sign[i] == isl_tab_row_neg)
+				sign = "-";
+			else if (tab->row_sign[i] == isl_tab_row_pos)
+				sign = "+";
+			else
+				sign = "+-";
+		}
+		fprintf(out, "r%d: %d%s%s", i, tab->row_var[i],
+		    isl_tab_var_from_row(tab, i)->is_nonneg ? " [>=0]" : "", sign);
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_col; ++i) {
+		if (i)
+			fprintf(out, ", ");
+		fprintf(out, "c%d: %d%s", i, tab->col_var[i],
+		    var_from_col(tab, i)->is_nonneg ? " [>=0]" : "");
+	}
+	fprintf(out, "]\n");
+	r = tab->mat->n_row;
+	tab->mat->n_row = tab->n_row;
+	c = tab->mat->n_col;
+	tab->mat->n_col = 2 + tab->M + tab->n_col;
+	isl_mat_print_internal(tab->mat, out, indent);
+	tab->mat->n_row = r;
+	tab->mat->n_col = c;
+	if (tab->bmap)
+		isl_basic_map_print_internal(tab->bmap, out, indent);
+}
+
+void isl_tab_dump(__isl_keep struct isl_tab *tab)
+{
+	isl_tab_print_internal(tab, stderr, 0);
+}

Added: polly/trunk/lib/External/isl/isl_tab.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_tab.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_tab.h (added)
+++ polly/trunk/lib/External/isl/isl_tab.h Wed Feb  4 14:55:43 2015
@@ -0,0 +1,304 @@
+/*
+ * 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_TAB_H
+#define ISL_TAB_H
+
+#include <isl/lp.h>
+#include <isl/map.h>
+#include <isl/mat.h>
+#include <isl/set.h>
+#include <isl_config.h>
+
+struct isl_tab_var {
+	int index;
+	unsigned is_row : 1;
+	unsigned is_nonneg : 1;
+	unsigned is_zero : 1;
+	unsigned is_redundant : 1;
+	unsigned marked : 1;
+	unsigned frozen : 1;
+	unsigned negated : 1;
+};
+
+enum isl_tab_undo_type {
+	isl_tab_undo_bottom,
+	isl_tab_undo_empty,
+	isl_tab_undo_nonneg,
+	isl_tab_undo_redundant,
+	isl_tab_undo_freeze,
+	isl_tab_undo_zero,
+	isl_tab_undo_allocate,
+	isl_tab_undo_relax,
+	isl_tab_undo_unrestrict,
+	isl_tab_undo_bmap_ineq,
+	isl_tab_undo_bmap_eq,
+	isl_tab_undo_bmap_div,
+	isl_tab_undo_saved_basis,
+	isl_tab_undo_drop_sample,
+	isl_tab_undo_saved_samples,
+	isl_tab_undo_callback,
+};
+
+struct isl_tab_callback {
+	int (*run)(struct isl_tab_callback *cb);
+};
+
+union isl_tab_undo_val {
+	int		var_index;
+	int		*col_var;
+	int		n;
+	struct isl_tab_callback	*callback;
+};
+
+struct isl_tab_undo {
+	enum isl_tab_undo_type	type;
+	union isl_tab_undo_val	u;
+	struct isl_tab_undo	*next;
+};
+
+/* The tableau maintains equality relations.
+ * Each column and each row is associated to a variable or a constraint.
+ * The "value" of an inequality constraint is the value of the corresponding
+ * slack variable.
+ * The "row_var" and "col_var" arrays map column and row indices
+ * to indices in the "var" and "con" arrays.  The elements of these
+ * arrays maintain extra information about the variables and the constraints.
+ * Each row expresses the corresponding row variable as an affine expression
+ * of the column variables.
+ * The first two columns in the matrix contain the common denominator of
+ * the row and the numerator of the constant term.
+ * If "M" is set, then the third column represents the "big parameter".
+ * The third (M = 0) or fourth (M = 1) column
+ * in the matrix is called column 0 with respect to the col_var array.
+ * The sample value of the tableau is the value that assigns zero
+ * to all the column variables and the constant term of each affine
+ * expression to the corresponding row variable.
+ * The operations on the tableau maintain the property that the sample
+ * value satisfies the non-negativity constraints (usually on the slack
+ * variables).
+ *
+ * The big parameter represents an arbitrarily big (and divisible)
+ * positive number.  If present, then the sign of a row is determined
+ * lexicographically, with the sign of the big parameter coefficient
+ * considered first.  The big parameter is only used while
+ * solving PILP problems.
+ *
+ * The first n_dead column variables have their values fixed to zero.
+ * The corresponding tab_vars are flagged "is_zero".
+ * Some of the rows that have have zero coefficients in all but
+ * the dead columns are also flagged "is_zero".
+ *
+ * The first n_redundant rows correspond to inequality constraints
+ * that are always satisfied for any value satisfying the non-redundant
+ * rows.  The corresponding tab_vars are flagged "is_redundant".
+ * A row variable that is flagged "is_zero" is also flagged "is_redundant"
+ * since the constraint has been reduced to 0 = 0 and is therefore always
+ * satisfied.
+ *
+ * There are "n_var" variables in total.  The first "n_param" of these
+ * are called parameters and the last "n_div" of these are called divs.
+ * The basic tableau operations makes no distinction between different
+ * kinds of variables.  These special variables are only used while
+ * solving PILP problems.
+ *
+ * Dead columns and redundant rows are detected on the fly.
+ * However, the basic operations do not ensure that all dead columns
+ * or all redundant rows are detected.
+ * isl_tab_detect_implicit_equalities and isl_tab_detect_redundant can be used
+ * to perform and exhaustive search for dead columns and redundant rows.
+ *
+ * The samples matrix contains "n_sample" integer points that have at some
+ * point been elements satisfying the tableau.  The first "n_outside"
+ * of them no longer satisfy the tableau.  They are kept because they
+ * can be reinstated during rollback when the constraint that cut them
+ * out is removed.  These samples are only maintained for the context
+ * tableau while solving PILP problems.
+ *
+ * If "preserve" is set, then we want to keep all constraints in the
+ * tableau, even if they turn out to be redundant.
+ */
+enum isl_tab_row_sign {
+	isl_tab_row_unknown = 0,
+	isl_tab_row_pos,
+	isl_tab_row_neg,
+	isl_tab_row_any,
+};
+struct isl_tab {
+	struct isl_mat *mat;
+
+	unsigned n_row;
+	unsigned n_col;
+	unsigned n_dead;
+	unsigned n_redundant;
+
+	unsigned n_var;
+	unsigned n_param;
+	unsigned n_div;
+	unsigned max_var;
+	unsigned n_con;
+	unsigned n_eq;
+	unsigned max_con;
+	struct isl_tab_var *var;
+	struct isl_tab_var *con;
+	int *row_var;	/* v >= 0 -> var v;	v < 0 -> con ~v */
+	int *col_var;	/* v >= 0 -> var v;	v < 0 -> con ~v */
+	enum isl_tab_row_sign *row_sign;
+
+	struct isl_tab_undo bottom;
+	struct isl_tab_undo *top;
+
+	struct isl_vec *dual;
+	struct isl_basic_map *bmap;
+
+	unsigned n_sample;
+	unsigned n_outside;
+	int *sample_index;
+	struct isl_mat *samples;
+
+	int n_zero;
+	int n_unbounded;
+	struct isl_mat *basis;
+
+	int (*conflict)(int con, void *user);
+	void *conflict_user;
+
+	unsigned strict_redundant : 1;
+	unsigned need_undo : 1;
+	unsigned preserve : 1;
+	unsigned rational : 1;
+	unsigned empty : 1;
+	unsigned in_undo : 1;
+	unsigned M : 1;
+	unsigned cone : 1;
+};
+
+struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_var, unsigned M);
+void isl_tab_free(struct isl_tab *tab);
+
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab);
+
+__isl_give struct isl_tab *isl_tab_from_basic_map(
+	__isl_keep isl_basic_map *bmap, int track);
+__isl_give struct isl_tab *isl_tab_from_basic_set(
+	__isl_keep isl_basic_set *bset, int track);
+struct isl_tab *isl_tab_from_recession_cone(struct isl_basic_set *bset,
+	int parametric);
+int isl_tab_cone_is_bounded(struct isl_tab *tab);
+struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap,
+	struct isl_tab *tab);
+struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset,
+	struct isl_tab *tab);
+int isl_tab_detect_implicit_equalities(struct isl_tab *tab) WARN_UNUSED;
+__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab,
+	__isl_take isl_basic_map *bmap);
+int isl_tab_detect_redundant(struct isl_tab *tab) WARN_UNUSED;
+#define ISL_TAB_SAVE_DUAL	(1 << 0)
+enum isl_lp_result isl_tab_min(struct isl_tab *tab,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	unsigned flags) WARN_UNUSED;
+
+int isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq) WARN_UNUSED;
+int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+
+int isl_tab_freeze_constraint(struct isl_tab *tab, int con) WARN_UNUSED;
+
+int isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap) WARN_UNUSED;
+int isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset) WARN_UNUSED;
+__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab);
+
+int isl_tab_is_equality(struct isl_tab *tab, int con);
+int isl_tab_is_redundant(struct isl_tab *tab, int con);
+
+int isl_tab_sample_is_integer(struct isl_tab *tab);
+struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab);
+
+enum isl_ineq_type {
+	isl_ineq_error = -1,
+	isl_ineq_redundant,
+	isl_ineq_separate,
+	isl_ineq_cut,
+	isl_ineq_adj_eq,
+	isl_ineq_adj_ineq,
+};
+
+enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq);
+
+struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab);
+int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED;
+
+struct isl_tab *isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED;
+int isl_tab_select_facet(struct isl_tab *tab, int con) WARN_UNUSED;
+int isl_tab_unrestrict(struct isl_tab *tab, int con) WARN_UNUSED;
+
+void isl_tab_dump(__isl_keep struct isl_tab *tab);
+
+struct isl_map *isl_tab_basic_map_partial_lexopt(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty, int max);
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexopt_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max);
+
+/* An isl_region represents a sequence of consecutive variables.
+ * pos is the location (starting at 0) of the first variable in the sequence.
+ */
+struct isl_region {
+	int pos;
+	int len;
+};
+
+__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(
+	__isl_take isl_basic_set *bset, int n_op, int n_region,
+	struct isl_region *region,
+	int (*conflict)(int con, void *user), void *user);
+__isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin(
+	__isl_take isl_basic_set *bset);
+
+/* private */
+
+struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i);
+int isl_tab_mark_redundant(struct isl_tab *tab, int row) WARN_UNUSED;
+int isl_tab_mark_empty(struct isl_tab *tab) WARN_UNUSED;
+struct isl_tab *isl_tab_dup(struct isl_tab *tab);
+struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2);
+int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new) WARN_UNUSED;
+int isl_tab_allocate_con(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new) WARN_UNUSED;
+int isl_tab_allocate_var(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_pivot(struct isl_tab *tab, int row, int col) WARN_UNUSED;
+int isl_tab_add_row(struct isl_tab *tab, isl_int *line) WARN_UNUSED;
+int isl_tab_row_is_redundant(struct isl_tab *tab, int row);
+int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var);
+int isl_tab_sign_of_max(struct isl_tab *tab, int con);
+int isl_tab_kill_col(struct isl_tab *tab, int col) WARN_UNUSED;
+
+int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type) WARN_UNUSED;
+int isl_tab_push_var(struct isl_tab *tab,
+	enum isl_tab_undo_type type, struct isl_tab_var *var) WARN_UNUSED;
+int isl_tab_push_basis(struct isl_tab *tab) WARN_UNUSED;
+
+struct isl_tab *isl_tab_init_samples(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_add_sample(struct isl_tab *tab,
+	__isl_take isl_vec *sample) WARN_UNUSED;
+struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s);
+int isl_tab_save_samples(struct isl_tab *tab) WARN_UNUSED;
+
+struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab,
+	struct isl_tab *tab_cone) WARN_UNUSED;
+
+int isl_tab_push_callback(struct isl_tab *tab,
+	struct isl_tab_callback *callback) WARN_UNUSED;
+
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div,
+	int (*add_ineq)(void *user, isl_int *), void *user);
+
+#endif






More information about the llvm-commits mailing list