[polly] r228193 - Import isl(+imath) as an external library into Polly
Tobias Grosser
tobias at grosser.es
Wed Feb 4 12:55:55 PST 2015
Added: polly/trunk/lib/External/isl/isl_coalesce.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_coalesce.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_coalesce.c (added)
+++ polly/trunk/lib/External/isl/isl_coalesce.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,1745 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+#include "isl_map_private.h"
+#include <isl_seq.h>
+#include <isl/options.h>
+#include "isl_tab.h"
+#include <isl_mat_private.h>
+#include <isl_local_space_private.h>
+#include <isl_vec_private.h>
+
+#define STATUS_ERROR -1
+#define STATUS_REDUNDANT 1
+#define STATUS_VALID 2
+#define STATUS_SEPARATE 3
+#define STATUS_CUT 4
+#define STATUS_ADJ_EQ 5
+#define STATUS_ADJ_INEQ 6
+
+static int status_in(isl_int *ineq, struct isl_tab *tab)
+{
+ enum isl_ineq_type type = isl_tab_ineq_type(tab, ineq);
+ switch (type) {
+ default:
+ case isl_ineq_error: return STATUS_ERROR;
+ case isl_ineq_redundant: return STATUS_VALID;
+ case isl_ineq_separate: return STATUS_SEPARATE;
+ case isl_ineq_cut: return STATUS_CUT;
+ case isl_ineq_adj_eq: return STATUS_ADJ_EQ;
+ case isl_ineq_adj_ineq: return STATUS_ADJ_INEQ;
+ }
+}
+
+/* Compute the position of the equalities of basic map "bmap_i"
+ * with respect to the basic map represented by "tab_j".
+ * The resulting array has twice as many entries as the number
+ * of equalities corresponding to the two inequalties to which
+ * each equality corresponds.
+ */
+static int *eq_status_in(__isl_keep isl_basic_map *bmap_i,
+ struct isl_tab *tab_j)
+{
+ int k, l;
+ int *eq = isl_calloc_array(bmap_i->ctx, int, 2 * bmap_i->n_eq);
+ unsigned dim;
+
+ if (!eq)
+ return NULL;
+
+ dim = isl_basic_map_total_dim(bmap_i);
+ for (k = 0; k < bmap_i->n_eq; ++k) {
+ for (l = 0; l < 2; ++l) {
+ isl_seq_neg(bmap_i->eq[k], bmap_i->eq[k], 1+dim);
+ eq[2 * k + l] = status_in(bmap_i->eq[k], tab_j);
+ if (eq[2 * k + l] == STATUS_ERROR)
+ goto error;
+ }
+ if (eq[2 * k] == STATUS_SEPARATE ||
+ eq[2 * k + 1] == STATUS_SEPARATE)
+ break;
+ }
+
+ return eq;
+error:
+ free(eq);
+ return NULL;
+}
+
+/* Compute the position of the inequalities of basic map "bmap_i"
+ * (also represented by "tab_i", if not NULL) with respect to the basic map
+ * represented by "tab_j".
+ */
+static int *ineq_status_in(__isl_keep isl_basic_map *bmap_i,
+ struct isl_tab *tab_i, struct isl_tab *tab_j)
+{
+ int k;
+ unsigned n_eq = bmap_i->n_eq;
+ int *ineq = isl_calloc_array(bmap_i->ctx, int, bmap_i->n_ineq);
+
+ if (!ineq)
+ return NULL;
+
+ for (k = 0; k < bmap_i->n_ineq; ++k) {
+ if (tab_i && isl_tab_is_redundant(tab_i, n_eq + k)) {
+ ineq[k] = STATUS_REDUNDANT;
+ continue;
+ }
+ ineq[k] = status_in(bmap_i->ineq[k], tab_j);
+ if (ineq[k] == STATUS_ERROR)
+ goto error;
+ if (ineq[k] == STATUS_SEPARATE)
+ break;
+ }
+
+ return ineq;
+error:
+ free(ineq);
+ return NULL;
+}
+
+static int any(int *con, unsigned len, int status)
+{
+ int i;
+
+ for (i = 0; i < len ; ++i)
+ if (con[i] == status)
+ return 1;
+ return 0;
+}
+
+static int count(int *con, unsigned len, int status)
+{
+ int i;
+ int c = 0;
+
+ for (i = 0; i < len ; ++i)
+ if (con[i] == status)
+ c++;
+ return c;
+}
+
+static int all(int *con, unsigned len, int status)
+{
+ int i;
+
+ for (i = 0; i < len ; ++i) {
+ if (con[i] == STATUS_REDUNDANT)
+ continue;
+ if (con[i] != status)
+ return 0;
+ }
+ return 1;
+}
+
+static void drop(struct isl_map *map, int i, struct isl_tab **tabs)
+{
+ isl_basic_map_free(map->p[i]);
+ isl_tab_free(tabs[i]);
+
+ if (i != map->n - 1) {
+ map->p[i] = map->p[map->n - 1];
+ tabs[i] = tabs[map->n - 1];
+ }
+ tabs[map->n - 1] = NULL;
+ map->n--;
+}
+
+/* Replace the pair of basic maps i and j by the basic map bounded
+ * by the valid constraints in both basic maps and the constraint
+ * in extra (if not NULL).
+ */
+static int fuse(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j,
+ __isl_keep isl_mat *extra)
+{
+ int k, l;
+ struct isl_basic_map *fused = NULL;
+ struct isl_tab *fused_tab = NULL;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+ unsigned extra_rows = extra ? extra->n_row : 0;
+
+ fused = isl_basic_map_alloc_space(isl_space_copy(map->p[i]->dim),
+ map->p[i]->n_div,
+ map->p[i]->n_eq + map->p[j]->n_eq,
+ map->p[i]->n_ineq + map->p[j]->n_ineq + extra_rows);
+ if (!fused)
+ goto error;
+
+ for (k = 0; k < map->p[i]->n_eq; ++k) {
+ if (eq_i && (eq_i[2 * k] != STATUS_VALID ||
+ eq_i[2 * k + 1] != STATUS_VALID))
+ continue;
+ l = isl_basic_map_alloc_equality(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->eq[l], map->p[i]->eq[k], 1 + total);
+ }
+
+ for (k = 0; k < map->p[j]->n_eq; ++k) {
+ if (eq_j && (eq_j[2 * k] != STATUS_VALID ||
+ eq_j[2 * k + 1] != STATUS_VALID))
+ continue;
+ l = isl_basic_map_alloc_equality(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->eq[l], map->p[j]->eq[k], 1 + total);
+ }
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k) {
+ if (ineq_i[k] != STATUS_VALID)
+ continue;
+ l = isl_basic_map_alloc_inequality(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->ineq[l], map->p[i]->ineq[k], 1 + total);
+ }
+
+ for (k = 0; k < map->p[j]->n_ineq; ++k) {
+ if (ineq_j[k] != STATUS_VALID)
+ continue;
+ l = isl_basic_map_alloc_inequality(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->ineq[l], map->p[j]->ineq[k], 1 + total);
+ }
+
+ for (k = 0; k < map->p[i]->n_div; ++k) {
+ int l = isl_basic_map_alloc_div(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->div[l], map->p[i]->div[k], 1 + 1 + total);
+ }
+
+ for (k = 0; k < extra_rows; ++k) {
+ l = isl_basic_map_alloc_inequality(fused);
+ if (l < 0)
+ goto error;
+ isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total);
+ }
+
+ fused = isl_basic_map_gauss(fused, NULL);
+ ISL_F_SET(fused, ISL_BASIC_MAP_FINAL);
+ if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) &&
+ ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL))
+ ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL);
+
+ fused_tab = isl_tab_from_basic_map(fused, 0);
+ if (isl_tab_detect_redundant(fused_tab) < 0)
+ goto error;
+
+ isl_basic_map_free(map->p[i]);
+ map->p[i] = fused;
+ isl_tab_free(tabs[i]);
+ tabs[i] = fused_tab;
+ drop(map, j, tabs);
+
+ return 1;
+error:
+ isl_tab_free(fused_tab);
+ isl_basic_map_free(fused);
+ return -1;
+}
+
+/* Given a pair of basic maps i and j such that all constraints are either
+ * "valid" or "cut", check if the facets corresponding to the "cut"
+ * constraints of i lie entirely within basic map j.
+ * If so, replace the pair by the basic map consisting of the valid
+ * constraints in both basic maps.
+ *
+ * To see that we are not introducing any extra points, call the
+ * two basic maps A and B and the resulting map U and let x
+ * be an element of U \setminus ( A \cup B ).
+ * Then there is a pair of cut constraints c_1 and c_2 in A and B such that x
+ * violates them. Let X be the intersection of U with the opposites
+ * of these constraints. Then x \in X.
+ * The facet corresponding to c_1 contains the corresponding facet of A.
+ * This facet is entirely contained in B, so c_2 is valid on the facet.
+ * However, since it is also (part of) a facet of X, -c_2 is also valid
+ * on the facet. This means c_2 is saturated on the facet, so c_1 and
+ * c_2 must be opposites of each other, but then x could not violate
+ * both of them.
+ */
+static int check_facets(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *ineq_i, int *ineq_j)
+{
+ int k, l;
+ struct isl_tab_undo *snap;
+ unsigned n_eq = map->p[i]->n_eq;
+
+ snap = isl_tab_snap(tabs[i]);
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k) {
+ if (ineq_i[k] != STATUS_CUT)
+ continue;
+ if (isl_tab_select_facet(tabs[i], n_eq + k) < 0)
+ return -1;
+ for (l = 0; l < map->p[j]->n_ineq; ++l) {
+ int stat;
+ if (ineq_j[l] != STATUS_CUT)
+ continue;
+ stat = status_in(map->p[j]->ineq[l], tabs[i]);
+ if (stat != STATUS_VALID)
+ break;
+ }
+ if (isl_tab_rollback(tabs[i], snap) < 0)
+ return -1;
+ if (l < map->p[j]->n_ineq)
+ break;
+ }
+
+ if (k < map->p[i]->n_ineq)
+ /* BAD CUT PAIR */
+ return 0;
+ return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
+}
+
+/* Check if basic map "i" contains the basic map represented
+ * by the tableau "tab".
+ */
+static int contains(struct isl_map *map, int i, int *ineq_i,
+ struct isl_tab *tab)
+{
+ int k, l;
+ unsigned dim;
+
+ dim = isl_basic_map_total_dim(map->p[i]);
+ for (k = 0; k < map->p[i]->n_eq; ++k) {
+ for (l = 0; l < 2; ++l) {
+ int stat;
+ isl_seq_neg(map->p[i]->eq[k], map->p[i]->eq[k], 1+dim);
+ stat = status_in(map->p[i]->eq[k], tab);
+ if (stat != STATUS_VALID)
+ return 0;
+ }
+ }
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k) {
+ int stat;
+ if (ineq_i[k] == STATUS_REDUNDANT)
+ continue;
+ stat = status_in(map->p[i]->ineq[k], tab);
+ if (stat != STATUS_VALID)
+ return 0;
+ }
+ return 1;
+}
+
+/* Basic map "i" has an inequality (say "k") that is adjacent
+ * to some inequality of basic map "j". All the other inequalities
+ * are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * Note that this function is only called if some of the equalities or
+ * inequalities of basic map "j" do cut basic map "i". The function is
+ * correct even if there are no such cut constraints, but in that case
+ * the additional checks performed by this function are overkill.
+ *
+ * In particular, we replace constraint k, say f >= 0, by constraint
+ * f <= -1, add the inequalities of "j" that are valid for "i"
+ * and check if the result is a subset of basic map "j".
+ * If so, then we know that this result is exactly equal to basic map "j"
+ * since all its constraints are valid for basic map "j".
+ * By combining the valid constraints of "i" (all equalities and all
+ * inequalities except "k") and the valid constraints of "j" we therefore
+ * obtain a basic map that is equal to their union.
+ * In this case, there is no need to perform a rollback of the tableau
+ * since it is going to be destroyed in fuse().
+ *
+ *
+ * |\__ |\__
+ * | \__ | \__
+ * | \_ => | \__
+ * |_______| _ |_________\
+ *
+ *
+ * |\ |\
+ * | \ | \
+ * | \ | \
+ * | | | \
+ * | ||\ => | \
+ * | || \ | \
+ * | || | | |
+ * |__||_/ |_____/
+ */
+static int is_adj_ineq_extension(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int k;
+ struct isl_tab_undo *snap;
+ unsigned n_eq = map->p[i]->n_eq;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+ int r;
+
+ if (isl_tab_extend_cons(tabs[i], 1 + map->p[j]->n_ineq) < 0)
+ return -1;
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k)
+ if (ineq_i[k] == STATUS_ADJ_INEQ)
+ break;
+ if (k >= map->p[i]->n_ineq)
+ isl_die(isl_map_get_ctx(map), isl_error_internal,
+ "ineq_i should have exactly one STATUS_ADJ_INEQ",
+ return -1);
+
+ snap = isl_tab_snap(tabs[i]);
+
+ if (isl_tab_unrestrict(tabs[i], n_eq + k) < 0)
+ return -1;
+
+ isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+ isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ r = isl_tab_add_ineq(tabs[i], map->p[i]->ineq[k]);
+ isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+ isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ if (r < 0)
+ return -1;
+
+ for (k = 0; k < map->p[j]->n_ineq; ++k) {
+ if (ineq_j[k] != STATUS_VALID)
+ continue;
+ if (isl_tab_add_ineq(tabs[i], map->p[j]->ineq[k]) < 0)
+ return -1;
+ }
+
+ if (contains(map, j, ineq_j, tabs[i]))
+ return fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, NULL);
+
+ if (isl_tab_rollback(tabs[i], snap) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/* Both basic maps have at least one inequality with and adjacent
+ * (but opposite) inequality in the other basic map.
+ * Check that there are no cut constraints and that there is only
+ * a single pair of adjacent inequalities.
+ * If so, we can replace the pair by a single basic map described
+ * by all but the pair of adjacent inequalities.
+ * Any additional points introduced lie strictly between the two
+ * adjacent hyperplanes and can therefore be integral.
+ *
+ * ____ _____
+ * / ||\ / \
+ * / || \ / \
+ * \ || \ => \ \
+ * \ || / \ /
+ * \___||_/ \_____/
+ *
+ * The test for a single pair of adjancent inequalities is important
+ * for avoiding the combination of two basic maps like the following
+ *
+ * /|
+ * / |
+ * /__|
+ * _____
+ * | |
+ * | |
+ * |___|
+ *
+ * If there are some cut constraints on one side, then we may
+ * still be able to fuse the two basic maps, but we need to perform
+ * some additional checks in is_adj_ineq_extension.
+ */
+static int check_adj_ineq(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int count_i, count_j;
+ int cut_i, cut_j;
+
+ count_i = count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ);
+ count_j = count(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ);
+
+ if (count_i != 1 && count_j != 1)
+ return 0;
+
+ cut_i = any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) ||
+ any(ineq_i, map->p[i]->n_ineq, STATUS_CUT);
+ cut_j = any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT) ||
+ any(ineq_j, map->p[j]->n_ineq, STATUS_CUT);
+
+ if (!cut_i && !cut_j && count_i == 1 && count_j == 1)
+ return fuse(map, i, j, tabs, NULL, ineq_i, NULL, ineq_j, NULL);
+
+ if (count_i == 1 && !cut_i)
+ return is_adj_ineq_extension(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+
+ if (count_j == 1 && !cut_j)
+ return is_adj_ineq_extension(map, j, i, tabs,
+ eq_j, ineq_j, eq_i, ineq_i);
+
+ return 0;
+}
+
+/* Basic map "i" has an inequality "k" that is adjacent to some equality
+ * of basic map "j". All the other inequalities are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * In particular, we relax constraint "k", compute the corresponding
+ * facet and check whether it is included in the other basic map.
+ * If so, we know that relaxing the constraint extends the basic
+ * map with exactly the other basic map (we already know that this
+ * other basic map is included in the extension, because there
+ * were no "cut" inequalities in "i") and we can replace the
+ * two basic maps by this extension.
+ * ____ _____
+ * / || / |
+ * / || / |
+ * \ || => \ |
+ * \ || \ |
+ * \___|| \____|
+ */
+static int is_adj_eq_extension(struct isl_map *map, int i, int j, int k,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+ int super;
+ struct isl_tab_undo *snap, *snap2;
+ unsigned n_eq = map->p[i]->n_eq;
+
+ if (isl_tab_is_equality(tabs[i], n_eq + k))
+ return 0;
+
+ snap = isl_tab_snap(tabs[i]);
+ tabs[i] = isl_tab_relax(tabs[i], n_eq + k);
+ snap2 = isl_tab_snap(tabs[i]);
+ if (isl_tab_select_facet(tabs[i], n_eq + k) < 0)
+ return -1;
+ super = contains(map, j, ineq_j, tabs[i]);
+ if (super) {
+ if (isl_tab_rollback(tabs[i], snap2) < 0)
+ return -1;
+ map->p[i] = isl_basic_map_cow(map->p[i]);
+ if (!map->p[i])
+ return -1;
+ isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ ISL_F_SET(map->p[i], ISL_BASIC_MAP_FINAL);
+ drop(map, j, tabs);
+ changed = 1;
+ } else
+ if (isl_tab_rollback(tabs[i], snap) < 0)
+ return -1;
+
+ return changed;
+}
+
+/* Data structure that keeps track of the wrapping constraints
+ * and of information to bound the coefficients of those constraints.
+ *
+ * bound is set if we want to apply a bound on the coefficients
+ * mat contains the wrapping constraints
+ * max is the bound on the coefficients (if bound is set)
+ */
+struct isl_wraps {
+ int bound;
+ isl_mat *mat;
+ isl_int max;
+};
+
+/* Update wraps->max to be greater than or equal to the coefficients
+ * in the equalities and inequalities of bmap that can be removed if we end up
+ * applying wrapping.
+ */
+static void wraps_update_max(struct isl_wraps *wraps,
+ __isl_keep isl_basic_map *bmap, int *eq, int *ineq)
+{
+ int k;
+ isl_int max_k;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ isl_int_init(max_k);
+
+ for (k = 0; k < bmap->n_eq; ++k) {
+ if (eq[2 * k] == STATUS_VALID &&
+ eq[2 * k + 1] == STATUS_VALID)
+ continue;
+ isl_seq_abs_max(bmap->eq[k] + 1, total, &max_k);
+ if (isl_int_abs_gt(max_k, wraps->max))
+ isl_int_set(wraps->max, max_k);
+ }
+
+ for (k = 0; k < bmap->n_ineq; ++k) {
+ if (ineq[k] == STATUS_VALID || ineq[k] == STATUS_REDUNDANT)
+ continue;
+ isl_seq_abs_max(bmap->ineq[k] + 1, total, &max_k);
+ if (isl_int_abs_gt(max_k, wraps->max))
+ isl_int_set(wraps->max, max_k);
+ }
+
+ isl_int_clear(max_k);
+}
+
+/* Initialize the isl_wraps data structure.
+ * If we want to bound the coefficients of the wrapping constraints,
+ * we set wraps->max to the largest coefficient
+ * in the equalities and inequalities that can be removed if we end up
+ * applying wrapping.
+ */
+static void wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat,
+ __isl_keep isl_map *map, int i, int j,
+ int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ isl_ctx *ctx;
+
+ wraps->bound = 0;
+ wraps->mat = mat;
+ if (!mat)
+ return;
+ ctx = isl_mat_get_ctx(mat);
+ wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx);
+ if (!wraps->bound)
+ return;
+ isl_int_init(wraps->max);
+ isl_int_set_si(wraps->max, 0);
+ wraps_update_max(wraps, map->p[i], eq_i, ineq_i);
+ wraps_update_max(wraps, map->p[j], eq_j, ineq_j);
+}
+
+/* Free the contents of the isl_wraps data structure.
+ */
+static void wraps_free(struct isl_wraps *wraps)
+{
+ isl_mat_free(wraps->mat);
+ if (wraps->bound)
+ isl_int_clear(wraps->max);
+}
+
+/* Is the wrapping constraint in row "row" allowed?
+ *
+ * If wraps->bound is set, we check that none of the coefficients
+ * is greater than wraps->max.
+ */
+static int allow_wrap(struct isl_wraps *wraps, int row)
+{
+ int i;
+
+ if (!wraps->bound)
+ return 1;
+
+ for (i = 1; i < wraps->mat->n_col; ++i)
+ if (isl_int_abs_gt(wraps->mat->row[row][i], wraps->max))
+ return 0;
+
+ return 1;
+}
+
+/* For each non-redundant constraint in "bmap" (as determined by "tab"),
+ * wrap the constraint around "bound" such that it includes the whole
+ * set "set" and append the resulting constraint to "wraps".
+ * "wraps" is assumed to have been pre-allocated to the appropriate size.
+ * wraps->n_row is the number of actual wrapped constraints that have
+ * been added.
+ * If any of the wrapping problems results in a constraint that is
+ * identical to "bound", then this means that "set" is unbounded in such
+ * way that no wrapping is possible. If this happens then wraps->n_row
+ * is reset to zero.
+ * Similarly, if we want to bound the coefficients of the wrapping
+ * constraints and a newly added wrapping constraint does not
+ * satisfy the bound, then wraps->n_row is also reset to zero.
+ */
+static int add_wraps(struct isl_wraps *wraps, __isl_keep isl_basic_map *bmap,
+ struct isl_tab *tab, isl_int *bound, __isl_keep isl_set *set)
+{
+ int l;
+ int w;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ w = wraps->mat->n_row;
+
+ for (l = 0; l < bmap->n_ineq; ++l) {
+ if (isl_seq_is_neg(bound, bmap->ineq[l], 1 + total))
+ continue;
+ if (isl_seq_eq(bound, bmap->ineq[l], 1 + total))
+ continue;
+ if (isl_tab_is_redundant(tab, bmap->n_eq + l))
+ continue;
+
+ isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+ if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->ineq[l]))
+ return -1;
+ if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+ goto unbounded;
+ if (!allow_wrap(wraps, w))
+ goto unbounded;
+ ++w;
+ }
+ for (l = 0; l < bmap->n_eq; ++l) {
+ if (isl_seq_is_neg(bound, bmap->eq[l], 1 + total))
+ continue;
+ if (isl_seq_eq(bound, bmap->eq[l], 1 + total))
+ continue;
+
+ isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+ isl_seq_neg(wraps->mat->row[w + 1], bmap->eq[l], 1 + total);
+ if (!isl_set_wrap_facet(set, wraps->mat->row[w],
+ wraps->mat->row[w + 1]))
+ return -1;
+ if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+ goto unbounded;
+ if (!allow_wrap(wraps, w))
+ goto unbounded;
+ ++w;
+
+ isl_seq_cpy(wraps->mat->row[w], bound, 1 + total);
+ if (!isl_set_wrap_facet(set, wraps->mat->row[w], bmap->eq[l]))
+ return -1;
+ if (isl_seq_eq(wraps->mat->row[w], bound, 1 + total))
+ goto unbounded;
+ if (!allow_wrap(wraps, w))
+ goto unbounded;
+ ++w;
+ }
+
+ wraps->mat->n_row = w;
+ return 0;
+unbounded:
+ wraps->mat->n_row = 0;
+ return 0;
+}
+
+/* Check if the constraints in "wraps" from "first" until the last
+ * are all valid for the basic set represented by "tab".
+ * If not, wraps->n_row is set to zero.
+ */
+static int check_wraps(__isl_keep isl_mat *wraps, int first,
+ struct isl_tab *tab)
+{
+ int i;
+
+ for (i = first; i < wraps->n_row; ++i) {
+ enum isl_ineq_type type;
+ type = isl_tab_ineq_type(tab, wraps->row[i]);
+ if (type == isl_ineq_error)
+ return -1;
+ if (type == isl_ineq_redundant)
+ continue;
+ wraps->n_row = 0;
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Return a set that corresponds to the non-redudant constraints
+ * (as recorded in tab) of bmap.
+ *
+ * It's important to remove the redundant constraints as some
+ * of the other constraints may have been modified after the
+ * constraints were marked redundant.
+ * In particular, a constraint may have been relaxed.
+ * Redundant constraints are ignored when a constraint is relaxed
+ * and should therefore continue to be ignored ever after.
+ * Otherwise, the relaxation might be thwarted by some of
+ * these constraints.
+ */
+static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap,
+ struct isl_tab *tab)
+{
+ bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_update_from_tab(bmap, tab);
+ return isl_set_from_basic_set(isl_basic_map_underlying_set(bmap));
+}
+
+/* Given a basic set i with a constraint k that is adjacent to either the
+ * whole of basic set j or a facet of basic set j, check if we can wrap
+ * both the facet corresponding to k and the facet of j (or the whole of j)
+ * around their ridges to include the other set.
+ * If so, replace the pair of basic sets by their union.
+ *
+ * All constraints of i (except k) are assumed to be valid for j.
+ *
+ * However, the constraints of j may not be valid for i and so
+ * we have to check that the wrapping constraints for j are valid for i.
+ *
+ * In the case where j has a facet adjacent to i, tab[j] is assumed
+ * to have been restricted to this facet, so that the non-redundant
+ * constraints in tab[j] are the ridges of the facet.
+ * Note that for the purpose of wrapping, it does not matter whether
+ * we wrap the ridges of i around the whole of j or just around
+ * the facet since all the other constraints are assumed to be valid for j.
+ * In practice, we wrap to include the whole of j.
+ * ____ _____
+ * / | / \
+ * / || / |
+ * \ || => \ |
+ * \ || \ |
+ * \___|| \____|
+ *
+ */
+static int can_wrap_in_facet(struct isl_map *map, int i, int j, int k,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+ struct isl_wraps wraps;
+ isl_mat *mat;
+ struct isl_set *set_i = NULL;
+ struct isl_set *set_j = NULL;
+ struct isl_vec *bound = NULL;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+ struct isl_tab_undo *snap;
+ int n;
+
+ set_i = set_from_updated_bmap(map->p[i], tabs[i]);
+ set_j = set_from_updated_bmap(map->p[j], tabs[j]);
+ mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+ map->p[i]->n_ineq + map->p[j]->n_ineq,
+ 1 + total);
+ wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+ bound = isl_vec_alloc(map->ctx, 1 + total);
+ if (!set_i || !set_j || !wraps.mat || !bound)
+ goto error;
+
+ isl_seq_cpy(bound->el, map->p[i]->ineq[k], 1 + total);
+ isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+ isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+ wraps.mat->n_row = 1;
+
+ if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0)
+ goto error;
+ if (!wraps.mat->n_row)
+ goto unbounded;
+
+ snap = isl_tab_snap(tabs[i]);
+
+ if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + k) < 0)
+ goto error;
+ if (isl_tab_detect_redundant(tabs[i]) < 0)
+ goto error;
+
+ isl_seq_neg(bound->el, map->p[i]->ineq[k], 1 + total);
+
+ n = wraps.mat->n_row;
+ if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0)
+ goto error;
+
+ if (isl_tab_rollback(tabs[i], snap) < 0)
+ goto error;
+ if (check_wraps(wraps.mat, n, tabs[i]) < 0)
+ goto error;
+ if (!wraps.mat->n_row)
+ goto unbounded;
+
+ changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+unbounded:
+ wraps_free(&wraps);
+
+ isl_set_free(set_i);
+ isl_set_free(set_j);
+
+ isl_vec_free(bound);
+
+ return changed;
+error:
+ wraps_free(&wraps);
+ isl_vec_free(bound);
+ isl_set_free(set_i);
+ isl_set_free(set_j);
+ return -1;
+}
+
+/* Set the is_redundant property of the "n" constraints in "cuts",
+ * except "k" to "v".
+ * This is a fairly tricky operation as it bypasses isl_tab.c.
+ * The reason we want to temporarily mark some constraints redundant
+ * is that we want to ignore them in add_wraps.
+ *
+ * Initially all cut constraints are non-redundant, but the
+ * selection of a facet right before the call to this function
+ * may have made some of them redundant.
+ * Likewise, the same constraints are marked non-redundant
+ * in the second call to this function, before they are officially
+ * made non-redundant again in the subsequent rollback.
+ */
+static void set_is_redundant(struct isl_tab *tab, unsigned n_eq,
+ int *cuts, int n, int k, int v)
+{
+ int l;
+
+ for (l = 0; l < n; ++l) {
+ if (l == k)
+ continue;
+ tab->con[n_eq + cuts[l]].is_redundant = v;
+ }
+}
+
+/* Given a pair of basic maps i and j such that j sticks out
+ * of i at n cut constraints, each time by at most one,
+ * try to compute wrapping constraints and replace the two
+ * basic maps by a single basic map.
+ * The other constraints of i are assumed to be valid for j.
+ *
+ * The facets of i corresponding to the cut constraints are
+ * wrapped around their ridges, except those ridges determined
+ * by any of the other cut constraints.
+ * The intersections of cut constraints need to be ignored
+ * as the result of wrapping one cut constraint around another
+ * would result in a constraint cutting the union.
+ * In each case, the facets are wrapped to include the union
+ * of the two basic maps.
+ *
+ * The pieces of j that lie at an offset of exactly one from
+ * one of the cut constraints of i are wrapped around their edges.
+ * Here, there is no need to ignore intersections because we
+ * are wrapping around the union of the two basic maps.
+ *
+ * If any wrapping fails, i.e., if we cannot wrap to touch
+ * the union, then we give up.
+ * Otherwise, the pair of basic maps is replaced by their union.
+ */
+static int wrap_in_facets(struct isl_map *map, int i, int j,
+ int *cuts, int n, struct isl_tab **tabs,
+ int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+ struct isl_wraps wraps;
+ isl_mat *mat;
+ isl_set *set = NULL;
+ isl_vec *bound = NULL;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+ int max_wrap;
+ int k;
+ struct isl_tab_undo *snap_i, *snap_j;
+
+ if (isl_tab_extend_cons(tabs[j], 1) < 0)
+ goto error;
+
+ max_wrap = 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+ map->p[i]->n_ineq + map->p[j]->n_ineq;
+ max_wrap *= n;
+
+ set = isl_set_union(set_from_updated_bmap(map->p[i], tabs[i]),
+ set_from_updated_bmap(map->p[j], tabs[j]));
+ mat = isl_mat_alloc(map->ctx, max_wrap, 1 + total);
+ wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+ bound = isl_vec_alloc(map->ctx, 1 + total);
+ if (!set || !wraps.mat || !bound)
+ goto error;
+
+ snap_i = isl_tab_snap(tabs[i]);
+ snap_j = isl_tab_snap(tabs[j]);
+
+ wraps.mat->n_row = 0;
+
+ for (k = 0; k < n; ++k) {
+ if (isl_tab_select_facet(tabs[i], map->p[i]->n_eq + cuts[k]) < 0)
+ goto error;
+ if (isl_tab_detect_redundant(tabs[i]) < 0)
+ goto error;
+ set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 1);
+
+ isl_seq_neg(bound->el, map->p[i]->ineq[cuts[k]], 1 + total);
+ if (!tabs[i]->empty &&
+ add_wraps(&wraps, map->p[i], tabs[i], bound->el, set) < 0)
+ goto error;
+
+ set_is_redundant(tabs[i], map->p[i]->n_eq, cuts, n, k, 0);
+ if (isl_tab_rollback(tabs[i], snap_i) < 0)
+ goto error;
+
+ if (tabs[i]->empty)
+ break;
+ if (!wraps.mat->n_row)
+ break;
+
+ isl_seq_cpy(bound->el, map->p[i]->ineq[cuts[k]], 1 + total);
+ isl_int_add_ui(bound->el[0], bound->el[0], 1);
+ if (isl_tab_add_eq(tabs[j], bound->el) < 0)
+ goto error;
+ if (isl_tab_detect_redundant(tabs[j]) < 0)
+ goto error;
+
+ if (!tabs[j]->empty &&
+ add_wraps(&wraps, map->p[j], tabs[j], bound->el, set) < 0)
+ goto error;
+
+ if (isl_tab_rollback(tabs[j], snap_j) < 0)
+ goto error;
+
+ if (!wraps.mat->n_row)
+ break;
+ }
+
+ if (k == n)
+ changed = fuse(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+ isl_vec_free(bound);
+ wraps_free(&wraps);
+ isl_set_free(set);
+
+ return changed;
+error:
+ isl_vec_free(bound);
+ wraps_free(&wraps);
+ isl_set_free(set);
+ return -1;
+}
+
+/* Given two basic sets i and j such that i has no cut equalities,
+ * check if relaxing all the cut inequalities of i by one turns
+ * them into valid constraint for j and check if we can wrap in
+ * the bits that are sticking out.
+ * If so, replace the pair by their union.
+ *
+ * We first check if all relaxed cut inequalities of i are valid for j
+ * and then try to wrap in the intersections of the relaxed cut inequalities
+ * with j.
+ *
+ * During this wrapping, we consider the points of j that lie at a distance
+ * of exactly 1 from i. In particular, we ignore the points that lie in
+ * between this lower-dimensional space and the basic map i.
+ * We can therefore only apply this to integer maps.
+ * ____ _____
+ * / ___|_ / \
+ * / | | / |
+ * \ | | => \ |
+ * \|____| \ |
+ * \___| \____/
+ *
+ * _____ ______
+ * | ____|_ | \
+ * | | | | |
+ * | | | => | |
+ * |_| | | |
+ * |_____| \______|
+ *
+ * _______
+ * | |
+ * | |\ |
+ * | | \ |
+ * | | \ |
+ * | | \|
+ * | | \
+ * | |_____\
+ * | |
+ * |_______|
+ *
+ * Wrapping can fail if the result of wrapping one of the facets
+ * around its edges does not produce any new facet constraint.
+ * In particular, this happens when we try to wrap in unbounded sets.
+ *
+ * _______________________________________________________________________
+ * |
+ * | ___
+ * | | |
+ * |_| |_________________________________________________________________
+ * |___|
+ *
+ * The following is not an acceptable result of coalescing the above two
+ * sets as it includes extra integer points.
+ * _______________________________________________________________________
+ * |
+ * |
+ * |
+ * |
+ * \______________________________________________________________________
+ */
+static int can_wrap_in_set(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+ int k, m;
+ int n;
+ int *cuts = NULL;
+
+ if (ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_RATIONAL) ||
+ ISL_F_ISSET(map->p[j], ISL_BASIC_MAP_RATIONAL))
+ return 0;
+
+ n = count(ineq_i, map->p[i]->n_ineq, STATUS_CUT);
+ if (n == 0)
+ return 0;
+
+ cuts = isl_alloc_array(map->ctx, int, n);
+ if (!cuts)
+ return -1;
+
+ for (k = 0, m = 0; m < n; ++k) {
+ enum isl_ineq_type type;
+
+ if (ineq_i[k] != STATUS_CUT)
+ continue;
+
+ isl_int_add_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ type = isl_tab_ineq_type(tabs[j], map->p[i]->ineq[k]);
+ isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ if (type == isl_ineq_error)
+ goto error;
+ if (type != isl_ineq_redundant)
+ break;
+ cuts[m] = k;
+ ++m;
+ }
+
+ if (m == n)
+ changed = wrap_in_facets(map, i, j, cuts, n, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+
+ free(cuts);
+
+ return changed;
+error:
+ free(cuts);
+ return -1;
+}
+
+/* Check if either i or j has a single cut constraint that can
+ * be used to wrap in (a facet of) the other basic set.
+ * if so, replace the pair by their union.
+ */
+static int check_wrap(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+
+ if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT))
+ changed = can_wrap_in_set(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ if (changed)
+ return changed;
+
+ if (!any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
+ changed = can_wrap_in_set(map, j, i, tabs,
+ eq_j, ineq_j, eq_i, ineq_i);
+ return changed;
+}
+
+/* At least one of the basic maps has an equality that is adjacent
+ * to inequality. Make sure that only one of the basic maps has
+ * such an equality and that the other basic map has exactly one
+ * inequality adjacent to an equality.
+ * We call the basic map that has the inequality "i" and the basic
+ * map that has the equality "j".
+ * If "i" has any "cut" (in)equality, then relaxing the inequality
+ * by one would not result in a basic map that contains the other
+ * basic map.
+ */
+static int check_adj_eq(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int changed = 0;
+ int k;
+
+ if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) &&
+ any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ))
+ /* ADJ EQ TOO MANY */
+ return 0;
+
+ if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ))
+ return check_adj_eq(map, j, i, tabs,
+ eq_j, ineq_j, eq_i, ineq_i);
+
+ /* j has an equality adjacent to an inequality in i */
+
+ if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT))
+ return 0;
+ if (any(ineq_i, map->p[i]->n_ineq, STATUS_CUT))
+ /* ADJ EQ CUT */
+ return 0;
+ if (count(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) != 1 ||
+ any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ) ||
+ any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) ||
+ any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ))
+ /* ADJ EQ TOO MANY */
+ return 0;
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k)
+ if (ineq_i[k] == STATUS_ADJ_EQ)
+ break;
+
+ changed = is_adj_eq_extension(map, i, j, k, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ if (changed)
+ return changed;
+
+ if (count(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ) != 1)
+ return 0;
+
+ changed = can_wrap_in_facet(map, i, j, k, tabs, eq_i, ineq_i, eq_j, ineq_j);
+
+ return changed;
+}
+
+/* The two basic maps lie on adjacent hyperplanes. In particular,
+ * basic map "i" has an equality that lies parallel to basic map "j".
+ * Check if we can wrap the facets around the parallel hyperplanes
+ * to include the other set.
+ *
+ * We perform basically the same operations as can_wrap_in_facet,
+ * except that we don't need to select a facet of one of the sets.
+ * _
+ * \\ \\
+ * \\ => \\
+ * \ \|
+ *
+ * We only allow one equality of "i" to be adjacent to an equality of "j"
+ * to avoid coalescing
+ *
+ * [m, n] -> { [x, y] -> [x, 1 + y] : x >= 1 and y >= 1 and
+ * x <= 10 and y <= 10;
+ * [x, y] -> [1 + x, y] : x >= 1 and x <= 20 and
+ * y >= 5 and y <= 15 }
+ *
+ * to
+ *
+ * [m, n] -> { [x, y] -> [x2, y2] : x >= 1 and 10y2 <= 20 - x + 10y and
+ * 4y2 >= 5 + 3y and 5y2 <= 15 + 4y and
+ * y2 <= 1 + x + y - x2 and y2 >= y and
+ * y2 >= 1 + x + y - x2 }
+ */
+static int check_eq_adj_eq(struct isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int k;
+ int changed = 0;
+ struct isl_wraps wraps;
+ isl_mat *mat;
+ struct isl_set *set_i = NULL;
+ struct isl_set *set_j = NULL;
+ struct isl_vec *bound = NULL;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+
+ if (count(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ) != 1)
+ return 0;
+
+ for (k = 0; k < 2 * map->p[i]->n_eq ; ++k)
+ if (eq_i[k] == STATUS_ADJ_EQ)
+ break;
+
+ set_i = set_from_updated_bmap(map->p[i], tabs[i]);
+ set_j = set_from_updated_bmap(map->p[j], tabs[j]);
+ mat = isl_mat_alloc(map->ctx, 2 * (map->p[i]->n_eq + map->p[j]->n_eq) +
+ map->p[i]->n_ineq + map->p[j]->n_ineq,
+ 1 + total);
+ wraps_init(&wraps, mat, map, i, j, eq_i, ineq_i, eq_j, ineq_j);
+ bound = isl_vec_alloc(map->ctx, 1 + total);
+ if (!set_i || !set_j || !wraps.mat || !bound)
+ goto error;
+
+ if (k % 2 == 0)
+ isl_seq_neg(bound->el, map->p[i]->eq[k / 2], 1 + total);
+ else
+ isl_seq_cpy(bound->el, map->p[i]->eq[k / 2], 1 + total);
+ isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+ isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+ wraps.mat->n_row = 1;
+
+ if (add_wraps(&wraps, map->p[j], tabs[j], bound->el, set_i) < 0)
+ goto error;
+ if (!wraps.mat->n_row)
+ goto unbounded;
+
+ isl_int_sub_ui(bound->el[0], bound->el[0], 1);
+ isl_seq_neg(bound->el, bound->el, 1 + total);
+
+ isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total);
+ wraps.mat->n_row++;
+
+ if (add_wraps(&wraps, map->p[i], tabs[i], bound->el, set_j) < 0)
+ goto error;
+ if (!wraps.mat->n_row)
+ goto unbounded;
+
+ changed = fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, wraps.mat);
+
+ if (0) {
+error: changed = -1;
+ }
+unbounded:
+
+ wraps_free(&wraps);
+ isl_set_free(set_i);
+ isl_set_free(set_j);
+ isl_vec_free(bound);
+
+ return changed;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return 1.
+ * Otherwise, return 0;
+ * The two basic maps are assumed to live in the same local space.
+ *
+ * We first check the effect of each constraint of one basic map
+ * on the other basic map.
+ * The constraint may be
+ * redundant the constraint is redundant in its own
+ * basic map and should be ignore and removed
+ * in the end
+ * valid all (integer) points of the other basic map
+ * satisfy the constraint
+ * separate no (integer) point of the other basic map
+ * satisfies the constraint
+ * cut some but not all points of the other basic map
+ * satisfy the constraint
+ * adj_eq the given constraint is adjacent (on the outside)
+ * to an equality of the other basic map
+ * adj_ineq the given constraint is adjacent (on the outside)
+ * to an inequality of the other basic map
+ *
+ * We consider seven cases in which we can replace the pair by a single
+ * basic map. We ignore all "redundant" constraints.
+ *
+ * 1. all constraints of one basic map are valid
+ * => the other basic map is a subset and can be removed
+ *
+ * 2. all constraints of both basic maps are either "valid" or "cut"
+ * and the facets corresponding to the "cut" constraints
+ * of one of the basic maps lies entirely inside the other basic map
+ * => the pair can be replaced by a basic map consisting
+ * of the valid constraints in both basic maps
+ *
+ * 3. there is a single pair of adjacent inequalities
+ * (all other constraints are "valid")
+ * => the pair can be replaced by a basic map consisting
+ * of the valid constraints in both basic maps
+ *
+ * 4. one basic map has a single adjacent inequality, while the other
+ * constraints are "valid". The other basic map has some
+ * "cut" constraints, but replacing the adjacent inequality by
+ * its opposite and adding the valid constraints of the other
+ * basic map results in a subset of the other basic map
+ * => the pair can be replaced by a basic map consisting
+ * of the valid constraints in both basic maps
+ *
+ * 5. there is a single adjacent pair of an inequality and an equality,
+ * the other constraints of the basic map containing the inequality are
+ * "valid". Moreover, if the inequality the basic map is relaxed
+ * and then turned into an equality, then resulting facet lies
+ * entirely inside the other basic map
+ * => the pair can be replaced by the basic map containing
+ * the inequality, with the inequality relaxed.
+ *
+ * 6. there is a single adjacent pair of an inequality and an equality,
+ * the other constraints of the basic map containing the inequality are
+ * "valid". Moreover, the facets corresponding to both
+ * the inequality and the equality can be wrapped around their
+ * ridges to include the other basic map
+ * => the pair can be replaced by a basic map consisting
+ * of the valid constraints in both basic maps together
+ * with all wrapping constraints
+ *
+ * 7. one of the basic maps extends beyond the other by at most one.
+ * Moreover, the facets corresponding to the cut constraints and
+ * the pieces of the other basic map at offset one from these cut
+ * constraints can be wrapped around their ridges to include
+ * the union of the two basic maps
+ * => the pair can be replaced by a basic map consisting
+ * of the valid constraints in both basic maps together
+ * with all wrapping constraints
+ *
+ * 8. the two basic maps live in adjacent hyperplanes. In principle
+ * such sets can always be combined through wrapping, but we impose
+ * that there is only one such pair, to avoid overeager coalescing.
+ *
+ * Throughout the computation, we maintain a collection of tableaus
+ * corresponding to the basic maps. When the basic maps are dropped
+ * or combined, the tableaus are modified accordingly.
+ */
+static int coalesce_local_pair(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs)
+{
+ int changed = 0;
+ int *eq_i = NULL;
+ int *eq_j = NULL;
+ int *ineq_i = NULL;
+ int *ineq_j = NULL;
+
+ eq_i = eq_status_in(map->p[i], tabs[j]);
+ if (map->p[i]->n_eq && !eq_i)
+ goto error;
+ if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ERROR))
+ goto error;
+ if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_SEPARATE))
+ goto done;
+
+ eq_j = eq_status_in(map->p[j], tabs[i]);
+ if (map->p[j]->n_eq && !eq_j)
+ goto error;
+ if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ERROR))
+ goto error;
+ if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_SEPARATE))
+ goto done;
+
+ ineq_i = ineq_status_in(map->p[i], tabs[i], tabs[j]);
+ if (map->p[i]->n_ineq && !ineq_i)
+ goto error;
+ if (any(ineq_i, map->p[i]->n_ineq, STATUS_ERROR))
+ goto error;
+ if (any(ineq_i, map->p[i]->n_ineq, STATUS_SEPARATE))
+ goto done;
+
+ ineq_j = ineq_status_in(map->p[j], tabs[j], tabs[i]);
+ if (map->p[j]->n_ineq && !ineq_j)
+ goto error;
+ if (any(ineq_j, map->p[j]->n_ineq, STATUS_ERROR))
+ goto error;
+ if (any(ineq_j, map->p[j]->n_ineq, STATUS_SEPARATE))
+ goto done;
+
+ if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) &&
+ all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) {
+ drop(map, j, tabs);
+ changed = 1;
+ } else if (all(eq_j, 2 * map->p[j]->n_eq, STATUS_VALID) &&
+ all(ineq_j, map->p[j]->n_ineq, STATUS_VALID)) {
+ drop(map, i, tabs);
+ changed = 1;
+ } else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_EQ)) {
+ changed = check_eq_adj_eq(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ } else if (any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_EQ)) {
+ changed = check_eq_adj_eq(map, j, i, tabs,
+ eq_j, ineq_j, eq_i, ineq_i);
+ } else if (any(eq_i, 2 * map->p[i]->n_eq, STATUS_ADJ_INEQ) ||
+ any(eq_j, 2 * map->p[j]->n_eq, STATUS_ADJ_INEQ)) {
+ changed = check_adj_eq(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ } else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_EQ) ||
+ any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_EQ)) {
+ /* Can't happen */
+ /* BAD ADJ INEQ */
+ } else if (any(ineq_i, map->p[i]->n_ineq, STATUS_ADJ_INEQ) ||
+ any(ineq_j, map->p[j]->n_ineq, STATUS_ADJ_INEQ)) {
+ changed = check_adj_ineq(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ } else {
+ if (!any(eq_i, 2 * map->p[i]->n_eq, STATUS_CUT) &&
+ !any(eq_j, 2 * map->p[j]->n_eq, STATUS_CUT))
+ changed = check_facets(map, i, j, tabs, ineq_i, ineq_j);
+ if (!changed)
+ changed = check_wrap(map, i, j, tabs,
+ eq_i, ineq_i, eq_j, ineq_j);
+ }
+
+done:
+ free(eq_i);
+ free(eq_j);
+ free(ineq_i);
+ free(ineq_j);
+ return changed;
+error:
+ free(eq_i);
+ free(eq_j);
+ free(ineq_i);
+ free(ineq_j);
+ return -1;
+}
+
+/* Do the two basic maps live in the same local space, i.e.,
+ * do they have the same (known) divs?
+ * If either basic map has any unknown divs, then we can only assume
+ * that they do not live in the same local space.
+ */
+static int same_divs(__isl_keep isl_basic_map *bmap1,
+ __isl_keep isl_basic_map *bmap2)
+{
+ int i;
+ int known;
+ int total;
+
+ if (!bmap1 || !bmap2)
+ return -1;
+ if (bmap1->n_div != bmap2->n_div)
+ return 0;
+
+ if (bmap1->n_div == 0)
+ return 1;
+
+ known = isl_basic_map_divs_known(bmap1);
+ if (known < 0 || !known)
+ return known;
+ known = isl_basic_map_divs_known(bmap2);
+ if (known < 0 || !known)
+ return known;
+
+ total = isl_basic_map_total_dim(bmap1);
+ for (i = 0; i < bmap1->n_div; ++i)
+ if (!isl_seq_eq(bmap1->div[i], bmap2->div[i], 2 + total))
+ return 0;
+
+ return 1;
+}
+
+/* Given two basic maps "i" and "j", where the divs of "i" form a subset
+ * of those of "j", check if basic map "j" is a subset of basic map "i"
+ * and, if so, drop basic map "j".
+ *
+ * We first expand the divs of basic map "i" to match those of basic map "j",
+ * using the divs and expansion computed by the caller.
+ * Then we check if all constraints of the expanded "i" are valid for "j".
+ */
+static int coalesce_subset(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs, __isl_keep isl_mat *div, int *exp)
+{
+ isl_basic_map *bmap;
+ int changed = 0;
+ int *eq_i = NULL;
+ int *ineq_i = NULL;
+
+ bmap = isl_basic_map_copy(map->p[i]);
+ bmap = isl_basic_set_expand_divs(bmap, isl_mat_copy(div), exp);
+
+ if (!bmap)
+ goto error;
+
+ eq_i = eq_status_in(bmap, tabs[j]);
+ if (bmap->n_eq && !eq_i)
+ goto error;
+ if (any(eq_i, 2 * bmap->n_eq, STATUS_ERROR))
+ goto error;
+ if (any(eq_i, 2 * bmap->n_eq, STATUS_SEPARATE))
+ goto done;
+
+ ineq_i = ineq_status_in(bmap, NULL, tabs[j]);
+ if (bmap->n_ineq && !ineq_i)
+ goto error;
+ if (any(ineq_i, bmap->n_ineq, STATUS_ERROR))
+ goto error;
+ if (any(ineq_i, bmap->n_ineq, STATUS_SEPARATE))
+ goto done;
+
+ if (all(eq_i, 2 * map->p[i]->n_eq, STATUS_VALID) &&
+ all(ineq_i, map->p[i]->n_ineq, STATUS_VALID)) {
+ drop(map, j, tabs);
+ changed = 1;
+ }
+
+done:
+ isl_basic_map_free(bmap);
+ free(eq_i);
+ free(ineq_i);
+ return 0;
+error:
+ isl_basic_map_free(bmap);
+ free(eq_i);
+ free(ineq_i);
+ return -1;
+}
+
+/* Check if the basic map "j" is a subset of basic map "i",
+ * assuming that "i" has fewer divs that "j".
+ * If not, then we change the order.
+ *
+ * If the two basic maps have the same number of divs, then
+ * they must necessarily be different. Otherwise, we would have
+ * called coalesce_local_pair. We therefore don't try anything
+ * in this case.
+ *
+ * We first check if the divs of "i" are all known and form a subset
+ * of those of "j". If so, we pass control over to coalesce_subset.
+ */
+static int check_coalesce_subset(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs)
+{
+ int known;
+ isl_mat *div_i, *div_j, *div;
+ int *exp1 = NULL;
+ int *exp2 = NULL;
+ isl_ctx *ctx;
+ int subset;
+
+ if (map->p[i]->n_div == map->p[j]->n_div)
+ return 0;
+ if (map->p[j]->n_div < map->p[i]->n_div)
+ return check_coalesce_subset(map, j, i, tabs);
+
+ known = isl_basic_map_divs_known(map->p[i]);
+ if (known < 0 || !known)
+ return known;
+
+ ctx = isl_map_get_ctx(map);
+
+ div_i = isl_basic_map_get_divs(map->p[i]);
+ div_j = isl_basic_map_get_divs(map->p[j]);
+
+ if (!div_i || !div_j)
+ goto error;
+
+ exp1 = isl_alloc_array(ctx, int, div_i->n_row);
+ exp2 = isl_alloc_array(ctx, int, div_j->n_row);
+ if ((div_i->n_row && !exp1) || (div_j->n_row && !exp2))
+ goto error;
+
+ div = isl_merge_divs(div_i, div_j, exp1, exp2);
+ if (!div)
+ goto error;
+
+ if (div->n_row == div_j->n_row)
+ subset = coalesce_subset(map, i, j, tabs, div, exp1);
+ else
+ subset = 0;
+
+ isl_mat_free(div);
+
+ isl_mat_free(div_i);
+ isl_mat_free(div_j);
+
+ free(exp2);
+ free(exp1);
+
+ return subset;
+error:
+ isl_mat_free(div_i);
+ isl_mat_free(div_j);
+ free(exp1);
+ free(exp2);
+ return -1;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return 1.
+ * Otherwise, return 0;
+ *
+ * We first check if the two basic maps live in the same local space.
+ * If so, we do the complete check. Otherwise, we check if one is
+ * an obvious subset of the other.
+ */
+static int coalesce_pair(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs)
+{
+ int same;
+
+ same = same_divs(map->p[i], map->p[j]);
+ if (same < 0)
+ return -1;
+ if (same)
+ return coalesce_local_pair(map, i, j, tabs);
+
+ return check_coalesce_subset(map, i, j, tabs);
+}
+
+static struct isl_map *coalesce(struct isl_map *map, struct isl_tab **tabs)
+{
+ int i, j;
+
+ for (i = map->n - 2; i >= 0; --i)
+restart:
+ for (j = i + 1; j < map->n; ++j) {
+ int changed;
+ changed = coalesce_pair(map, i, j, tabs);
+ if (changed < 0)
+ goto error;
+ if (changed)
+ goto restart;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* For each pair of basic maps in the map, check if the union of the two
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and start over.
+ *
+ * Since we are constructing the tableaus of the basic maps anyway,
+ * we exploit them to detect implicit equalities and redundant constraints.
+ * This also helps the coalescing as it can ignore the redundant constraints.
+ * In order to avoid confusion, we make all implicit equalities explicit
+ * in the basic maps. We don't call isl_basic_map_gauss, though,
+ * as that may affect the number of constraints.
+ * This means that we have to call isl_basic_map_gauss at the end
+ * of the computation to ensure that the basic maps are not left
+ * in an unexpected state.
+ */
+struct isl_map *isl_map_coalesce(struct isl_map *map)
+{
+ int i;
+ unsigned n;
+ struct isl_tab **tabs = NULL;
+
+ map = isl_map_remove_empty_parts(map);
+ if (!map)
+ return NULL;
+
+ if (map->n <= 1)
+ return map;
+
+ map = isl_map_sort_divs(map);
+ map = isl_map_cow(map);
+
+ if (!map)
+ return NULL;
+
+ tabs = isl_calloc_array(map->ctx, struct isl_tab *, map->n);
+ if (!tabs)
+ goto error;
+
+ n = map->n;
+ for (i = 0; i < map->n; ++i) {
+ tabs[i] = isl_tab_from_basic_map(map->p[i], 0);
+ if (!tabs[i])
+ goto error;
+ if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT))
+ if (isl_tab_detect_implicit_equalities(tabs[i]) < 0)
+ goto error;
+ map->p[i] = isl_tab_make_equalities_explicit(tabs[i],
+ map->p[i]);
+ if (!map->p[i])
+ goto error;
+ if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT))
+ if (isl_tab_detect_redundant(tabs[i]) < 0)
+ goto error;
+ }
+ for (i = map->n - 1; i >= 0; --i)
+ if (tabs[i]->empty)
+ drop(map, i, tabs);
+
+ map = coalesce(map, tabs);
+
+ if (map)
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_update_from_tab(map->p[i],
+ tabs[i]);
+ map->p[i] = isl_basic_map_gauss(map->p[i], NULL);
+ map->p[i] = isl_basic_map_finalize(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_SET(map->p[i], ISL_BASIC_MAP_NO_REDUNDANT);
+ }
+
+ for (i = 0; i < n; ++i)
+ isl_tab_free(tabs[i]);
+
+ free(tabs);
+
+ return map;
+error:
+ if (tabs)
+ for (i = 0; i < n; ++i)
+ isl_tab_free(tabs[i]);
+ free(tabs);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* For each pair of basic sets in the set, check if the union of the two
+ * can be represented by a single basic set.
+ * If so, replace the pair by the single basic set and start over.
+ */
+struct isl_set *isl_set_coalesce(struct isl_set *set)
+{
+ return (struct isl_set *)isl_map_coalesce((struct isl_map *)set);
+}
Added: polly/trunk/lib/External/isl/isl_config.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_config.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_config.h (added)
+++ polly/trunk/lib/External/isl/isl_config.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,169 @@
+/* isl_config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if HeaderSearchOptions::AddPath takes 4 arguments */
+#undef ADDPATH_TAKES_4_ARGUMENTS
+
+/* Clang installation prefix */
+#undef CLANG_PREFIX
+
+/* Define if CompilerInstance::createDiagnostics takes argc and argv */
+#undef CREATEDIAGNOSTICS_TAKES_ARG
+
+/* Define if CompilerInstance::createPreprocessor takes TranslationUnitKind */
+#undef CREATEPREPROCESSOR_TAKES_TUKIND
+
+/* Define if TargetInfo::CreateTargetInfo takes pointer */
+#undef CREATETARGETINFO_TAKES_POINTER
+
+/* Define if TargetInfo::CreateTargetInfo takes shared_ptr */
+#undef CREATETARGETINFO_TAKES_SHARED_PTR
+
+/* Define if Driver constructor takes default image name */
+#undef DRIVER_CTOR_TAKES_DEFAULTIMAGENAME
+
+/* Define to Diagnostic for older versions of clang */
+#undef DiagnosticsEngine
+
+/* most gcc compilers know a function __attribute__((__warn_unused_result__))
+ */
+#undef GCC_WARN_UNUSED_RESULT
+
+/* Define if llvm/ADT/OwningPtr.h exists */
+#undef HAVE_ADT_OWNINGPTR_H
+
+/* Define if clang/Basic/DiagnosticOptions.h exists */
+#undef HAVE_BASIC_DIAGNOSTICOPTIONS_H
+
+/* Define if Driver constructor takes CXXIsProduction argument */
+#undef HAVE_CXXISPRODUCTION
+
+/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */
+#undef HAVE_DECL_FFS
+
+/* Define to 1 if you have the declaration of `mp_get_memory_functions', and
+ to 0 if you don't. */
+#undef HAVE_DECL_MP_GET_MEMORY_FUNCTIONS
+
+/* Define to 1 if you have the declaration of `__builtin_ffs', and to 0 if you
+ don't. */
+#undef HAVE_DECL___BUILTIN_FFS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if Driver constructor takes IsProduction argument */
+#undef HAVE_ISPRODUCTION
+
+/* Define to 1 if you have the `gmp' library (-lgmp). */
+#undef HAVE_LIBGMP
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if SourceManager has a setMainFileID method */
+#undef HAVE_SETMAINFILEID
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* define if your compiler has __attribute__ */
+#undef HAVE___ATTRIBUTE__
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclContinue
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclReturn
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if Driver::BuildCompilation takes ArrayRef */
+#undef USE_ARRAYREF
+
+/* use gmp to implement isl_int */
+#undef USE_GMP_FOR_MP
+
+/* use imath to implement isl_int */
+#define USE_IMATH_FOR_MP 1
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to getParamType for newer versions of clang */
+#undef getArgType
+
+/* Define to getHostTriple for older versions of clang */
+#undef getDefaultTargetTriple
+
+/* Define to getInstantiationLineNumber for older versions of clang */
+#undef getExpansionLineNumber
+
+/* Define to getNumParams for newer versions of clang */
+#undef getNumArgs
+
+/* Define to getResultType for older versions of clang */
+#undef getReturnType
+
+#include <isl_config_post.h>
Added: polly/trunk/lib/External/isl/isl_config_post.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_config_post.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_config_post.h (added)
+++ polly/trunk/lib/External/isl/isl_config_post.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,13 @@
+#ifndef HAVE___ATTRIBUTE__
+#define __attribute__(x)
+#endif
+
+#if (HAVE_DECL_FFS==0) && (HAVE_DECL___BUILTIN_FFS==1)
+#define ffs __builtin_ffs
+#endif
+
+#ifdef GCC_WARN_UNUSED_RESULT
+#define WARN_UNUSED GCC_WARN_UNUSED_RESULT
+#else
+#define WARN_UNUSED
+#endif
Added: polly/trunk/lib/External/isl/isl_constraint.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_constraint.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_constraint.c (added)
+++ polly/trunk/lib/External/isl/isl_constraint.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,1437 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_map_private.h>
+#include <isl_constraint_private.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl/deprecated/constraint_int.h>
+
+#undef BASE
+#define BASE constraint
+
+#include <isl_list_templ.c>
+
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c)
+{
+ return c ? isl_local_space_get_ctx(c->ls) : NULL;
+}
+
+static unsigned n(struct isl_constraint *c, enum isl_dim_type type)
+{
+ return isl_local_space_dim(c->ls, type);
+}
+
+static unsigned offset(struct isl_constraint *c, enum isl_dim_type type)
+{
+ return isl_local_space_offset(c->ls, type);
+}
+
+static unsigned basic_map_offset(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type)
+{
+ return type == isl_dim_div ? 1 + isl_space_dim(bmap->dim, isl_dim_all)
+ : 1 + isl_space_offset(bmap->dim, type);
+}
+
+static unsigned basic_set_offset(struct isl_basic_set *bset,
+ enum isl_dim_type type)
+{
+ isl_space *dim = bset->dim;
+ switch (type) {
+ case isl_dim_param: return 1;
+ case isl_dim_in: return 1 + dim->nparam;
+ case isl_dim_out: return 1 + dim->nparam + dim->n_in;
+ case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
+ default: return 0;
+ }
+}
+
+__isl_give isl_constraint *isl_constraint_alloc_vec(int eq,
+ __isl_take isl_local_space *ls, __isl_take isl_vec *v)
+{
+ isl_constraint *constraint;
+
+ if (!ls || !v)
+ goto error;
+
+ constraint = isl_alloc_type(isl_vec_get_ctx(v), isl_constraint);
+ if (!constraint)
+ goto error;
+
+ constraint->ref = 1;
+ constraint->eq = eq;
+ constraint->ls = ls;
+ constraint->v = v;
+
+ return constraint;
+error:
+ isl_local_space_free(ls);
+ isl_vec_free(v);
+ return NULL;
+}
+
+__isl_give isl_constraint *isl_constraint_alloc(int eq,
+ __isl_take isl_local_space *ls)
+{
+ isl_ctx *ctx;
+ isl_vec *v;
+
+ if (!ls)
+ return NULL;
+
+ ctx = isl_local_space_get_ctx(ls);
+ v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+ v = isl_vec_clr(v);
+ return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+struct isl_constraint *isl_basic_map_constraint(struct isl_basic_map *bmap,
+ isl_int **line)
+{
+ int eq;
+ isl_ctx *ctx;
+ isl_vec *v;
+ isl_local_space *ls = NULL;
+ isl_constraint *constraint;
+
+ if (!bmap || !line)
+ goto error;
+
+ eq = line >= bmap->eq;
+
+ ctx = isl_basic_map_get_ctx(bmap);
+ ls = isl_basic_map_get_local_space(bmap);
+ v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+ if (!v)
+ goto error;
+ isl_seq_cpy(v->el, line[0], v->size);
+ constraint = isl_constraint_alloc_vec(eq, ls, v);
+
+ isl_basic_map_free(bmap);
+ return constraint;
+error:
+ isl_local_space_free(ls);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+ isl_int **line)
+{
+ return isl_basic_map_constraint((struct isl_basic_map *)bset, line);
+}
+
+__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls)
+{
+ return isl_constraint_alloc(1, ls);
+}
+
+__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls)
+{
+ return isl_constraint_alloc(0, ls);
+}
+
+struct isl_constraint *isl_constraint_dup(struct isl_constraint *c)
+{
+ if (!c)
+ return NULL;
+
+ return isl_constraint_alloc_vec(c->eq, isl_local_space_copy(c->ls),
+ isl_vec_copy(c->v));
+}
+
+struct isl_constraint *isl_constraint_cow(struct isl_constraint *c)
+{
+ if (!c)
+ return NULL;
+
+ if (c->ref == 1)
+ return c;
+ c->ref--;
+ return isl_constraint_dup(c);
+}
+
+struct isl_constraint *isl_constraint_copy(struct isl_constraint *constraint)
+{
+ if (!constraint)
+ return NULL;
+
+ constraint->ref++;
+ return constraint;
+}
+
+__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c)
+{
+ if (!c)
+ return NULL;
+
+ if (--c->ref > 0)
+ return NULL;
+
+ isl_local_space_free(c->ls);
+ isl_vec_free(c->v);
+ free(c);
+
+ return NULL;
+}
+
+/* Return the number of constraints in "bmap", i.e., the
+ * number of times isl_basic_map_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+
+ return bmap->n_eq + bmap->n_ineq;
+}
+
+/* Return the number of constraints in "bset", i.e., the
+ * number of times isl_basic_set_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_n_constraint(bset);
+}
+
+int isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap,
+ int (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+ int i;
+ struct isl_constraint *c;
+
+ if (!bmap)
+ return -1;
+
+ isl_assert(bmap->ctx, ISL_F_ISSET(bmap, ISL_BASIC_MAP_FINAL),
+ return -1);
+
+ for (i = 0; i < bmap->n_eq; ++i) {
+ c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+ &bmap->eq[i]);
+ if (!c)
+ return -1;
+ if (fn(c, user) < 0)
+ return -1;
+ }
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+ &bmap->ineq[i]);
+ if (!c)
+ return -1;
+ if (fn(c, user) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset,
+ int (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+ return isl_basic_map_foreach_constraint((isl_basic_map *)bset, fn, user);
+}
+
+/* Add the constraint to the list that "user" points to, if it is not
+ * a div constraint.
+ */
+static int collect_constraint(__isl_take isl_constraint *constraint,
+ void *user)
+{
+ isl_constraint_list **list = user;
+
+ if (isl_constraint_is_div_constraint(constraint))
+ isl_constraint_free(constraint);
+ else
+ *list = isl_constraint_list_add(*list, constraint);
+
+ return 0;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bmap". The input is required to have only known divs.
+ *
+ * There is no need to include the div constraints as they are
+ * implied by the div expressions.
+ */
+__isl_give isl_constraint_list *isl_basic_map_get_constraint_list(
+ __isl_keep isl_basic_map *bmap)
+{
+ int n;
+ int known;
+ isl_ctx *ctx;
+ isl_constraint_list *list;
+
+ known = isl_basic_map_divs_known(bmap);
+ if (known < 0)
+ return NULL;
+ ctx = isl_basic_map_get_ctx(bmap);
+ if (!known)
+ isl_die(ctx, isl_error_invalid,
+ "input involves unknown divs", return NULL);
+
+ n = isl_basic_map_n_constraint(bmap);
+ list = isl_constraint_list_alloc(ctx, n);
+ if (isl_basic_map_foreach_constraint(bmap,
+ &collect_constraint, &list) < 0)
+ list = isl_constraint_list_free(list);
+
+ return list;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bset". The input is required to have only known divs.
+ */
+__isl_give isl_constraint_list *isl_basic_set_get_constraint_list(
+ __isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_get_constraint_list(bset);
+}
+
+int isl_constraint_is_equal(struct isl_constraint *constraint1,
+ struct isl_constraint *constraint2)
+{
+ int equal;
+
+ if (!constraint1 || !constraint2)
+ return 0;
+ if (constraint1->eq != constraint2->eq)
+ return 0;
+ equal = isl_local_space_is_equal(constraint1->ls, constraint2->ls);
+ if (equal < 0 || !equal)
+ return equal;
+ return isl_vec_is_equal(constraint1->v, constraint2->v);
+}
+
+struct isl_basic_map *isl_basic_map_add_constraint(
+ struct isl_basic_map *bmap, struct isl_constraint *constraint)
+{
+ isl_ctx *ctx;
+ isl_space *dim;
+ int equal_space;
+
+ if (!bmap || !constraint)
+ goto error;
+
+ ctx = isl_constraint_get_ctx(constraint);
+ dim = isl_constraint_get_space(constraint);
+ equal_space = isl_space_is_equal(bmap->dim, dim);
+ isl_space_free(dim);
+ isl_assert(ctx, equal_space, goto error);
+
+ bmap = isl_basic_map_intersect(bmap,
+ isl_basic_map_from_constraint(constraint));
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_constraint_free(constraint);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraint(
+ struct isl_basic_set *bset, struct isl_constraint *constraint)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_add_constraint((struct isl_basic_map *)bset,
+ constraint);
+}
+
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+ __isl_take isl_constraint *constraint)
+{
+ isl_basic_map *bmap;
+
+ bmap = isl_basic_map_from_constraint(constraint);
+ map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+ return map;
+}
+
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+ __isl_take isl_constraint *constraint)
+{
+ return isl_map_add_constraint(set, constraint);
+}
+
+__isl_give isl_space *isl_constraint_get_space(
+ __isl_keep isl_constraint *constraint)
+{
+ return constraint ? isl_local_space_get_space(constraint->ls) : NULL;
+}
+
+__isl_give isl_local_space *isl_constraint_get_local_space(
+ __isl_keep isl_constraint *constraint)
+{
+ return constraint ? isl_local_space_copy(constraint->ls) : NULL;
+}
+
+int isl_constraint_dim(struct isl_constraint *constraint,
+ enum isl_dim_type type)
+{
+ if (!constraint)
+ return -1;
+ return n(constraint, type);
+}
+
+int isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+ isl_ctx *ctx;
+ int *active = NULL;
+ int involves = 0;
+
+ if (!constraint)
+ return -1;
+ if (n == 0)
+ return 0;
+
+ ctx = isl_constraint_get_ctx(constraint);
+ if (first + n > isl_constraint_dim(constraint, type))
+ isl_die(ctx, isl_error_invalid,
+ "range out of bounds", return -1);
+
+ active = isl_local_space_get_active(constraint->ls,
+ constraint->v->el + 1);
+ if (!active)
+ goto error;
+
+ first += isl_local_space_offset(constraint->ls, type) - 1;
+ for (i = 0; i < n; ++i)
+ if (active[first + i]) {
+ involves = 1;
+ break;
+ }
+
+ free(active);
+
+ return involves;
+error:
+ free(active);
+ return -1;
+}
+
+/* Does the given constraint represent a lower bound on the given
+ * dimension?
+ */
+int isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint,
+ enum isl_dim_type type, unsigned pos)
+{
+ if (!constraint)
+ return -1;
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "position out of bounds", return -1);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ return isl_int_is_pos(constraint->v->el[pos]);
+}
+
+/* Does the given constraint represent an upper bound on the given
+ * dimension?
+ */
+int isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint,
+ enum isl_dim_type type, unsigned pos)
+{
+ if (!constraint)
+ return -1;
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "position out of bounds", return -1);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ return isl_int_is_neg(constraint->v->el[pos]);
+}
+
+const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
+ enum isl_dim_type type, unsigned pos)
+{
+ return constraint ?
+ isl_local_space_get_dim_name(constraint->ls, type, pos) : NULL;
+}
+
+void isl_constraint_get_constant(struct isl_constraint *constraint, isl_int *v)
+{
+ if (!constraint)
+ return;
+ isl_int_set(*v, constraint->v->el[0]);
+}
+
+/* Return the constant term of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_constant_val(
+ __isl_keep isl_constraint *constraint)
+{
+ isl_ctx *ctx;
+
+ if (!constraint)
+ return NULL;
+
+ ctx = isl_constraint_get_ctx(constraint);
+ return isl_val_int_from_isl_int(ctx, constraint->v->el[0]);
+}
+
+void isl_constraint_get_coefficient(struct isl_constraint *constraint,
+ enum isl_dim_type type, int pos, isl_int *v)
+{
+ if (!constraint)
+ return;
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(constraint->v->ctx, isl_error_invalid,
+ "position out of bounds", return);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ isl_int_set(*v, constraint->v->el[pos]);
+}
+
+/* Return the coefficient of the variable of type "type" at position "pos"
+ * of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_coefficient_val(
+ __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+ isl_ctx *ctx;
+
+ if (!constraint)
+ return NULL;
+
+ ctx = isl_constraint_get_ctx(constraint);
+ if (pos < 0 || pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(ctx, isl_error_invalid,
+ "position out of bounds", return NULL);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ return isl_val_int_from_isl_int(ctx, constraint->v->el[pos]);
+}
+
+__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint,
+ int pos)
+{
+ if (!constraint)
+ return NULL;
+
+ return isl_local_space_get_div(constraint->ls, pos);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant(
+ __isl_take isl_constraint *constraint, isl_int v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ constraint->v = isl_vec_cow(constraint->v);
+ if (!constraint->v)
+ return isl_constraint_free(constraint);
+
+ isl_int_set(constraint->v->el[0], v);
+ return constraint;
+}
+
+/* Replace the constant term of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_constant_val(
+ __isl_take isl_constraint *constraint, __isl_take isl_val *v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint || !v)
+ goto error;
+ if (!isl_val_is_int(v))
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "expecting integer value", goto error);
+ constraint->v = isl_vec_set_element_val(constraint->v, 0, v);
+ if (!constraint->v)
+ constraint = isl_constraint_free(constraint);
+ return constraint;
+error:
+ isl_val_free(v);
+ return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant_si(
+ __isl_take isl_constraint *constraint, int v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ constraint->v = isl_vec_cow(constraint->v);
+ if (!constraint->v)
+ return isl_constraint_free(constraint);
+
+ isl_int_set_si(constraint->v->el[0], v);
+ return constraint;
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+ __isl_take isl_constraint *constraint,
+ enum isl_dim_type type, int pos, isl_int v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(constraint->v->ctx, isl_error_invalid,
+ "position out of bounds",
+ return isl_constraint_free(constraint));
+
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ constraint->v = isl_vec_cow(constraint->v);
+ if (!constraint->v)
+ return isl_constraint_free(constraint);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ isl_int_set(constraint->v->el[pos], v);
+
+ return constraint;
+}
+
+/* Replace the coefficient of the variable of type "type" at position "pos"
+ * of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_coefficient_val(
+ __isl_take isl_constraint *constraint,
+ enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint || !v)
+ goto error;
+ if (!isl_val_is_int(v))
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "expecting integer value", goto error);
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "position out of bounds", goto error);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ constraint->v = isl_vec_set_element_val(constraint->v, pos, v);
+ if (!constraint->v)
+ constraint = isl_constraint_free(constraint);
+ return constraint;
+error:
+ isl_val_free(v);
+ return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient_si(
+ __isl_take isl_constraint *constraint,
+ enum isl_dim_type type, int pos, int v)
+{
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ if (pos >= isl_local_space_dim(constraint->ls, type))
+ isl_die(constraint->v->ctx, isl_error_invalid,
+ "position out of bounds",
+ return isl_constraint_free(constraint));
+
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ constraint->v = isl_vec_cow(constraint->v);
+ if (!constraint->v)
+ return isl_constraint_free(constraint);
+
+ pos += isl_local_space_offset(constraint->ls, type);
+ isl_int_set_si(constraint->v->el[pos], v);
+
+ return constraint;
+}
+
+/* Drop any constraint from "bset" that is identical to "constraint".
+ * In particular, this means that the local spaces of "bset" and
+ * "constraint" need to be the same.
+ *
+ * Since the given constraint may actually be a pointer into the bset,
+ * we have to be careful not to reorder the constraints as the user
+ * may be holding on to other constraints from the same bset.
+ * This should be cleaned up when the internal representation of
+ * isl_constraint is changed to use isl_aff.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraint(
+ __isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint)
+{
+ int i;
+ unsigned n;
+ isl_int **row;
+ unsigned total;
+ isl_local_space *ls1;
+ int equal;
+
+ if (!bset || !constraint)
+ goto error;
+
+ ls1 = isl_basic_set_get_local_space(bset);
+ equal = isl_local_space_is_equal(ls1, constraint->ls);
+ isl_local_space_free(ls1);
+ if (equal < 0)
+ goto error;
+ if (!equal) {
+ isl_constraint_free(constraint);
+ return bset;
+ }
+
+ if (isl_constraint_is_equality(constraint)) {
+ n = bset->n_eq;
+ row = bset->eq;
+ } else {
+ n = bset->n_ineq;
+ row = bset->ineq;
+ }
+
+ total = isl_constraint_dim(constraint, isl_dim_all);
+ for (i = 0; i < n; ++i)
+ if (isl_seq_eq(row[i], constraint->v->el, 1 + total))
+ isl_seq_clr(row[i], 1 + total);
+
+ isl_constraint_free(constraint);
+ return bset;
+error:
+ isl_constraint_free(constraint);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint)
+{
+ isl_ctx *ctx;
+
+ constraint = isl_constraint_cow(constraint);
+ if (!constraint)
+ return NULL;
+
+ ctx = isl_constraint_get_ctx(constraint);
+ if (isl_constraint_is_equality(constraint))
+ isl_die(ctx, isl_error_invalid, "cannot negate equality",
+ return isl_constraint_free(constraint));
+ constraint->v = isl_vec_neg(constraint->v);
+ constraint->v = isl_vec_cow(constraint->v);
+ if (!constraint->v)
+ return isl_constraint_free(constraint);
+ isl_int_sub_ui(constraint->v->el[0], constraint->v->el[0], 1);
+ return constraint;
+}
+
+int isl_constraint_is_equality(struct isl_constraint *constraint)
+{
+ if (!constraint)
+ return -1;
+ return constraint->eq;
+}
+
+int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint)
+{
+ int i;
+ int n_div;
+
+ if (!constraint)
+ return -1;
+ if (isl_constraint_is_equality(constraint))
+ return 0;
+ n_div = isl_constraint_dim(constraint, isl_dim_div);
+ for (i = 0; i < n_div; ++i) {
+ if (isl_local_space_is_div_constraint(constraint->ls,
+ constraint->v->el, i))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* We manually set ISL_BASIC_SET_FINAL instead of calling
+ * isl_basic_map_finalize because we want to keep the position
+ * of the divs and we therefore do not want to throw away redundant divs.
+ * This is arguably a bit fragile.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_constraint(
+ __isl_take isl_constraint *constraint)
+{
+ int k;
+ isl_local_space *ls;
+ struct isl_basic_map *bmap;
+ isl_int *c;
+ unsigned total;
+
+ if (!constraint)
+ return NULL;
+
+ ls = isl_local_space_copy(constraint->ls);
+ bmap = isl_basic_map_from_local_space(ls);
+ bmap = isl_basic_map_extend_constraints(bmap, 1, 1);
+ if (isl_constraint_is_equality(constraint)) {
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+ c = bmap->eq[k];
+ }
+ else {
+ k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ c = bmap->ineq[k];
+ }
+ total = isl_basic_map_total_dim(bmap);
+ isl_seq_cpy(c, constraint->v->el, 1 + total);
+ isl_constraint_free(constraint);
+ if (bmap)
+ ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+ return bmap;
+error:
+ isl_constraint_free(constraint);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_constraint(
+ struct isl_constraint *constraint)
+{
+ if (!constraint)
+ return NULL;
+
+ if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+ isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+ "not a set constraint", goto error);
+ return (isl_basic_set *)isl_basic_map_from_constraint(constraint);
+error:
+ isl_constraint_free(constraint);
+ return NULL;
+}
+
+/* Is the variable of "type" at position "pos" of "bmap" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+int isl_basic_map_has_defining_equality(
+ __isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos,
+ __isl_give isl_constraint **c)
+{
+ int i;
+ unsigned offset;
+ unsigned total;
+
+ if (!bmap)
+ return -1;
+ offset = basic_map_offset(bmap, type);
+ total = isl_basic_map_total_dim(bmap);
+ isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), return -1);
+ for (i = 0; i < bmap->n_eq; ++i) {
+ if (isl_int_is_zero(bmap->eq[i][offset + pos]) ||
+ isl_seq_first_non_zero(bmap->eq[i]+offset+pos+1,
+ 1+total-offset-pos-1) != -1)
+ continue;
+ if (c)
+ *c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+ &bmap->eq[i]);
+ return 1;
+ }
+ return 0;
+}
+
+/* Is the variable of "type" at position "pos" of "bset" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+int isl_basic_set_has_defining_equality(
+ __isl_keep isl_basic_set *bset, enum isl_dim_type type, int pos,
+ __isl_give isl_constraint **c)
+{
+ return isl_basic_map_has_defining_equality((isl_basic_map *)bset,
+ type, pos, c);
+}
+
+int isl_basic_set_has_defining_inequalities(
+ struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+ struct isl_constraint **lower,
+ struct isl_constraint **upper)
+{
+ int i, j;
+ unsigned offset;
+ unsigned total;
+ isl_int m;
+ isl_int **lower_line, **upper_line;
+
+ if (!bset)
+ return -1;
+ offset = basic_set_offset(bset, type);
+ total = isl_basic_set_total_dim(bset);
+ isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), return -1);
+ isl_int_init(m);
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_zero(bset->ineq[i][offset + pos]))
+ continue;
+ if (isl_int_is_one(bset->ineq[i][offset + pos]))
+ continue;
+ if (isl_int_is_negone(bset->ineq[i][offset + pos]))
+ continue;
+ if (isl_seq_first_non_zero(bset->ineq[i]+offset+pos+1,
+ 1+total-offset-pos-1) != -1)
+ continue;
+ for (j = i + 1; j < bset->n_ineq; ++j) {
+ if (!isl_seq_is_neg(bset->ineq[i]+1, bset->ineq[j]+1,
+ total))
+ continue;
+ isl_int_add(m, bset->ineq[i][0], bset->ineq[j][0]);
+ if (isl_int_abs_ge(m, bset->ineq[i][offset+pos]))
+ continue;
+
+ if (isl_int_is_pos(bset->ineq[i][offset+pos])) {
+ lower_line = &bset->ineq[i];
+ upper_line = &bset->ineq[j];
+ } else {
+ lower_line = &bset->ineq[j];
+ upper_line = &bset->ineq[i];
+ }
+ *lower = isl_basic_set_constraint(
+ isl_basic_set_copy(bset), lower_line);
+ *upper = isl_basic_set_constraint(
+ isl_basic_set_copy(bset), upper_line);
+ isl_int_clear(m);
+ return 1;
+ }
+ }
+ *lower = NULL;
+ *upper = NULL;
+ isl_int_clear(m);
+ return 0;
+}
+
+/* Given two constraints "a" and "b" on the variable at position "abs_pos"
+ * (in "a" and "b"), add a constraint to "bset" that ensures that the
+ * bound implied by "a" is (strictly) larger than the bound implied by "b".
+ *
+ * If both constraints imply lower bounds, then this means that "a" is
+ * active in the result.
+ * If both constraints imply upper bounds, then this means that "b" is
+ * active in the result.
+ */
+static __isl_give isl_basic_set *add_larger_bound_constraint(
+ __isl_take isl_basic_set *bset, isl_int *a, isl_int *b,
+ unsigned abs_pos, int strict)
+{
+ int k;
+ isl_int t;
+ unsigned total;
+
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+
+ total = isl_basic_set_dim(bset, isl_dim_all);
+
+ isl_int_init(t);
+ isl_int_neg(t, b[1 + abs_pos]);
+
+ isl_seq_combine(bset->ineq[k], t, a, a[1 + abs_pos], b, 1 + abs_pos);
+ isl_seq_combine(bset->ineq[k] + 1 + abs_pos,
+ t, a + 1 + abs_pos + 1, a[1 + abs_pos], b + 1 + abs_pos + 1,
+ total - abs_pos);
+
+ if (strict)
+ isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+
+ isl_int_clear(t);
+
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Add constraints to "context" that ensure that "u" is the smallest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_smallest_upper_bound(
+ __isl_keep isl_basic_set *context,
+ __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_upper, int u)
+{
+ int j;
+
+ context = isl_basic_set_copy(context);
+ context = isl_basic_set_cow(context);
+
+ context = isl_basic_set_extend_constraints(context, 0, n_upper - 1);
+
+ for (j = 0; j < bset->n_ineq; ++j) {
+ if (j == u)
+ continue;
+ if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+ continue;
+ context = add_larger_bound_constraint(context,
+ bset->ineq[j], bset->ineq[u], abs_pos, j > u);
+ }
+
+ context = isl_basic_set_simplify(context);
+ context = isl_basic_set_finalize(context);
+
+ return context;
+}
+
+/* Add constraints to "context" that ensure that "u" is the largest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_largest_lower_bound(
+ __isl_keep isl_basic_set *context,
+ __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_lower, int l)
+{
+ int j;
+
+ context = isl_basic_set_copy(context);
+ context = isl_basic_set_cow(context);
+
+ context = isl_basic_set_extend_constraints(context, 0, n_lower - 1);
+
+ for (j = 0; j < bset->n_ineq; ++j) {
+ if (j == l)
+ continue;
+ if (!isl_int_is_pos(bset->ineq[j][1 + abs_pos]))
+ continue;
+ context = add_larger_bound_constraint(context,
+ bset->ineq[l], bset->ineq[j], abs_pos, j > l);
+ }
+
+ context = isl_basic_set_simplify(context);
+ context = isl_basic_set_finalize(context);
+
+ return context;
+}
+
+static int foreach_upper_bound(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned abs_pos,
+ __isl_take isl_basic_set *context, int n_upper,
+ int (*fn)(__isl_take isl_constraint *lower,
+ __isl_take isl_constraint *upper,
+ __isl_take isl_basic_set *bset, void *user), void *user)
+{
+ isl_basic_set *context_i;
+ isl_constraint *upper = NULL;
+ int i;
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+ continue;
+
+ context_i = set_smallest_upper_bound(context, bset,
+ abs_pos, n_upper, i);
+ if (isl_basic_set_is_empty(context_i)) {
+ isl_basic_set_free(context_i);
+ continue;
+ }
+ upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+ &bset->ineq[i]);
+ if (!upper || !context_i)
+ goto error;
+ if (fn(NULL, upper, context_i, user) < 0)
+ break;
+ }
+
+ isl_basic_set_free(context);
+
+ if (i < bset->n_ineq)
+ return -1;
+
+ return 0;
+error:
+ isl_constraint_free(upper);
+ isl_basic_set_free(context_i);
+ isl_basic_set_free(context);
+ return -1;
+}
+
+static int foreach_lower_bound(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned abs_pos,
+ __isl_take isl_basic_set *context, int n_lower,
+ int (*fn)(__isl_take isl_constraint *lower,
+ __isl_take isl_constraint *upper,
+ __isl_take isl_basic_set *bset, void *user), void *user)
+{
+ isl_basic_set *context_i;
+ isl_constraint *lower = NULL;
+ int i;
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+ continue;
+
+ context_i = set_largest_lower_bound(context, bset,
+ abs_pos, n_lower, i);
+ if (isl_basic_set_is_empty(context_i)) {
+ isl_basic_set_free(context_i);
+ continue;
+ }
+ lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+ &bset->ineq[i]);
+ if (!lower || !context_i)
+ goto error;
+ if (fn(lower, NULL, context_i, user) < 0)
+ break;
+ }
+
+ isl_basic_set_free(context);
+
+ if (i < bset->n_ineq)
+ return -1;
+
+ return 0;
+error:
+ isl_constraint_free(lower);
+ isl_basic_set_free(context_i);
+ isl_basic_set_free(context);
+ return -1;
+}
+
+static int foreach_bound_pair(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned abs_pos,
+ __isl_take isl_basic_set *context, int n_lower, int n_upper,
+ int (*fn)(__isl_take isl_constraint *lower,
+ __isl_take isl_constraint *upper,
+ __isl_take isl_basic_set *bset, void *user), void *user)
+{
+ isl_basic_set *context_i, *context_j;
+ isl_constraint *lower = NULL;
+ isl_constraint *upper = NULL;
+ int i, j;
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (!isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+ continue;
+
+ context_i = set_largest_lower_bound(context, bset,
+ abs_pos, n_lower, i);
+ if (isl_basic_set_is_empty(context_i)) {
+ isl_basic_set_free(context_i);
+ continue;
+ }
+
+ for (j = 0; j < bset->n_ineq; ++j) {
+ if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+ continue;
+
+ context_j = set_smallest_upper_bound(context_i, bset,
+ abs_pos, n_upper, j);
+ context_j = isl_basic_set_extend_constraints(context_j,
+ 0, 1);
+ context_j = add_larger_bound_constraint(context_j,
+ bset->ineq[i], bset->ineq[j], abs_pos, 0);
+ context_j = isl_basic_set_simplify(context_j);
+ context_j = isl_basic_set_finalize(context_j);
+ if (isl_basic_set_is_empty(context_j)) {
+ isl_basic_set_free(context_j);
+ continue;
+ }
+ lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+ &bset->ineq[i]);
+ upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+ &bset->ineq[j]);
+ if (!lower || !upper || !context_j)
+ goto error;
+ if (fn(lower, upper, context_j, user) < 0)
+ break;
+ }
+
+ isl_basic_set_free(context_i);
+
+ if (j < bset->n_ineq)
+ break;
+ }
+
+ isl_basic_set_free(context);
+
+ if (i < bset->n_ineq)
+ return -1;
+
+ return 0;
+error:
+ isl_constraint_free(lower);
+ isl_constraint_free(upper);
+ isl_basic_set_free(context_i);
+ isl_basic_set_free(context_j);
+ isl_basic_set_free(context);
+ return -1;
+}
+
+/* For each pair of lower and upper bounds on the variable "pos"
+ * of type "type", call "fn" with these lower and upper bounds and the
+ * set of constraints on the remaining variables where these bounds
+ * are active, i.e., (stricly) larger/smaller than the other lower/upper bounds.
+ *
+ * If the designated variable is equal to an affine combination of the
+ * other variables then fn is called with both lower and upper
+ * set to the corresponding equality.
+ *
+ * If there is no lower (or upper) bound, then NULL is passed
+ * as the corresponding bound.
+ *
+ * We first check if the variable is involved in any equality.
+ * If not, we count the number of lower and upper bounds and
+ * act accordingly.
+ */
+int isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos,
+ int (*fn)(__isl_take isl_constraint *lower,
+ __isl_take isl_constraint *upper,
+ __isl_take isl_basic_set *bset, void *user), void *user)
+{
+ int i;
+ isl_constraint *lower = NULL;
+ isl_constraint *upper = NULL;
+ isl_basic_set *context = NULL;
+ unsigned abs_pos;
+ int n_lower, n_upper;
+
+ if (!bset)
+ return -1;
+ isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), return -1);
+ isl_assert(bset->ctx, type == isl_dim_param || type == isl_dim_set,
+ return -1);
+
+ abs_pos = pos;
+ if (type == isl_dim_set)
+ abs_pos += isl_basic_set_dim(bset, isl_dim_param);
+
+ for (i = 0; i < bset->n_eq; ++i) {
+ if (isl_int_is_zero(bset->eq[i][1 + abs_pos]))
+ continue;
+
+ lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+ &bset->eq[i]);
+ upper = isl_constraint_copy(lower);
+ context = isl_basic_set_remove_dims(isl_basic_set_copy(bset),
+ type, pos, 1);
+ if (!lower || !upper || !context)
+ goto error;
+ return fn(lower, upper, context, user);
+ }
+
+ n_lower = 0;
+ n_upper = 0;
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+ n_lower++;
+ else if (isl_int_is_neg(bset->ineq[i][1 + abs_pos]))
+ n_upper++;
+ }
+
+ context = isl_basic_set_copy(bset);
+ context = isl_basic_set_cow(context);
+ if (!context)
+ goto error;
+ for (i = context->n_ineq - 1; i >= 0; --i)
+ if (!isl_int_is_zero(context->ineq[i][1 + abs_pos]))
+ isl_basic_set_drop_inequality(context, i);
+
+ context = isl_basic_set_drop(context, type, pos, 1);
+ if (!n_lower && !n_upper)
+ return fn(NULL, NULL, context, user);
+ if (!n_lower)
+ return foreach_upper_bound(bset, type, abs_pos, context, n_upper,
+ fn, user);
+ if (!n_upper)
+ return foreach_lower_bound(bset, type, abs_pos, context, n_lower,
+ fn, user);
+ return foreach_bound_pair(bset, type, abs_pos, context, n_lower, n_upper,
+ fn, user);
+error:
+ isl_constraint_free(lower);
+ isl_constraint_free(upper);
+ isl_basic_set_free(context);
+ return -1;
+}
+
+__isl_give isl_aff *isl_constraint_get_bound(
+ __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+ isl_aff *aff;
+ isl_ctx *ctx;
+
+ if (!constraint)
+ return NULL;
+ ctx = isl_constraint_get_ctx(constraint);
+ if (pos >= isl_constraint_dim(constraint, type))
+ isl_die(ctx, isl_error_invalid,
+ "index out of bounds", return NULL);
+ if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+ isl_die(ctx, isl_error_invalid,
+ "not a set constraint", return NULL);
+
+ pos += offset(constraint, type);
+ if (isl_int_is_zero(constraint->v->el[pos]))
+ isl_die(ctx, isl_error_invalid,
+ "constraint does not define a bound on given dimension",
+ return NULL);
+
+ aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+ if (!aff)
+ return NULL;
+
+ if (isl_int_is_neg(constraint->v->el[pos]))
+ isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+ else
+ isl_seq_neg(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+ isl_int_set_si(aff->v->el[1 + pos], 0);
+ isl_int_abs(aff->v->el[0], constraint->v->el[pos]);
+
+ return aff;
+}
+
+/* For an inequality constraint
+ *
+ * f >= 0
+ *
+ * or an equality constraint
+ *
+ * f = 0
+ *
+ * return the affine expression f.
+ */
+__isl_give isl_aff *isl_constraint_get_aff(
+ __isl_keep isl_constraint *constraint)
+{
+ isl_aff *aff;
+
+ if (!constraint)
+ return NULL;
+
+ aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+ if (!aff)
+ return NULL;
+
+ isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+ isl_int_set_si(aff->v->el[0], 1);
+
+ return aff;
+}
+
+/* Construct an inequality (eq = 0) or equality (eq = 1) constraint from "aff".
+ * In particular, construct aff >= 0 or aff = 0.
+ *
+ * The denominator of "aff" can be ignored.
+ */
+static __isl_give isl_constraint *isl_constraint_alloc_aff(int eq,
+ __isl_take isl_aff *aff)
+{
+ isl_local_space *ls;
+ isl_vec *v;
+
+ if (!aff)
+ return NULL;
+ ls = isl_aff_get_domain_local_space(aff);
+ v = isl_vec_drop_els(isl_vec_copy(aff->v), 0, 1);
+ isl_aff_free(aff);
+
+ return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+/* Construct an equality constraint equating the given affine expression
+ * to zero.
+ */
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff)
+{
+ return isl_constraint_alloc_aff(1, aff);
+}
+
+/* Construct an inequality constraint enforcing the given affine expression
+ * to be non-negative.
+ */
+__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff)
+{
+ return isl_constraint_alloc_aff(0, aff);
+}
+
+/* Compare two isl_constraints.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary. We do consider constraints that only involve
+ * earlier dimensions as "smaller".
+ */
+int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1,
+ __isl_keep isl_constraint *c2)
+{
+ int cmp;
+ int last1, last2;
+
+ if (c1 == c2)
+ return 0;
+ if (!c1)
+ return -1;
+ if (!c2)
+ return 1;
+ cmp = isl_local_space_cmp(c1->ls, c2->ls);
+ if (cmp != 0)
+ return cmp;
+
+ last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+ last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+ if (last1 != last2)
+ return last1 - last2;
+
+ return isl_seq_cmp(c1->v->el, c2->v->el, c1->v->size);
+}
+
+/* Compare two constraints based on their final (non-zero) coefficients.
+ * In particular, the constraint that involves later variables or
+ * that has a larger coefficient for a shared latest variable
+ * is considered "greater" than the other constraint.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * If the constraints live in different local spaces, then we cannot
+ * really compare the constraints so we compare the local spaces instead.
+ */
+int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1,
+ __isl_keep isl_constraint *c2)
+{
+ int cmp;
+ int last1, last2;
+
+ if (c1 == c2)
+ return 0;
+ if (!c1)
+ return -1;
+ if (!c2)
+ return 1;
+ cmp = isl_local_space_cmp(c1->ls, c2->ls);
+ if (cmp != 0)
+ return cmp;
+
+ last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+ last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+ if (last1 != last2)
+ return last1 - last2;
+ if (last1 == -1)
+ return 0;
+ return isl_int_abs_cmp(c1->v->el[1 + last1], c2->v->el[1 + last2]);
+}
Added: polly/trunk/lib/External/isl/isl_constraint_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_constraint_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_constraint_private.h (added)
+++ polly/trunk/lib/External/isl/isl_constraint_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,32 @@
+#ifndef ISL_CONSTRAINT_PRIVATE_H
+#define ISL_CONSTRAINT_PRIVATE_H
+
+#include <isl/constraint.h>
+#include <isl/local_space.h>
+#include <isl/vec.h>
+
+struct isl_constraint {
+ int ref;
+
+ int eq;
+ isl_local_space *ls;
+ isl_vec *v;
+};
+
+#undef EL
+#define EL isl_constraint
+
+#include <isl_list_templ.h>
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+ isl_int **line);
+
+void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint,
+ enum isl_dim_type type, int pos, isl_int *v);
+__isl_give isl_constraint *isl_constraint_set_constant(
+ __isl_take isl_constraint *constraint, isl_int v);
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+ __isl_take isl_constraint *constraint,
+ enum isl_dim_type type, int pos, isl_int v);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_convex_hull.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_convex_hull.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_convex_hull.c (added)
+++ polly/trunk/lib/External/isl/isl_convex_hull.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,2829 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2014 INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_lp_private.h>
+#include <isl/map.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_options_private.h>
+#include "isl_equalities.h"
+#include "isl_tab.h"
+#include <isl_sort.h>
+
+static struct isl_basic_set *uset_convex_hull_wrap_bounded(struct isl_set *set);
+
+/* Return 1 if constraint c is redundant with respect to the constraints
+ * in bmap. If c is a lower [upper] bound in some variable and bmap
+ * does not have a lower [upper] bound in that variable, then c cannot
+ * be redundant and we do not need solve any lp.
+ */
+int isl_basic_map_constraint_is_redundant(struct isl_basic_map **bmap,
+ isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+ enum isl_lp_result res;
+ unsigned total;
+ int i, j;
+
+ if (!bmap)
+ return -1;
+
+ total = isl_basic_map_total_dim(*bmap);
+ for (i = 0; i < total; ++i) {
+ int sign;
+ if (isl_int_is_zero(c[1+i]))
+ continue;
+ sign = isl_int_sgn(c[1+i]);
+ for (j = 0; j < (*bmap)->n_ineq; ++j)
+ if (sign == isl_int_sgn((*bmap)->ineq[j][1+i]))
+ break;
+ if (j == (*bmap)->n_ineq)
+ break;
+ }
+ if (i < total)
+ return 0;
+
+ res = isl_basic_map_solve_lp(*bmap, 0, c, (*bmap)->ctx->one,
+ opt_n, opt_d, NULL);
+ if (res == isl_lp_unbounded)
+ return 0;
+ if (res == isl_lp_error)
+ return -1;
+ if (res == isl_lp_empty) {
+ *bmap = isl_basic_map_set_to_empty(*bmap);
+ return 0;
+ }
+ return !isl_int_is_neg(*opt_n);
+}
+
+int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
+ isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+ return isl_basic_map_constraint_is_redundant(
+ (struct isl_basic_map **)bset, c, opt_n, opt_d);
+}
+
+/* Remove redundant
+ * constraints. If the minimal value along the normal of a constraint
+ * is the same if the constraint is removed, then the constraint is redundant.
+ *
+ * Alternatively, we could have intersected the basic map with the
+ * corresponding equality and the checked if the dimension was that
+ * of a facet.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+ __isl_take isl_basic_map *bmap)
+{
+ struct isl_tab *tab;
+
+ if (!bmap)
+ return NULL;
+
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+ return bmap;
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT))
+ return bmap;
+ if (bmap->n_ineq <= 1)
+ return bmap;
+
+ tab = isl_tab_from_basic_map(bmap, 0);
+ if (isl_tab_detect_implicit_equalities(tab) < 0)
+ goto error;
+ if (isl_tab_detect_redundant(tab) < 0)
+ goto error;
+ bmap = isl_basic_map_update_from_tab(bmap, tab);
+ isl_tab_free(tab);
+ ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+ return bmap;
+error:
+ isl_tab_free(tab);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+ __isl_take isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_remove_redundancies((struct isl_basic_map *)bset);
+}
+
+/* Remove redundant constraints in each of the basic maps.
+ */
+__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map)
+{
+ return isl_map_inline_foreach_basic_map(map,
+ &isl_basic_map_remove_redundancies);
+}
+
+__isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set)
+{
+ return isl_map_remove_redundancies(set);
+}
+
+/* Check if the set set is bound in the direction of the affine
+ * constraint c and if so, set the constant term such that the
+ * resulting constraint is a bounding constraint for the set.
+ */
+static int uset_is_bound(struct isl_set *set, isl_int *c, unsigned len)
+{
+ int first;
+ int j;
+ isl_int opt;
+ isl_int opt_denom;
+
+ isl_int_init(opt);
+ isl_int_init(opt_denom);
+ first = 1;
+ for (j = 0; j < set->n; ++j) {
+ enum isl_lp_result res;
+
+ if (ISL_F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY))
+ continue;
+
+ res = isl_basic_set_solve_lp(set->p[j],
+ 0, c, set->ctx->one, &opt, &opt_denom, NULL);
+ if (res == isl_lp_unbounded)
+ break;
+ if (res == isl_lp_error)
+ goto error;
+ if (res == isl_lp_empty) {
+ set->p[j] = isl_basic_set_set_to_empty(set->p[j]);
+ if (!set->p[j])
+ goto error;
+ continue;
+ }
+ if (first || isl_int_is_neg(opt)) {
+ if (!isl_int_is_one(opt_denom))
+ isl_seq_scale(c, c, opt_denom, len);
+ isl_int_sub(c[0], c[0], opt);
+ }
+ first = 0;
+ }
+ isl_int_clear(opt);
+ isl_int_clear(opt_denom);
+ return j >= set->n;
+error:
+ isl_int_clear(opt);
+ isl_int_clear(opt_denom);
+ return -1;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+ __isl_take isl_basic_set *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL);
+
+ return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_rational(
+ __isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_set_rational(bset);
+}
+
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_set_rational(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set)
+{
+ return isl_map_set_rational(set);
+}
+
+static struct isl_basic_set *isl_basic_set_add_equality(
+ struct isl_basic_set *bset, isl_int *c)
+{
+ int i;
+ unsigned dim;
+
+ if (!bset)
+ return NULL;
+
+ if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+ return bset;
+
+ isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+ isl_assert(bset->ctx, bset->n_div == 0, goto error);
+ dim = isl_basic_set_n_dim(bset);
+ bset = isl_basic_set_cow(bset);
+ bset = isl_basic_set_extend(bset, 0, dim, 0, 1, 0);
+ i = isl_basic_set_alloc_equality(bset);
+ if (i < 0)
+ goto error;
+ isl_seq_cpy(bset->eq[i], c, 1 + dim);
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+static struct isl_set *isl_set_add_basic_set_equality(struct isl_set *set, isl_int *c)
+{
+ int i;
+
+ set = isl_set_cow(set);
+ if (!set)
+ return NULL;
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_add_equality(set->p[i], c);
+ if (!set->p[i])
+ goto error;
+ }
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Given a union of basic sets, construct the constraints for wrapping
+ * a facet around one of its ridges.
+ * In particular, if each of n the d-dimensional basic sets i in "set"
+ * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0
+ * and is defined by the constraints
+ * [ 1 ]
+ * A_i [ x ] >= 0
+ *
+ * then the resulting set is of dimension n*(1+d) and has as constraints
+ *
+ * [ a_i ]
+ * A_i [ x_i ] >= 0
+ *
+ * a_i >= 0
+ *
+ * \sum_i x_{i,1} = 1
+ */
+static struct isl_basic_set *wrap_constraints(struct isl_set *set)
+{
+ struct isl_basic_set *lp;
+ unsigned n_eq;
+ unsigned n_ineq;
+ int i, j, k;
+ unsigned dim, lp_dim;
+
+ if (!set)
+ return NULL;
+
+ dim = 1 + isl_set_n_dim(set);
+ n_eq = 1;
+ n_ineq = set->n;
+ for (i = 0; i < set->n; ++i) {
+ n_eq += set->p[i]->n_eq;
+ n_ineq += set->p[i]->n_ineq;
+ }
+ lp = isl_basic_set_alloc(set->ctx, 0, dim * set->n, 0, n_eq, n_ineq);
+ lp = isl_basic_set_set_rational(lp);
+ if (!lp)
+ return NULL;
+ lp_dim = isl_basic_set_n_dim(lp);
+ k = isl_basic_set_alloc_equality(lp);
+ isl_int_set_si(lp->eq[k][0], -1);
+ for (i = 0; i < set->n; ++i) {
+ isl_int_set_si(lp->eq[k][1+dim*i], 0);
+ isl_int_set_si(lp->eq[k][1+dim*i+1], 1);
+ isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2);
+ }
+ for (i = 0; i < set->n; ++i) {
+ k = isl_basic_set_alloc_inequality(lp);
+ isl_seq_clr(lp->ineq[k], 1+lp_dim);
+ isl_int_set_si(lp->ineq[k][1+dim*i], 1);
+
+ for (j = 0; j < set->p[i]->n_eq; ++j) {
+ k = isl_basic_set_alloc_equality(lp);
+ isl_seq_clr(lp->eq[k], 1+dim*i);
+ isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim);
+ isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1));
+ }
+
+ for (j = 0; j < set->p[i]->n_ineq; ++j) {
+ k = isl_basic_set_alloc_inequality(lp);
+ isl_seq_clr(lp->ineq[k], 1+dim*i);
+ isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim);
+ isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1));
+ }
+ }
+ return lp;
+}
+
+/* Given a facet "facet" of the convex hull of "set" and a facet "ridge"
+ * of that facet, compute the other facet of the convex hull that contains
+ * the ridge.
+ *
+ * We first transform the set such that the facet constraint becomes
+ *
+ * x_1 >= 0
+ *
+ * I.e., the facet lies in
+ *
+ * x_1 = 0
+ *
+ * and on that facet, the constraint that defines the ridge is
+ *
+ * x_2 >= 0
+ *
+ * (This transformation is not strictly needed, all that is needed is
+ * that the ridge contains the origin.)
+ *
+ * Since the ridge contains the origin, the cone of the convex hull
+ * will be of the form
+ *
+ * x_1 >= 0
+ * x_2 >= a x_1
+ *
+ * with this second constraint defining the new facet.
+ * The constant a is obtained by settting x_1 in the cone of the
+ * convex hull to 1 and minimizing x_2.
+ * Now, each element in the cone of the convex hull is the sum
+ * of elements in the cones of the basic sets.
+ * If a_i is the dilation factor of basic set i, then the problem
+ * we need to solve is
+ *
+ * min \sum_i x_{i,2}
+ * st
+ * \sum_i x_{i,1} = 1
+ * a_i >= 0
+ * [ a_i ]
+ * A [ x_i ] >= 0
+ *
+ * with
+ * [ 1 ]
+ * A_i [ x_i ] >= 0
+ *
+ * the constraints of each (transformed) basic set.
+ * If a = n/d, then the constraint defining the new facet (in the transformed
+ * space) is
+ *
+ * -n x_1 + d x_2 >= 0
+ *
+ * In the original space, we need to take the same combination of the
+ * corresponding constraints "facet" and "ridge".
+ *
+ * If a = -infty = "-1/0", then we just return the original facet constraint.
+ * This means that the facet is unbounded, but has a bounded intersection
+ * with the union of sets.
+ */
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+ isl_int *facet, isl_int *ridge)
+{
+ int i;
+ isl_ctx *ctx;
+ struct isl_mat *T = NULL;
+ struct isl_basic_set *lp = NULL;
+ struct isl_vec *obj;
+ enum isl_lp_result res;
+ isl_int num, den;
+ unsigned dim;
+
+ if (!set)
+ return NULL;
+ ctx = set->ctx;
+ set = isl_set_copy(set);
+ set = isl_set_set_rational(set);
+
+ dim = 1 + isl_set_n_dim(set);
+ T = isl_mat_alloc(ctx, 3, dim);
+ if (!T)
+ goto error;
+ isl_int_set_si(T->row[0][0], 1);
+ isl_seq_clr(T->row[0]+1, dim - 1);
+ isl_seq_cpy(T->row[1], facet, dim);
+ isl_seq_cpy(T->row[2], ridge, dim);
+ T = isl_mat_right_inverse(T);
+ set = isl_set_preimage(set, T);
+ T = NULL;
+ if (!set)
+ goto error;
+ lp = wrap_constraints(set);
+ obj = isl_vec_alloc(ctx, 1 + dim*set->n);
+ if (!obj)
+ goto error;
+ isl_int_set_si(obj->block.data[0], 0);
+ for (i = 0; i < set->n; ++i) {
+ isl_seq_clr(obj->block.data + 1 + dim*i, 2);
+ isl_int_set_si(obj->block.data[1 + dim*i+2], 1);
+ isl_seq_clr(obj->block.data + 1 + dim*i+3, dim-3);
+ }
+ isl_int_init(num);
+ isl_int_init(den);
+ res = isl_basic_set_solve_lp(lp, 0,
+ obj->block.data, ctx->one, &num, &den, NULL);
+ if (res == isl_lp_ok) {
+ isl_int_neg(num, num);
+ isl_seq_combine(facet, num, facet, den, ridge, dim);
+ isl_seq_normalize(ctx, facet, dim);
+ }
+ isl_int_clear(num);
+ isl_int_clear(den);
+ isl_vec_free(obj);
+ isl_basic_set_free(lp);
+ isl_set_free(set);
+ if (res == isl_lp_error)
+ return NULL;
+ isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded,
+ return NULL);
+ return facet;
+error:
+ isl_basic_set_free(lp);
+ isl_mat_free(T);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Compute the constraint of a facet of "set".
+ *
+ * We first compute the intersection with a bounding constraint
+ * that is orthogonal to one of the coordinate axes.
+ * If the affine hull of this intersection has only one equality,
+ * we have found a facet.
+ * Otherwise, we wrap the current bounding constraint around
+ * one of the equalities of the face (one that is not equal to
+ * the current bounding constraint).
+ * This process continues until we have found a facet.
+ * The dimension of the intersection increases by at least
+ * one on each iteration, so termination is guaranteed.
+ */
+static __isl_give isl_mat *initial_facet_constraint(__isl_keep isl_set *set)
+{
+ struct isl_set *slice = NULL;
+ struct isl_basic_set *face = NULL;
+ int i;
+ unsigned dim = isl_set_n_dim(set);
+ int is_bound;
+ isl_mat *bounds = NULL;
+
+ isl_assert(set->ctx, set->n > 0, goto error);
+ bounds = isl_mat_alloc(set->ctx, 1, 1 + dim);
+ if (!bounds)
+ return NULL;
+
+ isl_seq_clr(bounds->row[0], dim);
+ isl_int_set_si(bounds->row[0][1 + dim - 1], 1);
+ is_bound = uset_is_bound(set, bounds->row[0], 1 + dim);
+ if (is_bound < 0)
+ goto error;
+ isl_assert(set->ctx, is_bound, goto error);
+ isl_seq_normalize(set->ctx, bounds->row[0], 1 + dim);
+ bounds->n_row = 1;
+
+ for (;;) {
+ slice = isl_set_copy(set);
+ slice = isl_set_add_basic_set_equality(slice, bounds->row[0]);
+ face = isl_set_affine_hull(slice);
+ if (!face)
+ goto error;
+ if (face->n_eq == 1) {
+ isl_basic_set_free(face);
+ break;
+ }
+ for (i = 0; i < face->n_eq; ++i)
+ if (!isl_seq_eq(bounds->row[0], face->eq[i], 1 + dim) &&
+ !isl_seq_is_neg(bounds->row[0],
+ face->eq[i], 1 + dim))
+ break;
+ isl_assert(set->ctx, i < face->n_eq, goto error);
+ if (!isl_set_wrap_facet(set, bounds->row[0], face->eq[i]))
+ goto error;
+ isl_seq_normalize(set->ctx, bounds->row[0], bounds->n_col);
+ isl_basic_set_free(face);
+ }
+
+ return bounds;
+error:
+ isl_basic_set_free(face);
+ isl_mat_free(bounds);
+ return NULL;
+}
+
+/* Given the bounding constraint "c" of a facet of the convex hull of "set",
+ * compute a hyperplane description of the facet, i.e., compute the facets
+ * of the facet.
+ *
+ * We compute an affine transformation that transforms the constraint
+ *
+ * [ 1 ]
+ * c [ x ] = 0
+ *
+ * to the constraint
+ *
+ * z_1 = 0
+ *
+ * by computing the right inverse U of a matrix that starts with the rows
+ *
+ * [ 1 0 ]
+ * [ c ]
+ *
+ * Then
+ * [ 1 ] [ 1 ]
+ * [ x ] = U [ z ]
+ * and
+ * [ 1 ] [ 1 ]
+ * [ z ] = Q [ x ]
+ *
+ * with Q = U^{-1}
+ * Since z_1 is zero, we can drop this variable as well as the corresponding
+ * column of U to obtain
+ *
+ * [ 1 ] [ 1 ]
+ * [ x ] = U' [ z' ]
+ * and
+ * [ 1 ] [ 1 ]
+ * [ z' ] = Q' [ x ]
+ *
+ * with Q' equal to Q, but without the corresponding row.
+ * After computing the facets of the facet in the z' space,
+ * we convert them back to the x space through Q.
+ */
+static struct isl_basic_set *compute_facet(struct isl_set *set, isl_int *c)
+{
+ struct isl_mat *m, *U, *Q;
+ struct isl_basic_set *facet = NULL;
+ struct isl_ctx *ctx;
+ unsigned dim;
+
+ ctx = set->ctx;
+ set = isl_set_copy(set);
+ dim = isl_set_n_dim(set);
+ m = isl_mat_alloc(set->ctx, 2, 1 + dim);
+ if (!m)
+ goto error;
+ isl_int_set_si(m->row[0][0], 1);
+ isl_seq_clr(m->row[0]+1, dim);
+ isl_seq_cpy(m->row[1], c, 1+dim);
+ U = isl_mat_right_inverse(m);
+ Q = isl_mat_right_inverse(isl_mat_copy(U));
+ U = isl_mat_drop_cols(U, 1, 1);
+ Q = isl_mat_drop_rows(Q, 1, 1);
+ set = isl_set_preimage(set, U);
+ facet = uset_convex_hull_wrap_bounded(set);
+ facet = isl_basic_set_preimage(facet, Q);
+ if (facet)
+ isl_assert(ctx, facet->n_eq == 0, goto error);
+ return facet;
+error:
+ isl_basic_set_free(facet);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Given an initial facet constraint, compute the remaining facets.
+ * We do this by running through all facets found so far and computing
+ * the adjacent facets through wrapping, adding those facets that we
+ * hadn't already found before.
+ *
+ * For each facet we have found so far, we first compute its facets
+ * in the resulting convex hull. That is, we compute the ridges
+ * of the resulting convex hull contained in the facet.
+ * We also compute the corresponding facet in the current approximation
+ * of the convex hull. There is no need to wrap around the ridges
+ * in this facet since that would result in a facet that is already
+ * present in the current approximation.
+ *
+ * This function can still be significantly optimized by checking which of
+ * the facets of the basic sets are also facets of the convex hull and
+ * using all the facets so far to help in constructing the facets of the
+ * facets
+ * and/or
+ * using the technique in section "3.1 Ridge Generation" of
+ * "Extended Convex Hull" by Fukuda et al.
+ */
+static struct isl_basic_set *extend(struct isl_basic_set *hull,
+ struct isl_set *set)
+{
+ int i, j, f;
+ int k;
+ struct isl_basic_set *facet = NULL;
+ struct isl_basic_set *hull_facet = NULL;
+ unsigned dim;
+
+ if (!hull)
+ return NULL;
+
+ isl_assert(set->ctx, set->n > 0, goto error);
+
+ dim = isl_set_n_dim(set);
+
+ for (i = 0; i < hull->n_ineq; ++i) {
+ facet = compute_facet(set, hull->ineq[i]);
+ facet = isl_basic_set_add_equality(facet, hull->ineq[i]);
+ facet = isl_basic_set_gauss(facet, NULL);
+ facet = isl_basic_set_normalize_constraints(facet);
+ hull_facet = isl_basic_set_copy(hull);
+ hull_facet = isl_basic_set_add_equality(hull_facet, hull->ineq[i]);
+ hull_facet = isl_basic_set_gauss(hull_facet, NULL);
+ hull_facet = isl_basic_set_normalize_constraints(hull_facet);
+ if (!facet || !hull_facet)
+ goto error;
+ hull = isl_basic_set_cow(hull);
+ hull = isl_basic_set_extend_space(hull,
+ isl_space_copy(hull->dim), 0, 0, facet->n_ineq);
+ if (!hull)
+ goto error;
+ for (j = 0; j < facet->n_ineq; ++j) {
+ for (f = 0; f < hull_facet->n_ineq; ++f)
+ if (isl_seq_eq(facet->ineq[j],
+ hull_facet->ineq[f], 1 + dim))
+ break;
+ if (f < hull_facet->n_ineq)
+ continue;
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim);
+ if (!isl_set_wrap_facet(set, hull->ineq[k], facet->ineq[j]))
+ goto error;
+ }
+ isl_basic_set_free(hull_facet);
+ isl_basic_set_free(facet);
+ }
+ hull = isl_basic_set_simplify(hull);
+ hull = isl_basic_set_finalize(hull);
+ return hull;
+error:
+ isl_basic_set_free(hull_facet);
+ isl_basic_set_free(facet);
+ isl_basic_set_free(hull);
+ return NULL;
+}
+
+/* Special case for computing the convex hull of a one dimensional set.
+ * We simply collect the lower and upper bounds of each basic set
+ * and the biggest of those.
+ */
+static struct isl_basic_set *convex_hull_1d(struct isl_set *set)
+{
+ struct isl_mat *c = NULL;
+ isl_int *lower = NULL;
+ isl_int *upper = NULL;
+ int i, j, k;
+ isl_int a, b;
+ struct isl_basic_set *hull;
+
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_simplify(set->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+ set = isl_set_remove_empty_parts(set);
+ if (!set)
+ goto error;
+ isl_assert(set->ctx, set->n > 0, goto error);
+ c = isl_mat_alloc(set->ctx, 2, 2);
+ if (!c)
+ goto error;
+
+ if (set->p[0]->n_eq > 0) {
+ isl_assert(set->ctx, set->p[0]->n_eq == 1, goto error);
+ lower = c->row[0];
+ upper = c->row[1];
+ if (isl_int_is_pos(set->p[0]->eq[0][1])) {
+ isl_seq_cpy(lower, set->p[0]->eq[0], 2);
+ isl_seq_neg(upper, set->p[0]->eq[0], 2);
+ } else {
+ isl_seq_neg(lower, set->p[0]->eq[0], 2);
+ isl_seq_cpy(upper, set->p[0]->eq[0], 2);
+ }
+ } else {
+ for (j = 0; j < set->p[0]->n_ineq; ++j) {
+ if (isl_int_is_pos(set->p[0]->ineq[j][1])) {
+ lower = c->row[0];
+ isl_seq_cpy(lower, set->p[0]->ineq[j], 2);
+ } else {
+ upper = c->row[1];
+ isl_seq_cpy(upper, set->p[0]->ineq[j], 2);
+ }
+ }
+ }
+
+ isl_int_init(a);
+ isl_int_init(b);
+ for (i = 0; i < set->n; ++i) {
+ struct isl_basic_set *bset = set->p[i];
+ int has_lower = 0;
+ int has_upper = 0;
+
+ for (j = 0; j < bset->n_eq; ++j) {
+ has_lower = 1;
+ has_upper = 1;
+ if (lower) {
+ isl_int_mul(a, lower[0], bset->eq[j][1]);
+ isl_int_mul(b, lower[1], bset->eq[j][0]);
+ if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+ isl_seq_cpy(lower, bset->eq[j], 2);
+ if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+ isl_seq_neg(lower, bset->eq[j], 2);
+ }
+ if (upper) {
+ isl_int_mul(a, upper[0], bset->eq[j][1]);
+ isl_int_mul(b, upper[1], bset->eq[j][0]);
+ if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+ isl_seq_neg(upper, bset->eq[j], 2);
+ if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+ isl_seq_cpy(upper, bset->eq[j], 2);
+ }
+ }
+ for (j = 0; j < bset->n_ineq; ++j) {
+ if (isl_int_is_pos(bset->ineq[j][1]))
+ has_lower = 1;
+ if (isl_int_is_neg(bset->ineq[j][1]))
+ has_upper = 1;
+ if (lower && isl_int_is_pos(bset->ineq[j][1])) {
+ isl_int_mul(a, lower[0], bset->ineq[j][1]);
+ isl_int_mul(b, lower[1], bset->ineq[j][0]);
+ if (isl_int_lt(a, b))
+ isl_seq_cpy(lower, bset->ineq[j], 2);
+ }
+ if (upper && isl_int_is_neg(bset->ineq[j][1])) {
+ isl_int_mul(a, upper[0], bset->ineq[j][1]);
+ isl_int_mul(b, upper[1], bset->ineq[j][0]);
+ if (isl_int_gt(a, b))
+ isl_seq_cpy(upper, bset->ineq[j], 2);
+ }
+ }
+ if (!has_lower)
+ lower = NULL;
+ if (!has_upper)
+ upper = NULL;
+ }
+ isl_int_clear(a);
+ isl_int_clear(b);
+
+ hull = isl_basic_set_alloc(set->ctx, 0, 1, 0, 0, 2);
+ hull = isl_basic_set_set_rational(hull);
+ if (!hull)
+ goto error;
+ if (lower) {
+ k = isl_basic_set_alloc_inequality(hull);
+ isl_seq_cpy(hull->ineq[k], lower, 2);
+ }
+ if (upper) {
+ k = isl_basic_set_alloc_inequality(hull);
+ isl_seq_cpy(hull->ineq[k], upper, 2);
+ }
+ hull = isl_basic_set_finalize(hull);
+ isl_set_free(set);
+ isl_mat_free(c);
+ return hull;
+error:
+ isl_set_free(set);
+ isl_mat_free(c);
+ return NULL;
+}
+
+static struct isl_basic_set *convex_hull_0d(struct isl_set *set)
+{
+ struct isl_basic_set *convex_hull;
+
+ if (!set)
+ return NULL;
+
+ if (isl_set_is_empty(set))
+ convex_hull = isl_basic_set_empty(isl_space_copy(set->dim));
+ else
+ convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+ isl_set_free(set);
+ return convex_hull;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions using Fourier-Motzkin elimination.
+ * The convex hull is the set of all points that can be written as
+ * the sum of points from both basic sets (in homogeneous coordinates).
+ * We set up the constraints in a space with dimensions for each of
+ * the three sets and then project out the dimensions corresponding
+ * to the two original basic sets, retaining only those corresponding
+ * to the convex hull.
+ */
+static struct isl_basic_set *convex_hull_pair_elim(struct isl_basic_set *bset1,
+ struct isl_basic_set *bset2)
+{
+ int i, j, k;
+ struct isl_basic_set *bset[2];
+ struct isl_basic_set *hull = NULL;
+ unsigned dim;
+
+ if (!bset1 || !bset2)
+ goto error;
+
+ dim = isl_basic_set_n_dim(bset1);
+ hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0,
+ 1 + dim + bset1->n_eq + bset2->n_eq,
+ 2 + bset1->n_ineq + bset2->n_ineq);
+ bset[0] = bset1;
+ bset[1] = bset2;
+ for (i = 0; i < 2; ++i) {
+ for (j = 0; j < bset[i]->n_eq; ++j) {
+ k = isl_basic_set_alloc_equality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(hull->eq[k], (i+1) * (1+dim));
+ isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+ isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j],
+ 1+dim);
+ }
+ for (j = 0; j < bset[i]->n_ineq; ++j) {
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(hull->ineq[k], (i+1) * (1+dim));
+ isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+ isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim),
+ bset[i]->ineq[j], 1+dim);
+ }
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(hull->ineq[k], 1+2+3*dim);
+ isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1);
+ }
+ for (j = 0; j < 1+dim; ++j) {
+ k = isl_basic_set_alloc_equality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(hull->eq[k], 1+2+3*dim);
+ isl_int_set_si(hull->eq[k][j], -1);
+ isl_int_set_si(hull->eq[k][1+dim+j], 1);
+ isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1);
+ }
+ hull = isl_basic_set_set_rational(hull);
+ hull = isl_basic_set_remove_dims(hull, isl_dim_set, dim, 2*(1+dim));
+ hull = isl_basic_set_remove_redundancies(hull);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return hull;
+error:
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ isl_basic_set_free(hull);
+ return NULL;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+int isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
+{
+ struct isl_tab *tab;
+ int bounded;
+
+ if (!bset)
+ return -1;
+ if (isl_basic_set_plain_is_empty(bset))
+ return 1;
+
+ tab = isl_tab_from_recession_cone(bset, 1);
+ bounded = isl_tab_cone_is_bounded(tab);
+ isl_tab_free(tab);
+ return bounded;
+}
+
+/* Is the image bounded for each value of the parameters and
+ * the domain variables?
+ */
+int isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap)
+{
+ unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in);
+ int bounded;
+
+ bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_move_dims(bmap, isl_dim_param, nparam,
+ isl_dim_in, 0, n_in);
+ bounded = isl_basic_set_is_bounded((isl_basic_set *)bmap);
+ isl_basic_map_free(bmap);
+
+ return bounded;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+int isl_set_is_bounded(__isl_keep isl_set *set)
+{
+ int i;
+
+ if (!set)
+ return -1;
+
+ for (i = 0; i < set->n; ++i) {
+ int bounded = isl_basic_set_is_bounded(set->p[i]);
+ if (!bounded || bounded < 0)
+ return bounded;
+ }
+ return 1;
+}
+
+/* Compute the lineality space of the convex hull of bset1 and bset2.
+ *
+ * We first compute the intersection of the recession cone of bset1
+ * with the negative of the recession cone of bset2 and then compute
+ * the linear hull of the resulting cone.
+ */
+static struct isl_basic_set *induced_lineality_space(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ int i, k;
+ struct isl_basic_set *lin = NULL;
+ unsigned dim;
+
+ if (!bset1 || !bset2)
+ goto error;
+
+ dim = isl_basic_set_total_dim(bset1);
+ lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset1), 0,
+ bset1->n_eq + bset2->n_eq,
+ bset1->n_ineq + bset2->n_ineq);
+ lin = isl_basic_set_set_rational(lin);
+ if (!lin)
+ goto error;
+ for (i = 0; i < bset1->n_eq; ++i) {
+ k = isl_basic_set_alloc_equality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->eq[k][0], 0);
+ isl_seq_cpy(lin->eq[k] + 1, bset1->eq[i] + 1, dim);
+ }
+ for (i = 0; i < bset1->n_ineq; ++i) {
+ k = isl_basic_set_alloc_inequality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->ineq[k][0], 0);
+ isl_seq_cpy(lin->ineq[k] + 1, bset1->ineq[i] + 1, dim);
+ }
+ for (i = 0; i < bset2->n_eq; ++i) {
+ k = isl_basic_set_alloc_equality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->eq[k][0], 0);
+ isl_seq_neg(lin->eq[k] + 1, bset2->eq[i] + 1, dim);
+ }
+ for (i = 0; i < bset2->n_ineq; ++i) {
+ k = isl_basic_set_alloc_inequality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->ineq[k][0], 0);
+ isl_seq_neg(lin->ineq[k] + 1, bset2->ineq[i] + 1, dim);
+ }
+
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return isl_basic_set_affine_hull(lin);
+error:
+ isl_basic_set_free(lin);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return NULL;
+}
+
+static struct isl_basic_set *uset_convex_hull(struct isl_set *set);
+
+/* Given a set and a linear space "lin" of dimension n > 0,
+ * project the linear space from the set, compute the convex hull
+ * and then map the set back to the original space.
+ *
+ * Let
+ *
+ * M x = 0
+ *
+ * describe the linear space. We first compute the Hermite normal
+ * form H = M U of M = H Q, to obtain
+ *
+ * H Q x = 0
+ *
+ * The last n rows of H will be zero, so the last n variables of x' = Q x
+ * are the one we want to project out. We do this by transforming each
+ * basic set A x >= b to A U x' >= b and then removing the last n dimensions.
+ * After computing the convex hull in x'_1, i.e., A' x'_1 >= b',
+ * we transform the hull back to the original space as A' Q_1 x >= b',
+ * with Q_1 all but the last n rows of Q.
+ */
+static struct isl_basic_set *modulo_lineality(struct isl_set *set,
+ struct isl_basic_set *lin)
+{
+ unsigned total = isl_basic_set_total_dim(lin);
+ unsigned lin_dim;
+ struct isl_basic_set *hull;
+ struct isl_mat *M, *U, *Q;
+
+ if (!set || !lin)
+ goto error;
+ lin_dim = total - lin->n_eq;
+ M = isl_mat_sub_alloc6(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
+ M = isl_mat_left_hermite(M, 0, &U, &Q);
+ if (!M)
+ goto error;
+ isl_mat_free(M);
+ isl_basic_set_free(lin);
+
+ Q = isl_mat_drop_rows(Q, Q->n_row - lin_dim, lin_dim);
+
+ U = isl_mat_lin_to_aff(U);
+ Q = isl_mat_lin_to_aff(Q);
+
+ set = isl_set_preimage(set, U);
+ set = isl_set_remove_dims(set, isl_dim_set, total - lin_dim, lin_dim);
+ hull = uset_convex_hull(set);
+ hull = isl_basic_set_preimage(hull, Q);
+
+ return hull;
+error:
+ isl_basic_set_free(lin);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Given two polyhedra with as constraints h_{ij} x >= 0 in homegeneous space,
+ * set up an LP for solving
+ *
+ * \sum_j \alpha_{1j} h_{1j} = \sum_j \alpha_{2j} h_{2j}
+ *
+ * \alpha{i0} corresponds to the (implicit) positivity constraint 1 >= 0
+ * The next \alpha{ij} correspond to the equalities and come in pairs.
+ * The final \alpha{ij} correspond to the inequalities.
+ */
+static struct isl_basic_set *valid_direction_lp(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ isl_space *dim;
+ struct isl_basic_set *lp;
+ unsigned d;
+ int n;
+ int i, j, k;
+
+ if (!bset1 || !bset2)
+ goto error;
+ d = 1 + isl_basic_set_total_dim(bset1);
+ n = 2 +
+ 2 * bset1->n_eq + bset1->n_ineq + 2 * bset2->n_eq + bset2->n_ineq;
+ dim = isl_space_set_alloc(bset1->ctx, 0, n);
+ lp = isl_basic_set_alloc_space(dim, 0, d, n);
+ if (!lp)
+ goto error;
+ for (i = 0; i < n; ++i) {
+ k = isl_basic_set_alloc_inequality(lp);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(lp->ineq[k] + 1, n);
+ isl_int_set_si(lp->ineq[k][0], -1);
+ isl_int_set_si(lp->ineq[k][1 + i], 1);
+ }
+ for (i = 0; i < d; ++i) {
+ k = isl_basic_set_alloc_equality(lp);
+ if (k < 0)
+ goto error;
+ n = 0;
+ isl_int_set_si(lp->eq[k][n], 0); n++;
+ /* positivity constraint 1 >= 0 */
+ isl_int_set_si(lp->eq[k][n], i == 0); n++;
+ for (j = 0; j < bset1->n_eq; ++j) {
+ isl_int_set(lp->eq[k][n], bset1->eq[j][i]); n++;
+ isl_int_neg(lp->eq[k][n], bset1->eq[j][i]); n++;
+ }
+ for (j = 0; j < bset1->n_ineq; ++j) {
+ isl_int_set(lp->eq[k][n], bset1->ineq[j][i]); n++;
+ }
+ /* positivity constraint 1 >= 0 */
+ isl_int_set_si(lp->eq[k][n], -(i == 0)); n++;
+ for (j = 0; j < bset2->n_eq; ++j) {
+ isl_int_neg(lp->eq[k][n], bset2->eq[j][i]); n++;
+ isl_int_set(lp->eq[k][n], bset2->eq[j][i]); n++;
+ }
+ for (j = 0; j < bset2->n_ineq; ++j) {
+ isl_int_neg(lp->eq[k][n], bset2->ineq[j][i]); n++;
+ }
+ }
+ lp = isl_basic_set_gauss(lp, NULL);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return lp;
+error:
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return NULL;
+}
+
+/* Compute a vector s in the homogeneous space such that <s, r> > 0
+ * for all rays in the homogeneous space of the two cones that correspond
+ * to the input polyhedra bset1 and bset2.
+ *
+ * We compute s as a vector that satisfies
+ *
+ * s = \sum_j \alpha_{ij} h_{ij} for i = 1,2 (*)
+ *
+ * with h_{ij} the normals of the facets of polyhedron i
+ * (including the "positivity constraint" 1 >= 0) and \alpha_{ij}
+ * strictly positive numbers. For simplicity we impose \alpha_{ij} >= 1.
+ * We first set up an LP with as variables the \alpha{ij}.
+ * In this formulation, for each polyhedron i,
+ * the first constraint is the positivity constraint, followed by pairs
+ * of variables for the equalities, followed by variables for the inequalities.
+ * We then simply pick a feasible solution and compute s using (*).
+ *
+ * Note that we simply pick any valid direction and make no attempt
+ * to pick a "good" or even the "best" valid direction.
+ */
+static struct isl_vec *valid_direction(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ struct isl_basic_set *lp;
+ struct isl_tab *tab;
+ struct isl_vec *sample = NULL;
+ struct isl_vec *dir;
+ unsigned d;
+ int i;
+ int n;
+
+ if (!bset1 || !bset2)
+ goto error;
+ lp = valid_direction_lp(isl_basic_set_copy(bset1),
+ isl_basic_set_copy(bset2));
+ tab = isl_tab_from_basic_set(lp, 0);
+ sample = isl_tab_get_sample_value(tab);
+ isl_tab_free(tab);
+ isl_basic_set_free(lp);
+ if (!sample)
+ goto error;
+ d = isl_basic_set_total_dim(bset1);
+ dir = isl_vec_alloc(bset1->ctx, 1 + d);
+ if (!dir)
+ goto error;
+ isl_seq_clr(dir->block.data + 1, dir->size - 1);
+ n = 1;
+ /* positivity constraint 1 >= 0 */
+ isl_int_set(dir->block.data[0], sample->block.data[n]); n++;
+ for (i = 0; i < bset1->n_eq; ++i) {
+ isl_int_sub(sample->block.data[n],
+ sample->block.data[n], sample->block.data[n+1]);
+ isl_seq_combine(dir->block.data,
+ bset1->ctx->one, dir->block.data,
+ sample->block.data[n], bset1->eq[i], 1 + d);
+
+ n += 2;
+ }
+ for (i = 0; i < bset1->n_ineq; ++i)
+ isl_seq_combine(dir->block.data,
+ bset1->ctx->one, dir->block.data,
+ sample->block.data[n++], bset1->ineq[i], 1 + d);
+ isl_vec_free(sample);
+ isl_seq_normalize(bset1->ctx, dir->el, dir->size);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return dir;
+error:
+ isl_vec_free(sample);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return NULL;
+}
+
+/* Given a polyhedron b_i + A_i x >= 0 and a map T = S^{-1},
+ * compute b_i' + A_i' x' >= 0, with
+ *
+ * [ b_i A_i ] [ y' ] [ y' ]
+ * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0
+ *
+ * In particular, add the "positivity constraint" and then perform
+ * the mapping.
+ */
+static struct isl_basic_set *homogeneous_map(struct isl_basic_set *bset,
+ struct isl_mat *T)
+{
+ int k;
+
+ if (!bset)
+ goto error;
+ bset = isl_basic_set_extend_constraints(bset, 0, 1);
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bset->ineq[k] + 1, isl_basic_set_total_dim(bset));
+ isl_int_set_si(bset->ineq[k][0], 1);
+ bset = isl_basic_set_preimage(bset, T);
+ return bset;
+error:
+ isl_mat_free(T);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions, where the convex hull is known to be pointed,
+ * but the basic sets may be unbounded.
+ *
+ * We turn this problem into the computation of a convex hull of a pair
+ * _bounded_ polyhedra by "changing the direction of the homogeneous
+ * dimension". This idea is due to Matthias Koeppe.
+ *
+ * Consider the cones in homogeneous space that correspond to the
+ * input polyhedra. The rays of these cones are also rays of the
+ * polyhedra if the coordinate that corresponds to the homogeneous
+ * dimension is zero. That is, if the inner product of the rays
+ * with the homogeneous direction is zero.
+ * The cones in the homogeneous space can also be considered to
+ * correspond to other pairs of polyhedra by chosing a different
+ * homogeneous direction. To ensure that both of these polyhedra
+ * are bounded, we need to make sure that all rays of the cones
+ * correspond to vertices and not to rays.
+ * Let s be a direction such that <s, r> > 0 for all rays r of both cones.
+ * Then using s as a homogeneous direction, we obtain a pair of polytopes.
+ * The vector s is computed in valid_direction.
+ *
+ * Note that we need to consider _all_ rays of the cones and not just
+ * the rays that correspond to rays in the polyhedra. If we were to
+ * only consider those rays and turn them into vertices, then we
+ * may inadvertently turn some vertices into rays.
+ *
+ * The standard homogeneous direction is the unit vector in the 0th coordinate.
+ * We therefore transform the two polyhedra such that the selected
+ * direction is mapped onto this standard direction and then proceed
+ * with the normal computation.
+ * Let S be a non-singular square matrix with s as its first row,
+ * then we want to map the polyhedra to the space
+ *
+ * [ y' ] [ y ] [ y ] [ y' ]
+ * [ x' ] = S [ x ] i.e., [ x ] = S^{-1} [ x' ]
+ *
+ * We take S to be the unimodular completion of s to limit the growth
+ * of the coefficients in the following computations.
+ *
+ * Let b_i + A_i x >= 0 be the constraints of polyhedron i.
+ * We first move to the homogeneous dimension
+ *
+ * b_i y + A_i x >= 0 [ b_i A_i ] [ y ] [ 0 ]
+ * y >= 0 or [ 1 0 ] [ x ] >= [ 0 ]
+ *
+ * Then we change directoin
+ *
+ * [ b_i A_i ] [ y' ] [ y' ]
+ * [ 1 0 ] S^{-1} [ x' ] >= 0 or [ b_i' A_i' ] [ x' ] >= 0
+ *
+ * Then we compute the convex hull of the polytopes b_i' + A_i' x' >= 0
+ * resulting in b' + A' x' >= 0, which we then convert back
+ *
+ * [ y ] [ y ]
+ * [ b' A' ] S [ x ] >= 0 or [ b A ] [ x ] >= 0
+ *
+ * The polyhedron b + A x >= 0 is then the convex hull of the input polyhedra.
+ */
+static struct isl_basic_set *convex_hull_pair_pointed(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ struct isl_ctx *ctx = NULL;
+ struct isl_vec *dir = NULL;
+ struct isl_mat *T = NULL;
+ struct isl_mat *T2 = NULL;
+ struct isl_basic_set *hull;
+ struct isl_set *set;
+
+ if (!bset1 || !bset2)
+ goto error;
+ ctx = bset1->ctx;
+ dir = valid_direction(isl_basic_set_copy(bset1),
+ isl_basic_set_copy(bset2));
+ if (!dir)
+ goto error;
+ T = isl_mat_alloc(bset1->ctx, dir->size, dir->size);
+ if (!T)
+ goto error;
+ isl_seq_cpy(T->row[0], dir->block.data, dir->size);
+ T = isl_mat_unimodular_complete(T, 1);
+ T2 = isl_mat_right_inverse(isl_mat_copy(T));
+
+ bset1 = homogeneous_map(bset1, isl_mat_copy(T2));
+ bset2 = homogeneous_map(bset2, T2);
+ set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+ set = isl_set_add_basic_set(set, bset1);
+ set = isl_set_add_basic_set(set, bset2);
+ hull = uset_convex_hull(set);
+ hull = isl_basic_set_preimage(hull, T);
+
+ isl_vec_free(dir);
+
+ return hull;
+error:
+ isl_vec_free(dir);
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return NULL;
+}
+
+static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set);
+static struct isl_basic_set *modulo_affine_hull(
+ struct isl_set *set, struct isl_basic_set *affine_hull);
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions.
+ *
+ * This function is called from uset_convex_hull_unbounded, which
+ * means that the complete convex hull is unbounded. Some pairs
+ * of basic sets may still be bounded, though.
+ * They may even lie inside a lower dimensional space, in which
+ * case they need to be handled inside their affine hull since
+ * the main algorithm assumes that the result is full-dimensional.
+ *
+ * If the convex hull of the two basic sets would have a non-trivial
+ * lineality space, we first project out this lineality space.
+ */
+static struct isl_basic_set *convex_hull_pair(struct isl_basic_set *bset1,
+ struct isl_basic_set *bset2)
+{
+ isl_basic_set *lin, *aff;
+ int bounded1, bounded2;
+
+ if (bset1->ctx->opt->convex == ISL_CONVEX_HULL_FM)
+ return convex_hull_pair_elim(bset1, bset2);
+
+ aff = isl_set_affine_hull(isl_basic_set_union(isl_basic_set_copy(bset1),
+ isl_basic_set_copy(bset2)));
+ if (!aff)
+ goto error;
+ if (aff->n_eq != 0)
+ return modulo_affine_hull(isl_basic_set_union(bset1, bset2), aff);
+ isl_basic_set_free(aff);
+
+ bounded1 = isl_basic_set_is_bounded(bset1);
+ bounded2 = isl_basic_set_is_bounded(bset2);
+
+ if (bounded1 < 0 || bounded2 < 0)
+ goto error;
+
+ if (bounded1 && bounded2)
+ return uset_convex_hull_wrap(isl_basic_set_union(bset1, bset2));
+
+ if (bounded1 || bounded2)
+ return convex_hull_pair_pointed(bset1, bset2);
+
+ lin = induced_lineality_space(isl_basic_set_copy(bset1),
+ isl_basic_set_copy(bset2));
+ if (!lin)
+ goto error;
+ if (isl_basic_set_is_universe(lin)) {
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return lin;
+ }
+ if (lin->n_eq < isl_basic_set_total_dim(lin)) {
+ struct isl_set *set;
+ set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+ set = isl_set_add_basic_set(set, bset1);
+ set = isl_set_add_basic_set(set, bset2);
+ return modulo_lineality(set, lin);
+ }
+ isl_basic_set_free(lin);
+
+ return convex_hull_pair_pointed(bset1, bset2);
+error:
+ isl_basic_set_free(bset1);
+ isl_basic_set_free(bset2);
+ return NULL;
+}
+
+/* Compute the lineality space of a basic set.
+ * We currently do not allow the basic set to have any divs.
+ * We basically just drop the constants and turn every inequality
+ * into an equality.
+ */
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset)
+{
+ int i, k;
+ struct isl_basic_set *lin = NULL;
+ unsigned dim;
+
+ if (!bset)
+ goto error;
+ isl_assert(bset->ctx, bset->n_div == 0, goto error);
+ dim = isl_basic_set_total_dim(bset);
+
+ lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), 0, dim, 0);
+ if (!lin)
+ goto error;
+ for (i = 0; i < bset->n_eq; ++i) {
+ k = isl_basic_set_alloc_equality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->eq[k][0], 0);
+ isl_seq_cpy(lin->eq[k] + 1, bset->eq[i] + 1, dim);
+ }
+ lin = isl_basic_set_gauss(lin, NULL);
+ if (!lin)
+ goto error;
+ for (i = 0; i < bset->n_ineq && lin->n_eq < dim; ++i) {
+ k = isl_basic_set_alloc_equality(lin);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(lin->eq[k][0], 0);
+ isl_seq_cpy(lin->eq[k] + 1, bset->ineq[i] + 1, dim);
+ lin = isl_basic_set_gauss(lin, NULL);
+ if (!lin)
+ goto error;
+ }
+ isl_basic_set_free(bset);
+ return lin;
+error:
+ isl_basic_set_free(lin);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Compute the (linear) hull of the lineality spaces of the basic sets in the
+ * "underlying" set "set".
+ */
+static struct isl_basic_set *uset_combined_lineality_space(struct isl_set *set)
+{
+ int i;
+ struct isl_set *lin = NULL;
+
+ if (!set)
+ return NULL;
+ if (set->n == 0) {
+ isl_space *dim = isl_set_get_space(set);
+ isl_set_free(set);
+ return isl_basic_set_empty(dim);
+ }
+
+ lin = isl_set_alloc_space(isl_set_get_space(set), set->n, 0);
+ for (i = 0; i < set->n; ++i)
+ lin = isl_set_add_basic_set(lin,
+ isl_basic_set_lineality_space(isl_basic_set_copy(set->p[i])));
+ isl_set_free(set);
+ return isl_set_affine_hull(lin);
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions.
+ * In each step, we combined two basic sets until only one
+ * basic set is left.
+ * The input basic sets are assumed not to have a non-trivial
+ * lineality space. If any of the intermediate results has
+ * a non-trivial lineality space, it is projected out.
+ */
+static struct isl_basic_set *uset_convex_hull_unbounded(struct isl_set *set)
+{
+ struct isl_basic_set *convex_hull = NULL;
+
+ convex_hull = isl_set_copy_basic_set(set);
+ set = isl_set_drop_basic_set(set, convex_hull);
+ if (!set)
+ goto error;
+ while (set->n > 0) {
+ struct isl_basic_set *t;
+ t = isl_set_copy_basic_set(set);
+ if (!t)
+ goto error;
+ set = isl_set_drop_basic_set(set, t);
+ if (!set)
+ goto error;
+ convex_hull = convex_hull_pair(convex_hull, t);
+ if (set->n == 0)
+ break;
+ t = isl_basic_set_lineality_space(isl_basic_set_copy(convex_hull));
+ if (!t)
+ goto error;
+ if (isl_basic_set_is_universe(t)) {
+ isl_basic_set_free(convex_hull);
+ convex_hull = t;
+ break;
+ }
+ if (t->n_eq < isl_basic_set_total_dim(t)) {
+ set = isl_set_add_basic_set(set, convex_hull);
+ return modulo_lineality(set, t);
+ }
+ isl_basic_set_free(t);
+ }
+ isl_set_free(set);
+ return convex_hull;
+error:
+ isl_set_free(set);
+ isl_basic_set_free(convex_hull);
+ return NULL;
+}
+
+/* Compute an initial hull for wrapping containing a single initial
+ * facet.
+ * This function assumes that the given set is bounded.
+ */
+static struct isl_basic_set *initial_hull(struct isl_basic_set *hull,
+ struct isl_set *set)
+{
+ struct isl_mat *bounds = NULL;
+ unsigned dim;
+ int k;
+
+ if (!hull)
+ goto error;
+ bounds = initial_facet_constraint(set);
+ if (!bounds)
+ goto error;
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ goto error;
+ dim = isl_set_n_dim(set);
+ isl_assert(set->ctx, 1 + dim == bounds->n_col, goto error);
+ isl_seq_cpy(hull->ineq[k], bounds->row[0], bounds->n_col);
+ isl_mat_free(bounds);
+
+ return hull;
+error:
+ isl_basic_set_free(hull);
+ isl_mat_free(bounds);
+ return NULL;
+}
+
+struct max_constraint {
+ struct isl_mat *c;
+ int count;
+ int ineq;
+};
+
+static int max_constraint_equal(const void *entry, const void *val)
+{
+ struct max_constraint *a = (struct max_constraint *)entry;
+ isl_int *b = (isl_int *)val;
+
+ return isl_seq_eq(a->c->row[0] + 1, b, a->c->n_col - 1);
+}
+
+static void update_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+ isl_int *con, unsigned len, int n, int ineq)
+{
+ struct isl_hash_table_entry *entry;
+ struct max_constraint *c;
+ uint32_t c_hash;
+
+ c_hash = isl_seq_get_hash(con + 1, len);
+ entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+ con + 1, 0);
+ if (!entry)
+ return;
+ c = entry->data;
+ if (c->count < n) {
+ isl_hash_table_remove(ctx, table, entry);
+ return;
+ }
+ c->count++;
+ if (isl_int_gt(c->c->row[0][0], con[0]))
+ return;
+ if (isl_int_eq(c->c->row[0][0], con[0])) {
+ if (ineq)
+ c->ineq = ineq;
+ return;
+ }
+ c->c = isl_mat_cow(c->c);
+ isl_int_set(c->c->row[0][0], con[0]);
+ c->ineq = ineq;
+}
+
+/* Check whether the constraint hash table "table" constains the constraint
+ * "con".
+ */
+static int has_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+ isl_int *con, unsigned len, int n)
+{
+ struct isl_hash_table_entry *entry;
+ struct max_constraint *c;
+ uint32_t c_hash;
+
+ c_hash = isl_seq_get_hash(con + 1, len);
+ entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+ con + 1, 0);
+ if (!entry)
+ return 0;
+ c = entry->data;
+ if (c->count < n)
+ return 0;
+ return isl_int_eq(c->c->row[0][0], con[0]);
+}
+
+/* Check for inequality constraints of a basic set without equalities
+ * such that the same or more stringent copies of the constraint appear
+ * in all of the basic sets. Such constraints are necessarily facet
+ * constraints of the convex hull.
+ *
+ * If the resulting basic set is by chance identical to one of
+ * the basic sets in "set", then we know that this basic set contains
+ * all other basic sets and is therefore the convex hull of set.
+ * In this case we set *is_hull to 1.
+ */
+static struct isl_basic_set *common_constraints(struct isl_basic_set *hull,
+ struct isl_set *set, int *is_hull)
+{
+ int i, j, s, n;
+ int min_constraints;
+ int best;
+ struct max_constraint *constraints = NULL;
+ struct isl_hash_table *table = NULL;
+ unsigned total;
+
+ *is_hull = 0;
+
+ for (i = 0; i < set->n; ++i)
+ if (set->p[i]->n_eq == 0)
+ break;
+ if (i >= set->n)
+ return hull;
+ min_constraints = set->p[i]->n_ineq;
+ best = i;
+ for (i = best + 1; i < set->n; ++i) {
+ if (set->p[i]->n_eq != 0)
+ continue;
+ if (set->p[i]->n_ineq >= min_constraints)
+ continue;
+ min_constraints = set->p[i]->n_ineq;
+ best = i;
+ }
+ constraints = isl_calloc_array(hull->ctx, struct max_constraint,
+ min_constraints);
+ if (!constraints)
+ return hull;
+ table = isl_alloc_type(hull->ctx, struct isl_hash_table);
+ if (isl_hash_table_init(hull->ctx, table, min_constraints))
+ goto error;
+
+ total = isl_space_dim(set->dim, isl_dim_all);
+ for (i = 0; i < set->p[best]->n_ineq; ++i) {
+ constraints[i].c = isl_mat_sub_alloc6(hull->ctx,
+ set->p[best]->ineq + i, 0, 1, 0, 1 + total);
+ if (!constraints[i].c)
+ goto error;
+ constraints[i].ineq = 1;
+ }
+ for (i = 0; i < min_constraints; ++i) {
+ struct isl_hash_table_entry *entry;
+ uint32_t c_hash;
+ c_hash = isl_seq_get_hash(constraints[i].c->row[0] + 1, total);
+ entry = isl_hash_table_find(hull->ctx, table, c_hash,
+ max_constraint_equal, constraints[i].c->row[0] + 1, 1);
+ if (!entry)
+ goto error;
+ isl_assert(hull->ctx, !entry->data, goto error);
+ entry->data = &constraints[i];
+ }
+
+ n = 0;
+ for (s = 0; s < set->n; ++s) {
+ if (s == best)
+ continue;
+
+ for (i = 0; i < set->p[s]->n_eq; ++i) {
+ isl_int *eq = set->p[s]->eq[i];
+ for (j = 0; j < 2; ++j) {
+ isl_seq_neg(eq, eq, 1 + total);
+ update_constraint(hull->ctx, table,
+ eq, total, n, 0);
+ }
+ }
+ for (i = 0; i < set->p[s]->n_ineq; ++i) {
+ isl_int *ineq = set->p[s]->ineq[i];
+ update_constraint(hull->ctx, table, ineq, total, n,
+ set->p[s]->n_eq == 0);
+ }
+ ++n;
+ }
+
+ for (i = 0; i < min_constraints; ++i) {
+ if (constraints[i].count < n)
+ continue;
+ if (!constraints[i].ineq)
+ continue;
+ j = isl_basic_set_alloc_inequality(hull);
+ if (j < 0)
+ goto error;
+ isl_seq_cpy(hull->ineq[j], constraints[i].c->row[0], 1 + total);
+ }
+
+ for (s = 0; s < set->n; ++s) {
+ if (set->p[s]->n_eq)
+ continue;
+ if (set->p[s]->n_ineq != hull->n_ineq)
+ continue;
+ for (i = 0; i < set->p[s]->n_ineq; ++i) {
+ isl_int *ineq = set->p[s]->ineq[i];
+ if (!has_constraint(hull->ctx, table, ineq, total, n))
+ break;
+ }
+ if (i == set->p[s]->n_ineq)
+ *is_hull = 1;
+ }
+
+ isl_hash_table_clear(table);
+ for (i = 0; i < min_constraints; ++i)
+ isl_mat_free(constraints[i].c);
+ free(constraints);
+ free(table);
+ return hull;
+error:
+ isl_hash_table_clear(table);
+ free(table);
+ if (constraints)
+ for (i = 0; i < min_constraints; ++i)
+ isl_mat_free(constraints[i].c);
+ free(constraints);
+ return hull;
+}
+
+/* Create a template for the convex hull of "set" and fill it up
+ * obvious facet constraints, if any. If the result happens to
+ * be the convex hull of "set" then *is_hull is set to 1.
+ */
+static struct isl_basic_set *proto_hull(struct isl_set *set, int *is_hull)
+{
+ struct isl_basic_set *hull;
+ unsigned n_ineq;
+ int i;
+
+ n_ineq = 1;
+ for (i = 0; i < set->n; ++i) {
+ n_ineq += set->p[i]->n_eq;
+ n_ineq += set->p[i]->n_ineq;
+ }
+ hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+ hull = isl_basic_set_set_rational(hull);
+ if (!hull)
+ return NULL;
+ return common_constraints(hull, set, is_hull);
+}
+
+static struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set)
+{
+ struct isl_basic_set *hull;
+ int is_hull;
+
+ hull = proto_hull(set, &is_hull);
+ if (hull && !is_hull) {
+ if (hull->n_ineq == 0)
+ hull = initial_hull(hull, set);
+ hull = extend(hull, set);
+ }
+ isl_set_free(set);
+
+ return hull;
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions. Depending on whether the set is bounded,
+ * we pass control to the wrapping based convex hull or
+ * the Fourier-Motzkin elimination based convex hull.
+ * We also handle a few special cases before checking the boundedness.
+ */
+static struct isl_basic_set *uset_convex_hull(struct isl_set *set)
+{
+ struct isl_basic_set *convex_hull = NULL;
+ struct isl_basic_set *lin;
+
+ if (isl_set_n_dim(set) == 0)
+ return convex_hull_0d(set);
+
+ set = isl_set_coalesce(set);
+ set = isl_set_set_rational(set);
+
+ if (!set)
+ goto error;
+ if (!set)
+ return NULL;
+ if (set->n == 1) {
+ convex_hull = isl_basic_set_copy(set->p[0]);
+ isl_set_free(set);
+ return convex_hull;
+ }
+ if (isl_set_n_dim(set) == 1)
+ return convex_hull_1d(set);
+
+ if (isl_set_is_bounded(set) &&
+ set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP)
+ return uset_convex_hull_wrap(set);
+
+ lin = uset_combined_lineality_space(isl_set_copy(set));
+ if (!lin)
+ goto error;
+ if (isl_basic_set_is_universe(lin)) {
+ isl_set_free(set);
+ return lin;
+ }
+ if (lin->n_eq < isl_basic_set_total_dim(lin))
+ return modulo_lineality(set, lin);
+ isl_basic_set_free(lin);
+
+ return uset_convex_hull_unbounded(set);
+error:
+ isl_set_free(set);
+ isl_basic_set_free(convex_hull);
+ return NULL;
+}
+
+/* This is the core procedure, where "set" is a "pure" set, i.e.,
+ * without parameters or divs and where the convex hull of set is
+ * known to be full-dimensional.
+ */
+static struct isl_basic_set *uset_convex_hull_wrap_bounded(struct isl_set *set)
+{
+ struct isl_basic_set *convex_hull = NULL;
+
+ if (!set)
+ goto error;
+
+ if (isl_set_n_dim(set) == 0) {
+ convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+ isl_set_free(set);
+ convex_hull = isl_basic_set_set_rational(convex_hull);
+ return convex_hull;
+ }
+
+ set = isl_set_set_rational(set);
+ set = isl_set_coalesce(set);
+ if (!set)
+ goto error;
+ if (set->n == 1) {
+ convex_hull = isl_basic_set_copy(set->p[0]);
+ isl_set_free(set);
+ convex_hull = isl_basic_map_remove_redundancies(convex_hull);
+ return convex_hull;
+ }
+ if (isl_set_n_dim(set) == 1)
+ return convex_hull_1d(set);
+
+ return uset_convex_hull_wrap(set);
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Compute the convex hull of set "set" with affine hull "affine_hull",
+ * We first remove the equalities (transforming the set), compute the
+ * convex hull of the transformed set and then add the equalities back
+ * (after performing the inverse transformation.
+ */
+static struct isl_basic_set *modulo_affine_hull(
+ struct isl_set *set, struct isl_basic_set *affine_hull)
+{
+ struct isl_mat *T;
+ struct isl_mat *T2;
+ struct isl_basic_set *dummy;
+ struct isl_basic_set *convex_hull;
+
+ dummy = isl_basic_set_remove_equalities(
+ isl_basic_set_copy(affine_hull), &T, &T2);
+ if (!dummy)
+ goto error;
+ isl_basic_set_free(dummy);
+ set = isl_set_preimage(set, T);
+ convex_hull = uset_convex_hull(set);
+ convex_hull = isl_basic_set_preimage(convex_hull, T2);
+ convex_hull = isl_basic_set_intersect(convex_hull, affine_hull);
+ return convex_hull;
+error:
+ isl_basic_set_free(affine_hull);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Compute the convex hull of a map.
+ *
+ * The implementation was inspired by "Extended Convex Hull" by Fukuda et al.,
+ * specifically, the wrapping of facets to obtain new facets.
+ */
+struct isl_basic_map *isl_map_convex_hull(struct isl_map *map)
+{
+ struct isl_basic_set *bset;
+ struct isl_basic_map *model = NULL;
+ struct isl_basic_set *affine_hull = NULL;
+ struct isl_basic_map *convex_hull = NULL;
+ struct isl_set *set = NULL;
+ struct isl_ctx *ctx;
+
+ map = isl_map_detect_equalities(map);
+ map = isl_map_align_divs(map);
+ if (!map)
+ goto error;
+
+ ctx = map->ctx;
+ if (map->n == 0) {
+ convex_hull = isl_basic_map_empty_like_map(map);
+ isl_map_free(map);
+ return convex_hull;
+ }
+
+ model = isl_basic_map_copy(map->p[0]);
+ set = isl_map_underlying_set(map);
+ if (!set)
+ goto error;
+
+ affine_hull = isl_set_affine_hull(isl_set_copy(set));
+ if (!affine_hull)
+ goto error;
+ if (affine_hull->n_eq != 0)
+ bset = modulo_affine_hull(set, affine_hull);
+ else {
+ isl_basic_set_free(affine_hull);
+ bset = uset_convex_hull(set);
+ }
+
+ convex_hull = isl_basic_map_overlying_set(bset, model);
+ if (!convex_hull)
+ return NULL;
+
+ ISL_F_SET(convex_hull, ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_SET(convex_hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+ ISL_F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL);
+ return convex_hull;
+error:
+ isl_set_free(set);
+ isl_basic_map_free(model);
+ return NULL;
+}
+
+struct isl_basic_set *isl_set_convex_hull(struct isl_set *set)
+{
+ return (struct isl_basic_set *)
+ isl_map_convex_hull((struct isl_map *)set);
+}
+
+__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map)
+{
+ isl_basic_map *hull;
+
+ hull = isl_map_convex_hull(map);
+ return isl_basic_map_remove_divs(hull);
+}
+
+__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set)
+{
+ return (isl_basic_set *)isl_map_polyhedral_hull((isl_map *)set);
+}
+
+struct sh_data_entry {
+ struct isl_hash_table *table;
+ struct isl_tab *tab;
+};
+
+/* Holds the data needed during the simple hull computation.
+ * In particular,
+ * n the number of basic sets in the original set
+ * hull_table a hash table of already computed constraints
+ * in the simple hull
+ * p for each basic set,
+ * table a hash table of the constraints
+ * tab the tableau corresponding to the basic set
+ */
+struct sh_data {
+ struct isl_ctx *ctx;
+ unsigned n;
+ struct isl_hash_table *hull_table;
+ struct sh_data_entry p[1];
+};
+
+static void sh_data_free(struct sh_data *data)
+{
+ int i;
+
+ if (!data)
+ return;
+ isl_hash_table_free(data->ctx, data->hull_table);
+ for (i = 0; i < data->n; ++i) {
+ isl_hash_table_free(data->ctx, data->p[i].table);
+ isl_tab_free(data->p[i].tab);
+ }
+ free(data);
+}
+
+struct ineq_cmp_data {
+ unsigned len;
+ isl_int *p;
+};
+
+static int has_ineq(const void *entry, const void *val)
+{
+ isl_int *row = (isl_int *)entry;
+ struct ineq_cmp_data *v = (struct ineq_cmp_data *)val;
+
+ return isl_seq_eq(row + 1, v->p + 1, v->len) ||
+ isl_seq_is_neg(row + 1, v->p + 1, v->len);
+}
+
+static int hash_ineq(struct isl_ctx *ctx, struct isl_hash_table *table,
+ isl_int *ineq, unsigned len)
+{
+ uint32_t c_hash;
+ struct ineq_cmp_data v;
+ struct isl_hash_table_entry *entry;
+
+ v.len = len;
+ v.p = ineq;
+ c_hash = isl_seq_get_hash(ineq + 1, len);
+ entry = isl_hash_table_find(ctx, table, c_hash, has_ineq, &v, 1);
+ if (!entry)
+ return - 1;
+ entry->data = ineq;
+ return 0;
+}
+
+/* Fill hash table "table" with the constraints of "bset".
+ * Equalities are added as two inequalities.
+ * The value in the hash table is a pointer to the (in)equality of "bset".
+ */
+static int hash_basic_set(struct isl_hash_table *table,
+ struct isl_basic_set *bset)
+{
+ int i, j;
+ unsigned dim = isl_basic_set_total_dim(bset);
+
+ for (i = 0; i < bset->n_eq; ++i) {
+ for (j = 0; j < 2; ++j) {
+ isl_seq_neg(bset->eq[i], bset->eq[i], 1 + dim);
+ if (hash_ineq(bset->ctx, table, bset->eq[i], dim) < 0)
+ return -1;
+ }
+ }
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (hash_ineq(bset->ctx, table, bset->ineq[i], dim) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static struct sh_data *sh_data_alloc(struct isl_set *set, unsigned n_ineq)
+{
+ struct sh_data *data;
+ int i;
+
+ data = isl_calloc(set->ctx, struct sh_data,
+ sizeof(struct sh_data) +
+ (set->n - 1) * sizeof(struct sh_data_entry));
+ if (!data)
+ return NULL;
+ data->ctx = set->ctx;
+ data->n = set->n;
+ data->hull_table = isl_hash_table_alloc(set->ctx, n_ineq);
+ if (!data->hull_table)
+ goto error;
+ for (i = 0; i < set->n; ++i) {
+ data->p[i].table = isl_hash_table_alloc(set->ctx,
+ 2 * set->p[i]->n_eq + set->p[i]->n_ineq);
+ if (!data->p[i].table)
+ goto error;
+ if (hash_basic_set(data->p[i].table, set->p[i]) < 0)
+ goto error;
+ }
+ return data;
+error:
+ sh_data_free(data);
+ return NULL;
+}
+
+/* Check if inequality "ineq" is a bound for basic set "j" or if
+ * it can be relaxed (by increasing the constant term) to become
+ * a bound for that basic set. In the latter case, the constant
+ * term is updated.
+ * Relaxation of the constant term is only allowed if "shift" is set.
+ *
+ * Return 1 if "ineq" is a bound
+ * 0 if "ineq" may attain arbitrarily small values on basic set "j"
+ * -1 if some error occurred
+ */
+static int is_bound(struct sh_data *data, struct isl_set *set, int j,
+ isl_int *ineq, int shift)
+{
+ enum isl_lp_result res;
+ isl_int opt;
+
+ if (!data->p[j].tab) {
+ data->p[j].tab = isl_tab_from_basic_set(set->p[j], 0);
+ if (!data->p[j].tab)
+ return -1;
+ }
+
+ isl_int_init(opt);
+
+ res = isl_tab_min(data->p[j].tab, ineq, data->ctx->one,
+ &opt, NULL, 0);
+ if (res == isl_lp_ok && isl_int_is_neg(opt)) {
+ if (shift)
+ isl_int_sub(ineq[0], ineq[0], opt);
+ else
+ res = isl_lp_unbounded;
+ }
+
+ isl_int_clear(opt);
+
+ return (res == isl_lp_ok || res == isl_lp_empty) ? 1 :
+ res == isl_lp_unbounded ? 0 : -1;
+}
+
+/* Check if inequality "ineq" from basic set "i" is or can be relaxed to
+ * become a bound on the whole set. If so, add the (relaxed) inequality
+ * to "hull". Relaxation is only allowed if "shift" is set.
+ *
+ * We first check if "hull" already contains a translate of the inequality.
+ * If so, we are done.
+ * Then, we check if any of the previous basic sets contains a translate
+ * of the inequality. If so, then we have already considered this
+ * inequality and we are done.
+ * Otherwise, for each basic set other than "i", we check if the inequality
+ * is a bound on the basic set.
+ * For previous basic sets, we know that they do not contain a translate
+ * of the inequality, so we directly call is_bound.
+ * For following basic sets, we first check if a translate of the
+ * inequality appears in its description and if so directly update
+ * the inequality accordingly.
+ */
+static struct isl_basic_set *add_bound(struct isl_basic_set *hull,
+ struct sh_data *data, struct isl_set *set, int i, isl_int *ineq,
+ int shift)
+{
+ uint32_t c_hash;
+ struct ineq_cmp_data v;
+ struct isl_hash_table_entry *entry;
+ int j, k;
+
+ if (!hull)
+ return NULL;
+
+ v.len = isl_basic_set_total_dim(hull);
+ v.p = ineq;
+ c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+ entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+ has_ineq, &v, 0);
+ if (entry)
+ return hull;
+
+ for (j = 0; j < i; ++j) {
+ entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+ c_hash, has_ineq, &v, 0);
+ if (entry)
+ break;
+ }
+ if (j < i)
+ return hull;
+
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+ for (j = 0; j < i; ++j) {
+ int bound;
+ bound = is_bound(data, set, j, hull->ineq[k], shift);
+ if (bound < 0)
+ goto error;
+ if (!bound)
+ break;
+ }
+ if (j < i) {
+ isl_basic_set_free_inequality(hull, 1);
+ return hull;
+ }
+
+ for (j = i + 1; j < set->n; ++j) {
+ int bound, neg;
+ isl_int *ineq_j;
+ entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+ c_hash, has_ineq, &v, 0);
+ if (entry) {
+ ineq_j = entry->data;
+ neg = isl_seq_is_neg(ineq_j + 1,
+ hull->ineq[k] + 1, v.len);
+ if (neg)
+ isl_int_neg(ineq_j[0], ineq_j[0]);
+ if (isl_int_gt(ineq_j[0], hull->ineq[k][0]))
+ isl_int_set(hull->ineq[k][0], ineq_j[0]);
+ if (neg)
+ isl_int_neg(ineq_j[0], ineq_j[0]);
+ continue;
+ }
+ bound = is_bound(data, set, j, hull->ineq[k], shift);
+ if (bound < 0)
+ goto error;
+ if (!bound)
+ break;
+ }
+ if (j < set->n) {
+ isl_basic_set_free_inequality(hull, 1);
+ return hull;
+ }
+
+ entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+ has_ineq, &v, 1);
+ if (!entry)
+ goto error;
+ entry->data = hull->ineq[k];
+
+ return hull;
+error:
+ isl_basic_set_free(hull);
+ return NULL;
+}
+
+/* Check if any inequality from basic set "i" is or can be relaxed to
+ * become a bound on the whole set. If so, add the (relaxed) inequality
+ * to "hull". Relaxation is only allowed if "shift" is set.
+ */
+static struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
+ struct sh_data *data, struct isl_set *set, int i, int shift)
+{
+ int j, k;
+ unsigned dim = isl_basic_set_total_dim(bset);
+
+ for (j = 0; j < set->p[i]->n_eq; ++j) {
+ for (k = 0; k < 2; ++k) {
+ isl_seq_neg(set->p[i]->eq[j], set->p[i]->eq[j], 1+dim);
+ bset = add_bound(bset, data, set, i, set->p[i]->eq[j],
+ shift);
+ }
+ }
+ for (j = 0; j < set->p[i]->n_ineq; ++j)
+ bset = add_bound(bset, data, set, i, set->p[i]->ineq[j], shift);
+ return bset;
+}
+
+/* Compute a superset of the convex hull of set that is described
+ * by only (translates of) the constraints in the constituents of set.
+ * Translation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_set *uset_simple_hull(__isl_take isl_set *set,
+ int shift)
+{
+ struct sh_data *data = NULL;
+ struct isl_basic_set *hull = NULL;
+ unsigned n_ineq;
+ int i;
+
+ if (!set)
+ return NULL;
+
+ n_ineq = 0;
+ for (i = 0; i < set->n; ++i) {
+ if (!set->p[i])
+ goto error;
+ n_ineq += 2 * set->p[i]->n_eq + set->p[i]->n_ineq;
+ }
+
+ hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+ if (!hull)
+ goto error;
+
+ data = sh_data_alloc(set, n_ineq);
+ if (!data)
+ goto error;
+
+ for (i = 0; i < set->n; ++i)
+ hull = add_bounds(hull, data, set, i, shift);
+
+ sh_data_free(data);
+ isl_set_free(set);
+
+ return hull;
+error:
+ sh_data_free(data);
+ isl_basic_set_free(hull);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only (translates of) the constraints in the constituents of map.
+ * Translation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_map *map_simple_hull(__isl_take isl_map *map,
+ int shift)
+{
+ struct isl_set *set = NULL;
+ struct isl_basic_map *model = NULL;
+ struct isl_basic_map *hull;
+ struct isl_basic_map *affine_hull;
+ struct isl_basic_set *bset = NULL;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0) {
+ hull = isl_basic_map_empty_like_map(map);
+ isl_map_free(map);
+ return hull;
+ }
+ if (map->n == 1) {
+ hull = isl_basic_map_copy(map->p[0]);
+ isl_map_free(map);
+ return hull;
+ }
+
+ map = isl_map_detect_equalities(map);
+ affine_hull = isl_map_affine_hull(isl_map_copy(map));
+ map = isl_map_align_divs(map);
+ model = map ? isl_basic_map_copy(map->p[0]) : NULL;
+
+ set = isl_map_underlying_set(map);
+
+ bset = uset_simple_hull(set, shift);
+
+ hull = isl_basic_map_overlying_set(bset, model);
+
+ hull = isl_basic_map_intersect(hull, affine_hull);
+ hull = isl_basic_map_remove_redundancies(hull);
+
+ if (!hull)
+ return NULL;
+ ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+
+ hull = isl_basic_map_finalize(hull);
+
+ return hull;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only translates of the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map)
+{
+ return map_simple_hull(map, 1);
+}
+
+struct isl_basic_set *isl_set_simple_hull(struct isl_set *set)
+{
+ return (struct isl_basic_set *)
+ isl_map_simple_hull((struct isl_map *)set);
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull(
+ __isl_take isl_map *map)
+{
+ return map_simple_hull(map, 0);
+}
+
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull(
+ __isl_take isl_set *set)
+{
+ return isl_map_unshifted_simple_hull(set);
+}
+
+/* Check if "ineq" is a bound on "set" and, if so, add it to "hull".
+ *
+ * For each basic set in "set", we first check if the basic set
+ * contains a translate of "ineq". If this translate is more relaxed,
+ * then we assume that "ineq" is not a bound on this basic set.
+ * Otherwise, we know that it is a bound.
+ * If the basic set does not contain a translate of "ineq", then
+ * we call is_bound to perform the test.
+ */
+static __isl_give isl_basic_set *add_bound_from_constraint(
+ __isl_take isl_basic_set *hull, struct sh_data *data,
+ __isl_keep isl_set *set, isl_int *ineq)
+{
+ int i, k;
+ isl_ctx *ctx;
+ uint32_t c_hash;
+ struct ineq_cmp_data v;
+
+ if (!hull || !set)
+ return isl_basic_set_free(hull);
+
+ v.len = isl_basic_set_total_dim(hull);
+ v.p = ineq;
+ c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+ ctx = isl_basic_set_get_ctx(hull);
+ for (i = 0; i < set->n; ++i) {
+ int bound;
+ struct isl_hash_table_entry *entry;
+
+ entry = isl_hash_table_find(ctx, data->p[i].table,
+ c_hash, &has_ineq, &v, 0);
+ if (entry) {
+ isl_int *ineq_i = entry->data;
+ int neg, more_relaxed;
+
+ neg = isl_seq_is_neg(ineq_i + 1, ineq + 1, v.len);
+ if (neg)
+ isl_int_neg(ineq_i[0], ineq_i[0]);
+ more_relaxed = isl_int_gt(ineq_i[0], ineq[0]);
+ if (neg)
+ isl_int_neg(ineq_i[0], ineq_i[0]);
+ if (more_relaxed)
+ break;
+ else
+ continue;
+ }
+ bound = is_bound(data, set, i, ineq, 0);
+ if (bound < 0)
+ return isl_basic_set_free(hull);
+ if (!bound)
+ break;
+ }
+ if (i < set->n)
+ return hull;
+
+ k = isl_basic_set_alloc_inequality(hull);
+ if (k < 0)
+ return isl_basic_set_free(hull);
+ isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+ return hull;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only some of the "n_ineq" constraints in the list "ineq", where "set"
+ * has no parameters or integer divisions.
+ *
+ * The inequalities in "ineq" are assumed to have been sorted such
+ * that constraints with the same linear part appear together and
+ * that among constraints with the same linear part, those with
+ * smaller constant term appear first.
+ *
+ * We reuse the same data structure that is used by uset_simple_hull,
+ * but we do not need the hull table since we will not consider the
+ * same constraint more than once. We therefore allocate it with zero size.
+ *
+ * We run through the constraints and try to add them one by one,
+ * skipping identical constraints. If we have added a constraint and
+ * the next constraint is a more relaxed translate, then we skip this
+ * next constraint as well.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_constraints(
+ __isl_take isl_set *set, int n_ineq, isl_int **ineq)
+{
+ int i;
+ int last_added = 0;
+ struct sh_data *data = NULL;
+ isl_basic_set *hull = NULL;
+ unsigned dim;
+
+ hull = isl_basic_set_alloc_space(isl_set_get_space(set), 0, 0, n_ineq);
+ if (!hull)
+ goto error;
+
+ data = sh_data_alloc(set, 0);
+ if (!data)
+ goto error;
+
+ dim = isl_set_dim(set, isl_dim_set);
+ for (i = 0; i < n_ineq; ++i) {
+ int hull_n_ineq = hull->n_ineq;
+ int parallel;
+
+ parallel = i > 0 && isl_seq_eq(ineq[i - 1] + 1, ineq[i] + 1,
+ dim);
+ if (parallel &&
+ (last_added || isl_int_eq(ineq[i - 1][0], ineq[i][0])))
+ continue;
+ hull = add_bound_from_constraint(hull, data, set, ineq[i]);
+ if (!hull)
+ goto error;
+ last_added = hull->n_ineq > hull_n_ineq;
+ }
+
+ sh_data_free(data);
+ isl_set_free(set);
+ return hull;
+error:
+ sh_data_free(data);
+ isl_set_free(set);
+ isl_basic_set_free(hull);
+ return NULL;
+}
+
+/* Collect pointers to all the inequalities in the elements of "list"
+ * in "ineq". For equalities, store both a pointer to the equality and
+ * a pointer to its opposite, which is first copied to "mat".
+ * "ineq" and "mat" are assumed to have been preallocated to the right size
+ * (the number of inequalities + 2 times the number of equalites and
+ * the number of equalities, respectively).
+ */
+static __isl_give isl_mat *collect_inequalities(__isl_take isl_mat *mat,
+ __isl_keep isl_basic_set_list *list, isl_int **ineq)
+{
+ int i, j, n, n_eq, n_ineq;
+
+ if (!mat)
+ return NULL;
+
+ n_eq = 0;
+ n_ineq = 0;
+ n = isl_basic_set_list_n_basic_set(list);
+ for (i = 0; i < n; ++i) {
+ isl_basic_set *bset;
+ bset = isl_basic_set_list_get_basic_set(list, i);
+ if (!bset)
+ return isl_mat_free(mat);
+ for (j = 0; j < bset->n_eq; ++j) {
+ ineq[n_ineq++] = mat->row[n_eq];
+ ineq[n_ineq++] = bset->eq[j];
+ isl_seq_neg(mat->row[n_eq++], bset->eq[j], mat->n_col);
+ }
+ for (j = 0; j < bset->n_ineq; ++j)
+ ineq[n_ineq++] = bset->ineq[j];
+ isl_basic_set_free(bset);
+ }
+
+ return mat;
+}
+
+/* Comparison routine for use as an isl_sort callback.
+ *
+ * Constraints with the same linear part are sorted together and
+ * among constraints with the same linear part, those with smaller
+ * constant term are sorted first.
+ */
+static int cmp_ineq(const void *a, const void *b, void *arg)
+{
+ unsigned dim = *(unsigned *) arg;
+ isl_int * const *ineq1 = a;
+ isl_int * const *ineq2 = b;
+ int cmp;
+
+ cmp = isl_seq_cmp((*ineq1) + 1, (*ineq2) + 1, dim);
+ if (cmp != 0)
+ return cmp;
+ return isl_int_cmp((*ineq1)[0], (*ineq2)[0]);
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list", where "set" has
+ * no parameters or integer divisions.
+ *
+ * We collect all the constraints in those elements and then
+ * sort the constraints such that constraints with the same linear part
+ * are sorted together and that those with smaller constant term are
+ * sorted first.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_basic_set_list(
+ __isl_take isl_set *set, __isl_take isl_basic_set_list *list)
+{
+ int i, n, n_eq, n_ineq;
+ unsigned dim;
+ isl_ctx *ctx;
+ isl_mat *mat = NULL;
+ isl_int **ineq = NULL;
+ isl_basic_set *hull;
+
+ if (!set)
+ goto error;
+ ctx = isl_set_get_ctx(set);
+
+ n_eq = 0;
+ n_ineq = 0;
+ n = isl_basic_set_list_n_basic_set(list);
+ for (i = 0; i < n; ++i) {
+ isl_basic_set *bset;
+ bset = isl_basic_set_list_get_basic_set(list, i);
+ if (!bset)
+ goto error;
+ n_eq += bset->n_eq;
+ n_ineq += 2 * bset->n_eq + bset->n_ineq;
+ isl_basic_set_free(bset);
+ }
+
+ ineq = isl_alloc_array(ctx, isl_int *, n_ineq);
+ if (n_ineq > 0 && !ineq)
+ goto error;
+
+ dim = isl_set_dim(set, isl_dim_set);
+ mat = isl_mat_alloc(ctx, n_eq, 1 + dim);
+ mat = collect_inequalities(mat, list, ineq);
+ if (!mat)
+ goto error;
+
+ if (isl_sort(ineq, n_ineq, sizeof(ineq[0]), &cmp_ineq, &dim) < 0)
+ goto error;
+
+ hull = uset_unshifted_simple_hull_from_constraints(set, n_ineq, ineq);
+
+ isl_mat_free(mat);
+ free(ineq);
+ isl_basic_set_list_free(list);
+ return hull;
+error:
+ isl_mat_free(mat);
+ free(ineq);
+ isl_set_free(set);
+ isl_basic_set_list_free(list);
+ return NULL;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If the list is empty, then we can only describe the universe set.
+ * If the input set is empty, then all constraints are valid, so
+ * we return the intersection of the elements in "list".
+ *
+ * Otherwise, we align all divs and temporarily treat them
+ * as regular variables, computing the unshifted simple hull in
+ * uset_unshifted_simple_hull_from_basic_set_list.
+ */
+static __isl_give isl_basic_set *set_unshifted_simple_hull_from_basic_set_list(
+ __isl_take isl_set *set, __isl_take isl_basic_set_list *list)
+{
+ isl_basic_set *model;
+ isl_basic_set *hull;
+
+ if (!set || !list)
+ goto error;
+
+ if (isl_basic_set_list_n_basic_set(list) == 0) {
+ isl_space *space;
+
+ space = isl_set_get_space(set);
+ isl_set_free(set);
+ isl_basic_set_list_free(list);
+ return isl_basic_set_universe(space);
+ }
+ if (isl_set_plain_is_empty(set)) {
+ isl_set_free(set);
+ return isl_basic_set_list_intersect(list);
+ }
+
+ set = isl_set_align_divs_to_basic_set_list(set, list);
+ if (!set)
+ goto error;
+ list = isl_basic_set_list_align_divs_to_basic_set(list, set->p[0]);
+
+ model = isl_basic_set_list_get_basic_set(list, 0);
+
+ set = isl_set_to_underlying_set(set);
+ list = isl_basic_set_list_underlying_set(list);
+
+ hull = uset_unshifted_simple_hull_from_basic_set_list(set, list);
+ hull = isl_basic_map_overlying_set(hull, model);
+
+ return hull;
+error:
+ isl_set_free(set);
+ isl_basic_set_list_free(list);
+ return NULL;
+}
+
+/* Return a sequence of the basic sets that make up the sets in "list".
+ */
+static __isl_give isl_basic_set_list *collect_basic_sets(
+ __isl_take isl_set_list *list)
+{
+ int i, n;
+ isl_ctx *ctx;
+ isl_basic_set_list *bset_list;
+
+ if (!list)
+ return NULL;
+ n = isl_set_list_n_set(list);
+ ctx = isl_set_list_get_ctx(list);
+ bset_list = isl_basic_set_list_alloc(ctx, 0);
+
+ for (i = 0; i < n; ++i) {
+ isl_set *set;
+ isl_basic_set_list *list_i;
+
+ set = isl_set_list_get_set(list, i);
+ set = isl_set_compute_divs(set);
+ list_i = isl_set_get_basic_set_list(set);
+ isl_set_free(set);
+ bset_list = isl_basic_set_list_concat(bset_list, list_i);
+ }
+
+ isl_set_list_free(list);
+ return bset_list;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If "set" is the universe, then the convex hull (and therefore
+ * any superset of the convexhull) is the universe as well.
+ *
+ * Otherwise, we collect all the basic sets in the set list and
+ * continue with set_unshifted_simple_hull_from_basic_set_list.
+ */
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list(
+ __isl_take isl_set *set, __isl_take isl_set_list *list)
+{
+ isl_basic_set_list *bset_list;
+ int is_universe;
+
+ is_universe = isl_set_plain_is_universe(set);
+ if (is_universe < 0)
+ set = isl_set_free(set);
+ if (is_universe < 0 || is_universe) {
+ isl_set_list_free(list);
+ return isl_set_unshifted_simple_hull(set);
+ }
+
+ bset_list = collect_basic_sets(list);
+ return set_unshifted_simple_hull_from_basic_set_list(set, bset_list);
+}
+
+/* Given a set "set", return parametric bounds on the dimension "dim".
+ */
+static struct isl_basic_set *set_bounds(struct isl_set *set, int dim)
+{
+ unsigned set_dim = isl_set_dim(set, isl_dim_set);
+ set = isl_set_copy(set);
+ set = isl_set_eliminate_dims(set, dim + 1, set_dim - (dim + 1));
+ set = isl_set_eliminate_dims(set, 0, dim);
+ return isl_set_convex_hull(set);
+}
+
+/* Computes a "simple hull" and then check if each dimension in the
+ * resulting hull is bounded by a symbolic constant. If not, the
+ * hull is intersected with the corresponding bounds on the whole set.
+ */
+struct isl_basic_set *isl_set_bounded_simple_hull(struct isl_set *set)
+{
+ int i, j;
+ struct isl_basic_set *hull;
+ unsigned nparam, left;
+ int removed_divs = 0;
+
+ hull = isl_set_simple_hull(isl_set_copy(set));
+ if (!hull)
+ goto error;
+
+ nparam = isl_basic_set_dim(hull, isl_dim_param);
+ for (i = 0; i < isl_basic_set_dim(hull, isl_dim_set); ++i) {
+ int lower = 0, upper = 0;
+ struct isl_basic_set *bounds;
+
+ left = isl_basic_set_total_dim(hull) - nparam - i - 1;
+ for (j = 0; j < hull->n_eq; ++j) {
+ if (isl_int_is_zero(hull->eq[j][1 + nparam + i]))
+ continue;
+ if (isl_seq_first_non_zero(hull->eq[j]+1+nparam+i+1,
+ left) == -1)
+ break;
+ }
+ if (j < hull->n_eq)
+ continue;
+
+ for (j = 0; j < hull->n_ineq; ++j) {
+ if (isl_int_is_zero(hull->ineq[j][1 + nparam + i]))
+ continue;
+ if (isl_seq_first_non_zero(hull->ineq[j]+1+nparam+i+1,
+ left) != -1 ||
+ isl_seq_first_non_zero(hull->ineq[j]+1+nparam,
+ i) != -1)
+ continue;
+ if (isl_int_is_pos(hull->ineq[j][1 + nparam + i]))
+ lower = 1;
+ else
+ upper = 1;
+ if (lower && upper)
+ break;
+ }
+
+ if (lower && upper)
+ continue;
+
+ if (!removed_divs) {
+ set = isl_set_remove_divs(set);
+ if (!set)
+ goto error;
+ removed_divs = 1;
+ }
+ bounds = set_bounds(set, i);
+ hull = isl_basic_set_intersect(hull, bounds);
+ if (!hull)
+ goto error;
+ }
+
+ isl_set_free(set);
+ return hull;
+error:
+ isl_set_free(set);
+ return NULL;
+}
Added: polly/trunk/lib/External/isl/isl_ctx.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ctx.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ctx.c (added)
+++ polly/trunk/lib/External/isl/isl_ctx.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl/vec.h>
+#include <isl_options_private.h>
+
+#define __isl_calloc(type,size) ((type *)calloc(1, size))
+#define __isl_calloc_type(type) __isl_calloc(type,sizeof(type))
+
+/* Check that the result of an allocation ("p") is not NULL and
+ * complain if it is.
+ * The only exception is when allocation size ("size") is equal to zero.
+ */
+static void *check_non_null(isl_ctx *ctx, void *p, size_t size)
+{
+ if (p || size == 0)
+ return p;
+ isl_die(ctx, isl_error_alloc, "allocation failure", return NULL);
+}
+
+/* Prepare for performing the next "operation" in the context.
+ * Return 0 if we are allowed to perform this operation and
+ * return -1 if we should abort the computation.
+ *
+ * In particular, we should stop if the user has explicitly aborted
+ * the computation or if the maximal number of operations has been exceeded.
+ */
+int isl_ctx_next_operation(isl_ctx *ctx)
+{
+ if (!ctx)
+ return -1;
+ if (ctx->abort) {
+ isl_ctx_set_error(ctx, isl_error_abort);
+ return -1;
+ }
+ if (ctx->max_operations && ctx->operations >= ctx->max_operations)
+ isl_die(ctx, isl_error_quota,
+ "maximal number of operations exceeded", return -1);
+ ctx->operations++;
+ return 0;
+}
+
+/* Call malloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_malloc_or_die(isl_ctx *ctx, size_t size)
+{
+ if (isl_ctx_next_operation(ctx) < 0)
+ return NULL;
+ return ctx ? check_non_null(ctx, malloc(size), size) : NULL;
+}
+
+/* Call calloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size)
+{
+ if (isl_ctx_next_operation(ctx) < 0)
+ return NULL;
+ return ctx ? check_non_null(ctx, calloc(nmemb, size), nmemb) : NULL;
+}
+
+/* Call realloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size)
+{
+ if (isl_ctx_next_operation(ctx) < 0)
+ return NULL;
+ return ctx ? check_non_null(ctx, realloc(ptr, size), size) : NULL;
+}
+
+void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
+ const char *file, int line)
+{
+ if (!ctx)
+ return;
+
+ isl_ctx_set_error(ctx, error);
+
+ switch (ctx->opt->on_error) {
+ case ISL_ON_ERROR_WARN:
+ fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+ return;
+ case ISL_ON_ERROR_CONTINUE:
+ return;
+ case ISL_ON_ERROR_ABORT:
+ fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+ abort();
+ return;
+ }
+}
+
+static struct isl_options *find_nested_options(struct isl_args *args,
+ void *opt, struct isl_args *wanted)
+{
+ int i;
+ struct isl_options *options;
+
+ if (args == wanted)
+ return opt;
+
+ for (i = 0; args->args[i].type != isl_arg_end; ++i) {
+ struct isl_arg *arg = &args->args[i];
+ void *child;
+
+ if (arg->type != isl_arg_child)
+ continue;
+
+ if (arg->offset == (size_t) -1)
+ child = opt;
+ else
+ child = *(void **)(((char *)opt) + arg->offset);
+
+ options = find_nested_options(arg->u.child.child,
+ child, wanted);
+ if (options)
+ return options;
+ }
+
+ return NULL;
+}
+
+static struct isl_options *find_nested_isl_options(struct isl_args *args,
+ void *opt)
+{
+ return find_nested_options(args, opt, &isl_options_args);
+}
+
+void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args)
+{
+ if (!ctx)
+ return NULL;
+ if (args == &isl_options_args)
+ return ctx->opt;
+ return find_nested_options(ctx->user_args, ctx->user_opt, args);
+}
+
+isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt)
+{
+ struct isl_ctx *ctx = NULL;
+ struct isl_options *opt = NULL;
+ int opt_allocated = 0;
+
+ if (!user_opt)
+ return NULL;
+
+ opt = find_nested_isl_options(args, user_opt);
+ if (!opt) {
+ opt = isl_options_new_with_defaults();
+ if (!opt)
+ goto error;
+ opt_allocated = 1;
+ }
+
+ ctx = __isl_calloc_type(struct isl_ctx);
+ if (!ctx)
+ goto error;
+
+ if (isl_hash_table_init(ctx, &ctx->id_table, 0))
+ goto error;
+
+ ctx->stats = isl_calloc_type(ctx, struct isl_stats);
+ if (!ctx->stats)
+ goto error;
+
+ ctx->user_args = args;
+ ctx->user_opt = user_opt;
+ ctx->opt_allocated = opt_allocated;
+ ctx->opt = opt;
+ ctx->ref = 0;
+
+ isl_int_init(ctx->zero);
+ isl_int_set_si(ctx->zero, 0);
+
+ isl_int_init(ctx->one);
+ isl_int_set_si(ctx->one, 1);
+
+ isl_int_init(ctx->two);
+ isl_int_set_si(ctx->two, 2);
+
+ isl_int_init(ctx->negone);
+ isl_int_set_si(ctx->negone, -1);
+
+ isl_int_init(ctx->normalize_gcd);
+
+ ctx->n_cached = 0;
+ ctx->n_miss = 0;
+
+ ctx->error = isl_error_none;
+
+ ctx->operations = 0;
+ isl_ctx_set_max_operations(ctx, ctx->opt->max_operations);
+
+ return ctx;
+error:
+ isl_args_free(args, user_opt);
+ if (opt_allocated)
+ isl_options_free(opt);
+ free(ctx);
+ return NULL;
+}
+
+struct isl_ctx *isl_ctx_alloc()
+{
+ struct isl_options *opt;
+
+ opt = isl_options_new_with_defaults();
+
+ return isl_ctx_alloc_with_options(&isl_options_args, opt);
+}
+
+void isl_ctx_ref(struct isl_ctx *ctx)
+{
+ ctx->ref++;
+}
+
+void isl_ctx_deref(struct isl_ctx *ctx)
+{
+ isl_assert(ctx, ctx->ref > 0, return);
+ ctx->ref--;
+}
+
+/* Print statistics on usage.
+ */
+static void print_stats(isl_ctx *ctx)
+{
+ fprintf(stderr, "operations: %lu\n", ctx->operations);
+}
+
+void isl_ctx_free(struct isl_ctx *ctx)
+{
+ if (!ctx)
+ return;
+ if (ctx->ref != 0)
+ isl_die(ctx, isl_error_invalid,
+ "isl_ctx freed, but some objects still reference it",
+ return);
+
+ if (ctx->opt->print_stats)
+ print_stats(ctx);
+
+ isl_hash_table_clear(&ctx->id_table);
+ isl_blk_clear_cache(ctx);
+ isl_int_clear(ctx->zero);
+ isl_int_clear(ctx->one);
+ isl_int_clear(ctx->two);
+ isl_int_clear(ctx->negone);
+ isl_int_clear(ctx->normalize_gcd);
+ isl_args_free(ctx->user_args, ctx->user_opt);
+ if (ctx->opt_allocated)
+ isl_options_free(ctx->opt);
+ free(ctx->stats);
+ free(ctx);
+}
+
+struct isl_options *isl_ctx_options(isl_ctx *ctx)
+{
+ if (!ctx)
+ return NULL;
+ return ctx->opt;
+}
+
+enum isl_error isl_ctx_last_error(isl_ctx *ctx)
+{
+ return ctx->error;
+}
+
+void isl_ctx_reset_error(isl_ctx *ctx)
+{
+ ctx->error = isl_error_none;
+}
+
+void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error)
+{
+ if (ctx)
+ ctx->error = error;
+}
+
+void isl_ctx_abort(isl_ctx *ctx)
+{
+ if (ctx)
+ ctx->abort = 1;
+}
+
+void isl_ctx_resume(isl_ctx *ctx)
+{
+ if (ctx)
+ ctx->abort = 0;
+}
+
+int isl_ctx_aborted(isl_ctx *ctx)
+{
+ return ctx ? ctx->abort : -1;
+}
+
+int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags)
+{
+ if (!ctx)
+ return -1;
+ return isl_args_parse(ctx->user_args, argc, argv, ctx->user_opt, flags);
+}
+
+/* Set the maximal number of iterations of "ctx" to "max_operations".
+ */
+void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations)
+{
+ if (!ctx)
+ return;
+ ctx->max_operations = max_operations;
+}
+
+/* Return the maximal number of iterations of "ctx".
+ */
+unsigned long isl_ctx_get_max_operations(isl_ctx *ctx)
+{
+ return ctx ? ctx->max_operations : 0;
+}
+
+/* Reset the number of operations performed by "ctx".
+ */
+void isl_ctx_reset_operations(isl_ctx *ctx)
+{
+ if (!ctx)
+ return;
+ ctx->operations = 0;
+}
Added: polly/trunk/lib/External/isl/isl_ctx_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ctx_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ctx_private.h (added)
+++ polly/trunk/lib/External/isl/isl_ctx_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,34 @@
+#include <isl/ctx.h>
+#include <isl_blk.h>
+
+struct isl_ctx {
+ int ref;
+
+ struct isl_stats *stats;
+
+ int opt_allocated;
+ struct isl_options *opt;
+ void *user_opt;
+ struct isl_args *user_args;
+
+ isl_int zero;
+ isl_int one;
+ isl_int two;
+ isl_int negone;
+
+ isl_int normalize_gcd;
+
+ int n_cached;
+ int n_miss;
+ struct isl_blk cache[ISL_BLK_CACHE_SIZE];
+ struct isl_hash_table id_table;
+
+ enum isl_error error;
+
+ int abort;
+
+ unsigned long operations;
+ unsigned long max_operations;
+};
+
+int isl_ctx_next_operation(isl_ctx *ctx);
Added: polly/trunk/lib/External/isl/isl_deprecated.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_deprecated.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_deprecated.c (added)
+++ polly/trunk/lib/External/isl/isl_deprecated.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,10 @@
+#include <isl/set.h>
+
+/* This function was never documented and has been replaced by
+ * isl_basic_set_add_dims.
+ */
+__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned n)
+{
+ return isl_basic_set_add_dims(bset, type, n);
+}
Added: polly/trunk/lib/External/isl/isl_dim.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim.c (added)
+++ polly/trunk/lib/External/isl/isl_dim.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,258 @@
+#include <isl/dim.h>
+#include <isl/aff.h>
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl/polynomial.h>
+
+isl_ctx *isl_dim_get_ctx(__isl_keep isl_space *dim)
+{
+ return isl_space_get_ctx(dim);
+}
+
+__isl_give isl_space *isl_dim_alloc(isl_ctx *ctx,
+ unsigned nparam, unsigned n_in, unsigned n_out)
+{
+ return isl_space_alloc(ctx, nparam, n_in, n_out);
+}
+__isl_give isl_space *isl_dim_set_alloc(isl_ctx *ctx,
+ unsigned nparam, unsigned dim)
+{
+ return isl_space_set_alloc(ctx, nparam, dim);
+}
+__isl_give isl_space *isl_dim_copy(__isl_keep isl_space *dim)
+{
+ return isl_space_copy(dim);
+}
+void isl_dim_free(__isl_take isl_space *dim)
+{
+ isl_space_free(dim);
+}
+
+unsigned isl_dim_size(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+ return isl_space_dim(dim, type);
+}
+
+__isl_give isl_space *isl_dim_set_dim_id(__isl_take isl_space *dim,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+ return isl_space_set_dim_id(dim, type, pos, id);
+}
+int isl_dim_has_dim_id(__isl_keep isl_space *dim,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_space_has_dim_id(dim, type, pos);
+}
+__isl_give isl_id *isl_dim_get_dim_id(__isl_keep isl_space *dim,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_space_get_dim_id(dim, type, pos);
+}
+
+int isl_dim_find_dim_by_id(__isl_keep isl_space *dim,
+ enum isl_dim_type type, __isl_keep isl_id *id)
+{
+ return isl_space_find_dim_by_id(dim, type, id);
+}
+
+__isl_give isl_space *isl_dim_set_tuple_id(__isl_take isl_space *dim,
+ enum isl_dim_type type, __isl_take isl_id *id)
+{
+ return isl_space_set_tuple_id(dim, type, id);
+}
+__isl_give isl_space *isl_dim_reset_tuple_id(__isl_take isl_space *dim,
+ enum isl_dim_type type)
+{
+ return isl_space_reset_tuple_id(dim, type);
+}
+int isl_dim_has_tuple_id(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+ return isl_space_has_tuple_id(dim, type);
+}
+__isl_give isl_id *isl_dim_get_tuple_id(__isl_keep isl_space *dim,
+ enum isl_dim_type type)
+{
+ return isl_space_get_tuple_id(dim, type);
+}
+
+__isl_give isl_space *isl_dim_set_name(__isl_take isl_space *dim,
+ enum isl_dim_type type, unsigned pos, __isl_keep const char *name)
+{
+ return isl_space_set_dim_name(dim, type, pos, name);
+}
+__isl_keep const char *isl_dim_get_name(__isl_keep isl_space *dim,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_space_get_dim_name(dim, type, pos);
+}
+
+__isl_give isl_space *isl_dim_set_tuple_name(__isl_take isl_space *dim,
+ enum isl_dim_type type, const char *s)
+{
+ return isl_space_set_tuple_name(dim, type, s);
+}
+const char *isl_dim_get_tuple_name(__isl_keep isl_space *dim,
+ enum isl_dim_type type)
+{
+ return isl_space_get_tuple_name(dim, type);
+}
+
+int isl_dim_is_wrapping(__isl_keep isl_space *dim)
+{
+ return isl_space_is_wrapping(dim);
+}
+__isl_give isl_space *isl_dim_wrap(__isl_take isl_space *dim)
+{
+ return isl_space_wrap(dim);
+}
+__isl_give isl_space *isl_dim_unwrap(__isl_take isl_space *dim)
+{
+ return isl_space_unwrap(dim);
+}
+
+__isl_give isl_space *isl_dim_domain(__isl_take isl_space *dim)
+{
+ return isl_space_domain(dim);
+}
+__isl_give isl_space *isl_dim_from_domain(__isl_take isl_space *dim)
+{
+ return isl_space_from_domain(dim);
+}
+__isl_give isl_space *isl_dim_range(__isl_take isl_space *dim)
+{
+ return isl_space_range(dim);
+}
+__isl_give isl_space *isl_dim_from_range(__isl_take isl_space *dim)
+{
+ return isl_space_from_range(dim);
+}
+__isl_give isl_space *isl_dim_reverse(__isl_take isl_space *dim)
+{
+ return isl_space_reverse(dim);
+}
+__isl_give isl_space *isl_dim_join(__isl_take isl_space *left,
+ __isl_take isl_space *right)
+{
+ return isl_space_join(left, right);
+}
+__isl_give isl_space *isl_dim_align_params(__isl_take isl_space *dim1,
+ __isl_take isl_space *dim2)
+{
+ return isl_space_align_params(dim1, dim2);
+}
+__isl_give isl_space *isl_dim_insert(__isl_take isl_space *dim,
+ enum isl_dim_type type, unsigned pos, unsigned n)
+{
+ return isl_space_insert_dims(dim, type, pos, n);
+}
+__isl_give isl_space *isl_dim_add(__isl_take isl_space *dim,
+ enum isl_dim_type type, unsigned n)
+{
+ return isl_space_add_dims(dim, type, n);
+}
+__isl_give isl_space *isl_dim_drop(__isl_take isl_space *dim,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_space_drop_dims(dim, type, first, n);
+}
+__isl_give isl_space *isl_dim_move(__isl_take isl_space *dim,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ return isl_space_move_dims(dim, dst_type, dst_pos, src_type, src_pos, n);
+}
+__isl_give isl_space *isl_dim_map_from_set(__isl_take isl_space *dim)
+{
+ return isl_space_map_from_set(dim);
+}
+__isl_give isl_space *isl_dim_zip(__isl_take isl_space *dim)
+{
+ return isl_space_zip(dim);
+}
+
+__isl_give isl_local_space *isl_local_space_from_dim(
+ __isl_take isl_space *dim)
+{
+ return isl_local_space_from_space(dim);
+}
+__isl_give isl_space *isl_local_space_get_dim(
+ __isl_keep isl_local_space *ls)
+{
+ return isl_local_space_get_space(ls);
+}
+
+__isl_give isl_space *isl_aff_get_dim(__isl_keep isl_aff *aff)
+{
+ return isl_aff_get_space(aff);
+}
+__isl_give isl_space *isl_pw_aff_get_dim(__isl_keep isl_pw_aff *pwaff)
+{
+ return isl_pw_aff_get_space(pwaff);
+}
+
+__isl_give isl_space *isl_constraint_get_dim(
+ __isl_keep isl_constraint *constraint)
+{
+ return isl_constraint_get_space(constraint);
+}
+
+__isl_give isl_space *isl_basic_map_get_dim(__isl_keep isl_basic_map *bmap)
+{
+ return isl_basic_map_get_space(bmap);
+}
+__isl_give isl_space *isl_map_get_dim(__isl_keep isl_map *map)
+{
+ return isl_map_get_space(map);
+}
+__isl_give isl_space *isl_union_map_get_dim(__isl_keep isl_union_map *umap)
+{
+ return isl_union_map_get_space(umap);
+}
+
+__isl_give isl_space *isl_basic_set_get_dim(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_set_get_space(bset);
+}
+__isl_give isl_space *isl_set_get_dim(__isl_keep isl_set *set)
+{
+ return isl_set_get_space(set);
+}
+__isl_give isl_space *isl_union_set_get_dim(__isl_keep isl_union_set *uset)
+{
+ return isl_union_set_get_space(uset);
+}
+
+__isl_give isl_space *isl_point_get_dim(__isl_keep isl_point *pnt)
+{
+ return isl_point_get_space(pnt);
+}
+
+__isl_give isl_space *isl_qpolynomial_get_dim(__isl_keep isl_qpolynomial *qp)
+{
+ return isl_qpolynomial_get_space(qp);
+}
+__isl_give isl_space *isl_pw_qpolynomial_get_dim(
+ __isl_keep isl_pw_qpolynomial *pwqp)
+{
+ return isl_pw_qpolynomial_get_space(pwqp);
+}
+__isl_give isl_space *isl_qpolynomial_fold_get_dim(
+ __isl_keep isl_qpolynomial_fold *fold)
+{
+ return isl_qpolynomial_fold_get_space(fold);
+}
+__isl_give isl_space *isl_pw_qpolynomial_fold_get_dim(
+ __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+ return isl_pw_qpolynomial_fold_get_space(pwf);
+}
+__isl_give isl_space *isl_union_pw_qpolynomial_get_dim(
+ __isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+ return isl_union_pw_qpolynomial_get_space(upwqp);
+}
+__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_dim(
+ __isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+ return isl_union_pw_qpolynomial_fold_get_space(upwf);
+}
Added: polly/trunk/lib/External/isl/isl_dim_map.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim_map.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim_map.c (added)
+++ polly/trunk/lib/External/isl/isl_dim_map.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_map_private.h>
+#include <isl_space_private.h>
+#include <isl_dim_map.h>
+#include <isl_reordering.h>
+
+struct isl_dim_map_entry {
+ int pos;
+ int sgn;
+};
+
+/* Maps dst positions to src positions */
+struct isl_dim_map {
+ unsigned len;
+ struct isl_dim_map_entry m[1];
+};
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len)
+{
+ int i;
+ struct isl_dim_map *dim_map;
+ dim_map = isl_alloc(ctx, struct isl_dim_map,
+ sizeof(struct isl_dim_map) + len * sizeof(struct isl_dim_map_entry));
+ if (!dim_map)
+ return NULL;
+ dim_map->len = 1 + len;
+ dim_map->m[0].pos = 0;
+ dim_map->m[0].sgn = 1;
+ for (i = 0; i < len; ++i)
+ dim_map->m[1 + i].sgn = 0;
+ return dim_map;
+}
+
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+ unsigned dst_pos, unsigned dst_stride,
+ unsigned src_pos, unsigned src_stride,
+ unsigned n, int sign)
+{
+ int i;
+
+ if (!dim_map)
+ return;
+
+ for (i = 0; i < n; ++i) {
+ unsigned d = 1 + dst_pos + dst_stride * i;
+ unsigned s = 1 + src_pos + src_stride * i;
+ dim_map->m[d].pos = s;
+ dim_map->m[d].sgn = sign;
+ }
+}
+
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+ __isl_keep isl_space *dim, enum isl_dim_type type,
+ unsigned first, unsigned n, unsigned dst_pos)
+{
+ int i;
+ unsigned src_pos;
+
+ if (!dim_map || !dim)
+ return;
+
+ src_pos = 1 + isl_space_offset(dim, type);
+ for (i = 0; i < n; ++i) {
+ dim_map->m[1 + dst_pos + i].pos = src_pos + first + i;
+ dim_map->m[1 + dst_pos + i].sgn = 1;
+ }
+}
+
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+ enum isl_dim_type type, unsigned dst_pos)
+{
+ isl_dim_map_dim_range(dim_map, dim, type,
+ 0, isl_space_dim(dim, type), dst_pos);
+}
+
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+ __isl_keep isl_basic_map *bmap, unsigned dst_pos)
+{
+ int i;
+ unsigned src_pos;
+
+ if (!dim_map || !bmap)
+ return;
+
+ src_pos = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+ for (i = 0; i < bmap->n_div; ++i) {
+ dim_map->m[1 + dst_pos + i].pos = src_pos + i;
+ dim_map->m[1 + dst_pos + i].sgn = 1;
+ }
+}
+
+void isl_dim_map_dump(struct isl_dim_map *dim_map)
+{
+ int i;
+
+ for (i = 0; i < dim_map->len; ++i)
+ fprintf(stderr, "%d -> %d * %d; ", i,
+ dim_map->m[i].sgn, dim_map->m[i].pos);
+ fprintf(stderr, "\n");
+}
+
+static void copy_constraint_dim_map(isl_int *dst, isl_int *src,
+ struct isl_dim_map *dim_map)
+{
+ int i;
+
+ for (i = 0; i < dim_map->len; ++i) {
+ if (dim_map->m[i].sgn == 0)
+ isl_int_set_si(dst[i], 0);
+ else if (dim_map->m[i].sgn > 0)
+ isl_int_set(dst[i], src[dim_map->m[i].pos]);
+ else
+ isl_int_neg(dst[i], src[dim_map->m[i].pos]);
+ }
+}
+
+static void copy_div_dim_map(isl_int *dst, isl_int *src,
+ struct isl_dim_map *dim_map)
+{
+ isl_int_set(dst[0], src[0]);
+ copy_constraint_dim_map(dst+1, src+1, dim_map);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+ __isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+ __isl_take isl_dim_map *dim_map)
+{
+ int i;
+
+ if (!src || !dst || !dim_map)
+ goto error;
+
+ for (i = 0; i < src->n_eq; ++i) {
+ int i1 = isl_basic_map_alloc_equality(dst);
+ if (i1 < 0)
+ goto error;
+ copy_constraint_dim_map(dst->eq[i1], src->eq[i], dim_map);
+ }
+
+ for (i = 0; i < src->n_ineq; ++i) {
+ int i1 = isl_basic_map_alloc_inequality(dst);
+ if (i1 < 0)
+ goto error;
+ copy_constraint_dim_map(dst->ineq[i1], src->ineq[i], dim_map);
+ }
+
+ for (i = 0; i < src->n_div; ++i) {
+ int i1 = isl_basic_map_alloc_div(dst);
+ if (i1 < 0)
+ goto error;
+ copy_div_dim_map(dst->div[i1], src->div[i], dim_map);
+ }
+
+ free(dim_map);
+ isl_basic_map_free(src);
+
+ return dst;
+error:
+ free(dim_map);
+ isl_basic_map_free(src);
+ isl_basic_map_free(dst);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+ __isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+ __isl_take isl_dim_map *dim_map)
+{
+ return isl_basic_map_add_constraints_dim_map(dst, src, dim_map);
+}
+
+/* Extend the given dim_map with mappings for the divs in bmap.
+ */
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+ __isl_keep isl_basic_map *bmap)
+{
+ int i;
+ struct isl_dim_map *res;
+ int offset;
+
+ offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+ res = isl_dim_map_alloc(bmap->ctx, dim_map->len - 1 + bmap->n_div);
+ if (!res)
+ return NULL;
+
+ for (i = 0; i < dim_map->len; ++i)
+ res->m[i] = dim_map->m[i];
+ for (i = 0; i < bmap->n_div; ++i) {
+ res->m[dim_map->len + i].pos = offset + i;
+ res->m[dim_map->len + i].sgn = 1;
+ }
+
+ return res;
+}
+
+/* Extract a dim_map from a reordering.
+ * We essentially need to reverse the mapping, and add an offset
+ * of 1 for the constant term.
+ */
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+ __isl_keep isl_reordering *exp)
+{
+ int i;
+ isl_ctx *ctx;
+ struct isl_dim_map *dim_map;
+
+ if (!exp)
+ return NULL;
+
+ ctx = isl_space_get_ctx(exp->dim);
+ dim_map = isl_dim_map_alloc(ctx, isl_space_dim(exp->dim, isl_dim_all));
+ if (!dim_map)
+ return NULL;
+
+ for (i = 0; i < exp->len; ++i) {
+ dim_map->m[1 + exp->pos[i]].pos = 1 + i;
+ dim_map->m[1 + exp->pos[i]].sgn = 1;
+ }
+
+ return dim_map;
+}
Added: polly/trunk/lib/External/isl/isl_dim_map.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_dim_map.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_dim_map.h (added)
+++ polly/trunk/lib/External/isl/isl_dim_map.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,36 @@
+#ifndef ISL_DIM_MAP_H
+#define ISL_DIM_MAP_H
+
+#include <isl/ctx.h>
+#include <isl/space.h>
+#include <isl/map.h>
+
+struct isl_dim_map;
+typedef struct isl_dim_map isl_dim_map;
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len);
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+ unsigned dst_pos, unsigned dst_stride,
+ unsigned src_pos, unsigned src_stride,
+ unsigned n, int sign);
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+ isl_space *dim, enum isl_dim_type type,
+ unsigned first, unsigned n, unsigned dst_pos);
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+ enum isl_dim_type type, unsigned dst_pos);
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+ __isl_keep isl_basic_map *bmap, unsigned dst_pos);
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+ __isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+ __isl_take isl_dim_map *dim_map);
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+ __isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+ __isl_take isl_dim_map *dim_map);
+
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+ __isl_keep isl_basic_map *bmap);
+
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+ __isl_keep isl_reordering *exp);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_equalities.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_equalities.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_equalities.c (added)
+++ polly/trunk/lib/External/isl/isl_equalities.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,782 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+#include "isl_map_private.h"
+#include "isl_equalities.h"
+#include <isl_val_private.h>
+
+/* Given a set of modulo constraints
+ *
+ * c + A y = 0 mod d
+ *
+ * this function computes a particular solution y_0
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ *
+ * The output is matrix containing the solution y_0 or
+ * a zero-column matrix if the constraints admit no integer solution.
+ *
+ * The given set of constrains is equivalent to
+ *
+ * c + A y = -D x
+ *
+ * with D = diag d and x a fresh set of variables.
+ * Reducing both c and A modulo d does not change the
+ * value of y in the solution and may lead to smaller coefficients.
+ * Let M = [ D A ] and [ H 0 ] = M U, the Hermite normal form of M.
+ * Then
+ * [ x ]
+ * M [ y ] = - c
+ * and so
+ * [ x ]
+ * [ H 0 ] U^{-1} [ y ] = - c
+ * Let
+ * [ A ] [ x ]
+ * [ B ] = U^{-1} [ y ]
+ * then
+ * H A + 0 B = -c
+ *
+ * so B may be chosen arbitrarily, e.g., B = 0, and then
+ *
+ * [ x ] = [ -c ]
+ * U^{-1} [ y ] = [ 0 ]
+ * or
+ * [ x ] [ -c ]
+ * [ y ] = U [ 0 ]
+ * specifically,
+ *
+ * y = U_{2,1} (-c)
+ *
+ * If any of the coordinates of this y are non-integer
+ * then the constraints admit no integer solution and
+ * a zero-column matrix is returned.
+ */
+static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d)
+{
+ int i, j;
+ struct isl_mat *M = NULL;
+ struct isl_mat *C = NULL;
+ struct isl_mat *U = NULL;
+ struct isl_mat *H = NULL;
+ struct isl_mat *cst = NULL;
+ struct isl_mat *T = NULL;
+
+ M = isl_mat_alloc(B->ctx, B->n_row, B->n_row + B->n_col - 1);
+ C = isl_mat_alloc(B->ctx, 1 + B->n_row, 1);
+ if (!M || !C)
+ goto error;
+ isl_int_set_si(C->row[0][0], 1);
+ for (i = 0; i < B->n_row; ++i) {
+ isl_seq_clr(M->row[i], B->n_row);
+ isl_int_set(M->row[i][i], d->block.data[i]);
+ isl_int_neg(C->row[1 + i][0], B->row[i][0]);
+ isl_int_fdiv_r(C->row[1+i][0], C->row[1+i][0], M->row[i][i]);
+ for (j = 0; j < B->n_col - 1; ++j)
+ isl_int_fdiv_r(M->row[i][B->n_row + j],
+ B->row[i][1 + j], M->row[i][i]);
+ }
+ M = isl_mat_left_hermite(M, 0, &U, NULL);
+ if (!M || !U)
+ goto error;
+ H = isl_mat_sub_alloc(M, 0, B->n_row, 0, B->n_row);
+ H = isl_mat_lin_to_aff(H);
+ C = isl_mat_inverse_product(H, C);
+ if (!C)
+ goto error;
+ for (i = 0; i < B->n_row; ++i) {
+ if (!isl_int_is_divisible_by(C->row[1+i][0], C->row[0][0]))
+ break;
+ isl_int_divexact(C->row[1+i][0], C->row[1+i][0], C->row[0][0]);
+ }
+ if (i < B->n_row)
+ cst = isl_mat_alloc(B->ctx, B->n_row, 0);
+ else
+ cst = isl_mat_sub_alloc(C, 1, B->n_row, 0, 1);
+ T = isl_mat_sub_alloc(U, B->n_row, B->n_col - 1, 0, B->n_row);
+ cst = isl_mat_product(T, cst);
+ isl_mat_free(M);
+ isl_mat_free(C);
+ isl_mat_free(U);
+ return cst;
+error:
+ isl_mat_free(M);
+ isl_mat_free(C);
+ isl_mat_free(U);
+ return NULL;
+}
+
+/* Compute and return the matrix
+ *
+ * U_1^{-1} diag(d_1, 1, ..., 1)
+ *
+ * with U_1 the unimodular completion of the first (and only) row of B.
+ * The columns of this matrix generate the lattice that satisfies
+ * the single (linear) modulo constraint.
+ */
+static struct isl_mat *parameter_compression_1(
+ struct isl_mat *B, struct isl_vec *d)
+{
+ struct isl_mat *U;
+
+ U = isl_mat_alloc(B->ctx, B->n_col - 1, B->n_col - 1);
+ if (!U)
+ return NULL;
+ isl_seq_cpy(U->row[0], B->row[0] + 1, B->n_col - 1);
+ U = isl_mat_unimodular_complete(U, 1);
+ U = isl_mat_right_inverse(U);
+ if (!U)
+ return NULL;
+ isl_mat_col_mul(U, 0, d->block.data[0], 0);
+ U = isl_mat_lin_to_aff(U);
+ return U;
+}
+
+/* Compute a common lattice of solutions to the linear modulo
+ * constraints specified by B and d.
+ * See also the documentation of isl_mat_parameter_compression.
+ * We put the matrix
+ *
+ * A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * on a common denominator. This denominator D is the lcm of modulos d.
+ * Since L_i = U_i^{-1} diag(d_i, 1, ... 1), we have
+ * L_i^{-T} = U_i^T diag(d_i, 1, ... 1)^{-T} = U_i^T diag(1/d_i, 1, ..., 1).
+ * Putting this on the common denominator, we have
+ * D * L_i^{-T} = U_i^T diag(D/d_i, D, ..., D).
+ */
+static struct isl_mat *parameter_compression_multi(
+ struct isl_mat *B, struct isl_vec *d)
+{
+ int i, j, k;
+ isl_int D;
+ struct isl_mat *A = NULL, *U = NULL;
+ struct isl_mat *T;
+ unsigned size;
+
+ isl_int_init(D);
+
+ isl_vec_lcm(d, &D);
+
+ size = B->n_col - 1;
+ A = isl_mat_alloc(B->ctx, size, B->n_row * size);
+ U = isl_mat_alloc(B->ctx, size, size);
+ if (!U || !A)
+ goto error;
+ for (i = 0; i < B->n_row; ++i) {
+ isl_seq_cpy(U->row[0], B->row[i] + 1, size);
+ U = isl_mat_unimodular_complete(U, 1);
+ if (!U)
+ goto error;
+ isl_int_divexact(D, D, d->block.data[i]);
+ for (k = 0; k < U->n_col; ++k)
+ isl_int_mul(A->row[k][i*size+0], D, U->row[0][k]);
+ isl_int_mul(D, D, d->block.data[i]);
+ for (j = 1; j < U->n_row; ++j)
+ for (k = 0; k < U->n_col; ++k)
+ isl_int_mul(A->row[k][i*size+j],
+ D, U->row[j][k]);
+ }
+ A = isl_mat_left_hermite(A, 0, NULL, NULL);
+ T = isl_mat_sub_alloc(A, 0, A->n_row, 0, A->n_row);
+ T = isl_mat_lin_to_aff(T);
+ if (!T)
+ goto error;
+ isl_int_set(T->row[0][0], D);
+ T = isl_mat_right_inverse(T);
+ if (!T)
+ goto error;
+ isl_assert(T->ctx, isl_int_is_one(T->row[0][0]), goto error);
+ T = isl_mat_transpose(T);
+ isl_mat_free(A);
+ isl_mat_free(U);
+
+ isl_int_clear(D);
+ return T;
+error:
+ isl_mat_free(A);
+ isl_mat_free(U);
+ isl_int_clear(D);
+ return NULL;
+}
+
+/* Given a set of modulo constraints
+ *
+ * c + A y = 0 mod d
+ *
+ * this function returns an affine transformation T,
+ *
+ * y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints.
+ *
+ * This function is inspired by Section 2.5.3
+ * of B. Meister, "Stating and Manipulating Periodicity in the Polytope
+ * Model. Applications to Program Analysis and Optimization".
+ * However, the implementation only follows the algorithm of that
+ * section for computing a particular solution and not for computing
+ * a general homogeneous solution. The latter is incomplete and
+ * may remove some valid solutions.
+ * Instead, we use an adaptation of the algorithm in Section 7 of
+ * B. Meister, S. Verdoolaege, "Polynomial Approximations in the Polytope
+ * Model: Bringing the Power of Quasi-Polynomials to the Masses".
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ * Each element of the vector d corresponds to a row in B.
+ * The output is a lower triangular matrix.
+ * If no integer vector y satisfies the given constraints then
+ * a matrix with zero columns is returned.
+ *
+ * We first compute a particular solution y_0 to the given set of
+ * modulo constraints in particular_solution. If no such solution
+ * exists, then we return a zero-columned transformation matrix.
+ * Otherwise, we compute the generic solution to
+ *
+ * A y = 0 mod d
+ *
+ * That is we want to compute G such that
+ *
+ * y = G y''
+ *
+ * with y'' integer, describes the set of solutions.
+ *
+ * We first remove the common factors of each row.
+ * In particular if gcd(A_i,d_i) != 1, then we divide the whole
+ * row i (including d_i) by this common factor. If afterwards gcd(A_i) != 1,
+ * then we divide this row of A by the common factor, unless gcd(A_i) = 0.
+ * In the later case, we simply drop the row (in both A and d).
+ *
+ * If there are no rows left in A, then G is the identity matrix. Otherwise,
+ * for each row i, we now determine the lattice of integer vectors
+ * that satisfies this row. Let U_i be the unimodular extension of the
+ * row A_i. This unimodular extension exists because gcd(A_i) = 1.
+ * The first component of
+ *
+ * y' = U_i y
+ *
+ * needs to be a multiple of d_i. Let y' = diag(d_i, 1, ..., 1) y''.
+ * Then,
+ *
+ * y = U_i^{-1} diag(d_i, 1, ..., 1) y''
+ *
+ * for arbitrary integer vectors y''. That is, y belongs to the lattice
+ * generated by the columns of L_i = U_i^{-1} diag(d_i, 1, ..., 1).
+ * If there is only one row, then G = L_1.
+ *
+ * If there is more than one row left, we need to compute the intersection
+ * of the lattices. That is, we need to compute an L such that
+ *
+ * L = L_i L_i' for all i
+ *
+ * with L_i' some integer matrices. Let A be constructed as follows
+ *
+ * A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * and computed the Hermite Normal Form of A = [ H 0 ] U
+ * Then,
+ *
+ * L_i^{-T} = H U_{1,i}
+ *
+ * or
+ *
+ * H^{-T} = L_i U_{1,i}^T
+ *
+ * In other words G = L = H^{-T}.
+ * To ensure that G is lower triangular, we compute and use its Hermite
+ * normal form.
+ *
+ * The affine transformation matrix returned is then
+ *
+ * [ 1 0 ]
+ * [ y_0 G ]
+ *
+ * as any y = y_0 + G y' with y' integer is a solution to the original
+ * modulo constraints.
+ */
+struct isl_mat *isl_mat_parameter_compression(
+ struct isl_mat *B, struct isl_vec *d)
+{
+ int i;
+ struct isl_mat *cst = NULL;
+ struct isl_mat *T = NULL;
+ isl_int D;
+
+ if (!B || !d)
+ goto error;
+ isl_assert(B->ctx, B->n_row == d->size, goto error);
+ cst = particular_solution(B, d);
+ if (!cst)
+ goto error;
+ if (cst->n_col == 0) {
+ T = isl_mat_alloc(B->ctx, B->n_col, 0);
+ isl_mat_free(cst);
+ isl_mat_free(B);
+ isl_vec_free(d);
+ return T;
+ }
+ isl_int_init(D);
+ /* Replace a*g*row = 0 mod g*m by row = 0 mod m */
+ for (i = 0; i < B->n_row; ++i) {
+ isl_seq_gcd(B->row[i] + 1, B->n_col - 1, &D);
+ if (isl_int_is_one(D))
+ continue;
+ if (isl_int_is_zero(D)) {
+ B = isl_mat_drop_rows(B, i, 1);
+ d = isl_vec_cow(d);
+ if (!B || !d)
+ goto error2;
+ isl_seq_cpy(d->block.data+i, d->block.data+i+1,
+ d->size - (i+1));
+ d->size--;
+ i--;
+ continue;
+ }
+ B = isl_mat_cow(B);
+ if (!B)
+ goto error2;
+ isl_seq_scale_down(B->row[i] + 1, B->row[i] + 1, D, B->n_col-1);
+ isl_int_gcd(D, D, d->block.data[i]);
+ d = isl_vec_cow(d);
+ if (!d)
+ goto error2;
+ isl_int_divexact(d->block.data[i], d->block.data[i], D);
+ }
+ isl_int_clear(D);
+ if (B->n_row == 0)
+ T = isl_mat_identity(B->ctx, B->n_col);
+ else if (B->n_row == 1)
+ T = parameter_compression_1(B, d);
+ else
+ T = parameter_compression_multi(B, d);
+ T = isl_mat_left_hermite(T, 0, NULL, NULL);
+ if (!T)
+ goto error;
+ isl_mat_sub_copy(T->ctx, T->row + 1, cst->row, cst->n_row, 0, 0, 1);
+ isl_mat_free(cst);
+ isl_mat_free(B);
+ isl_vec_free(d);
+ return T;
+error2:
+ isl_int_clear(D);
+error:
+ isl_mat_free(cst);
+ isl_mat_free(B);
+ isl_vec_free(d);
+ return NULL;
+}
+
+/* Given a set of equalities
+ *
+ * B(y) + A x = 0 (*)
+ *
+ * compute and return an affine transformation T,
+ *
+ * y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints for some value of x.
+ *
+ * Let [H 0] be the Hermite Normal Form of A, i.e.,
+ *
+ * A = [H 0] Q
+ *
+ * Then y is a solution of (*) iff
+ *
+ * H^-1 B(y) (= - [I 0] Q x)
+ *
+ * is an integer vector. Let d be the common denominator of H^-1.
+ * We impose
+ *
+ * d H^-1 B(y) = 0 mod d
+ *
+ * and compute the solution using isl_mat_parameter_compression.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+ __isl_take isl_mat *A)
+{
+ isl_ctx *ctx;
+ isl_vec *d;
+ int n_row, n_col;
+
+ if (!A)
+ return isl_mat_free(B);
+
+ ctx = isl_mat_get_ctx(A);
+ n_row = A->n_row;
+ n_col = A->n_col;
+ A = isl_mat_left_hermite(A, 0, NULL, NULL);
+ A = isl_mat_drop_cols(A, n_row, n_col - n_row);
+ A = isl_mat_lin_to_aff(A);
+ A = isl_mat_right_inverse(A);
+ d = isl_vec_alloc(ctx, n_row);
+ if (A)
+ d = isl_vec_set(d, A->row[0][0]);
+ A = isl_mat_drop_rows(A, 0, 1);
+ A = isl_mat_drop_cols(A, 0, 1);
+ B = isl_mat_product(A, B);
+
+ return isl_mat_parameter_compression(B, d);
+}
+
+/* Given a set of equalities
+ *
+ * M x - c = 0
+ *
+ * this function computes a unimodular transformation from a lower-dimensional
+ * space to the original space that bijectively maps the integer points x'
+ * in the lower-dimensional space to the integer points x in the original
+ * space that satisfy the equalities.
+ *
+ * The input is given as a matrix B = [ -c M ] and the output is a
+ * matrix that maps [1 x'] to [1 x].
+ * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x'].
+ *
+ * First compute the (left) Hermite normal form of M,
+ *
+ * M [U1 U2] = M U = H = [H1 0]
+ * or
+ * M = H Q = [H1 0] [Q1]
+ * [Q2]
+ *
+ * with U, Q unimodular, Q = U^{-1} (and H lower triangular).
+ * Define the transformed variables as
+ *
+ * x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x
+ * [ x2' ] [Q2]
+ *
+ * The equalities then become
+ *
+ * H1 x1' - c = 0 or x1' = H1^{-1} c = c'
+ *
+ * If any of the c' is non-integer, then the original set has no
+ * integer solutions (since the x' are a unimodular transformation
+ * of the x) and a zero-column matrix is returned.
+ * Otherwise, the transformation is given by
+ *
+ * x = U1 H1^{-1} c + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ * x2' = Q2 x
+ */
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+ __isl_give isl_mat **T2)
+{
+ int i;
+ struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
+ unsigned dim;
+
+ if (T2)
+ *T2 = NULL;
+ if (!B)
+ goto error;
+
+ dim = B->n_col - 1;
+ H = isl_mat_sub_alloc(B, 0, B->n_row, 1, dim);
+ H = isl_mat_left_hermite(H, 0, &U, T2);
+ if (!H || !U || (T2 && !*T2))
+ goto error;
+ if (T2) {
+ *T2 = isl_mat_drop_rows(*T2, 0, B->n_row);
+ *T2 = isl_mat_lin_to_aff(*T2);
+ if (!*T2)
+ goto error;
+ }
+ C = isl_mat_alloc(B->ctx, 1+B->n_row, 1);
+ if (!C)
+ goto error;
+ isl_int_set_si(C->row[0][0], 1);
+ isl_mat_sub_neg(C->ctx, C->row+1, B->row, B->n_row, 0, 0, 1);
+ H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+ H1 = isl_mat_lin_to_aff(H1);
+ TC = isl_mat_inverse_product(H1, C);
+ if (!TC)
+ goto error;
+ isl_mat_free(H);
+ if (!isl_int_is_one(TC->row[0][0])) {
+ for (i = 0; i < B->n_row; ++i) {
+ if (!isl_int_is_divisible_by(TC->row[1+i][0], TC->row[0][0])) {
+ struct isl_ctx *ctx = B->ctx;
+ isl_mat_free(B);
+ isl_mat_free(TC);
+ isl_mat_free(U);
+ if (T2) {
+ isl_mat_free(*T2);
+ *T2 = NULL;
+ }
+ return isl_mat_alloc(ctx, 1 + dim, 0);
+ }
+ isl_seq_scale_down(TC->row[1+i], TC->row[1+i], TC->row[0][0], 1);
+ }
+ isl_int_set_si(TC->row[0][0], 1);
+ }
+ U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, B->n_row);
+ U1 = isl_mat_lin_to_aff(U1);
+ U2 = isl_mat_sub_alloc(U, 0, U->n_row, B->n_row, U->n_row - B->n_row);
+ U2 = isl_mat_lin_to_aff(U2);
+ isl_mat_free(U);
+ TC = isl_mat_product(U1, TC);
+ TC = isl_mat_aff_direct_sum(TC, U2);
+
+ isl_mat_free(B);
+
+ return TC;
+error:
+ isl_mat_free(B);
+ isl_mat_free(H);
+ isl_mat_free(U);
+ if (T2) {
+ isl_mat_free(*T2);
+ *T2 = NULL;
+ }
+ return NULL;
+}
+
+/* Use the n equalities of bset to unimodularly transform the
+ * variables x such that n transformed variables x1' have a constant value
+ * and rewrite the constraints of bset in terms of the remaining
+ * transformed variables x2'. The matrix pointed to by T maps
+ * the new variables x2' back to the original variables x, while T2
+ * maps the original variables to the new variables.
+ */
+static struct isl_basic_set *compress_variables(
+ struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+ struct isl_mat *B, *TC;
+ unsigned dim;
+
+ if (T)
+ *T = NULL;
+ if (T2)
+ *T2 = NULL;
+ if (!bset)
+ goto error;
+ isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+ isl_assert(bset->ctx, bset->n_div == 0, goto error);
+ dim = isl_basic_set_n_dim(bset);
+ isl_assert(bset->ctx, bset->n_eq <= dim, goto error);
+ if (bset->n_eq == 0)
+ return bset;
+
+ B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
+ TC = isl_mat_variable_compression(B, T2);
+ if (!TC)
+ goto error;
+ if (TC->n_col == 0) {
+ isl_mat_free(TC);
+ if (T2) {
+ isl_mat_free(*T2);
+ *T2 = NULL;
+ }
+ return isl_basic_set_set_to_empty(bset);
+ }
+
+ bset = isl_basic_set_preimage(bset, T ? isl_mat_copy(TC) : TC);
+ if (T)
+ *T = TC;
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_remove_equalities(
+ struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+ if (T)
+ *T = NULL;
+ if (T2)
+ *T2 = NULL;
+ if (!bset)
+ return NULL;
+ isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+ bset = isl_basic_set_gauss(bset, NULL);
+ if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+ return bset;
+ bset = compress_variables(bset, T, T2);
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ *T = NULL;
+ return NULL;
+}
+
+/* Check if dimension dim belongs to a residue class
+ * i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+ int pos, isl_int *modulo, isl_int *residue)
+{
+ struct isl_ctx *ctx;
+ struct isl_mat *H = NULL, *U = NULL, *C, *H1, *U1;
+ unsigned total;
+ unsigned nparam;
+
+ if (!bset || !modulo || !residue)
+ return -1;
+
+ if (isl_basic_set_plain_dim_is_fixed(bset, pos, residue)) {
+ isl_int_set_si(*modulo, 0);
+ return 0;
+ }
+
+ ctx = bset->ctx;
+ total = isl_basic_set_total_dim(bset);
+ nparam = isl_basic_set_n_param(bset);
+ H = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 1, total);
+ H = isl_mat_left_hermite(H, 0, &U, NULL);
+ if (!H)
+ return -1;
+
+ isl_seq_gcd(U->row[nparam + pos]+bset->n_eq,
+ total-bset->n_eq, modulo);
+ if (isl_int_is_zero(*modulo))
+ isl_int_set_si(*modulo, 1);
+ if (isl_int_is_one(*modulo)) {
+ isl_int_set_si(*residue, 0);
+ isl_mat_free(H);
+ isl_mat_free(U);
+ return 0;
+ }
+
+ C = isl_mat_alloc(bset->ctx, 1+bset->n_eq, 1);
+ if (!C)
+ goto error;
+ isl_int_set_si(C->row[0][0], 1);
+ isl_mat_sub_neg(C->ctx, C->row+1, bset->eq, bset->n_eq, 0, 0, 1);
+ H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+ H1 = isl_mat_lin_to_aff(H1);
+ C = isl_mat_inverse_product(H1, C);
+ isl_mat_free(H);
+ U1 = isl_mat_sub_alloc(U, nparam+pos, 1, 0, bset->n_eq);
+ U1 = isl_mat_lin_to_aff(U1);
+ isl_mat_free(U);
+ C = isl_mat_product(U1, C);
+ if (!C)
+ return -1;
+ if (!isl_int_is_divisible_by(C->row[1][0], C->row[0][0])) {
+ bset = isl_basic_set_copy(bset);
+ bset = isl_basic_set_set_to_empty(bset);
+ isl_basic_set_free(bset);
+ isl_int_set_si(*modulo, 1);
+ isl_int_set_si(*residue, 0);
+ return 0;
+ }
+ isl_int_divexact(*residue, C->row[1][0], C->row[0][0]);
+ isl_int_fdiv_r(*residue, *residue, *modulo);
+ isl_mat_free(C);
+ return 0;
+error:
+ isl_mat_free(H);
+ isl_mat_free(U);
+ return -1;
+}
+
+/* Check if dimension dim belongs to a residue class
+ * i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class(struct isl_set *set,
+ int pos, isl_int *modulo, isl_int *residue)
+{
+ isl_int m;
+ isl_int r;
+ int i;
+
+ if (!set || !modulo || !residue)
+ return -1;
+
+ if (set->n == 0) {
+ isl_int_set_si(*modulo, 0);
+ isl_int_set_si(*residue, 0);
+ return 0;
+ }
+
+ if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0)
+ return -1;
+
+ if (set->n == 1)
+ return 0;
+
+ if (isl_int_is_one(*modulo))
+ return 0;
+
+ isl_int_init(m);
+ isl_int_init(r);
+
+ for (i = 1; i < set->n; ++i) {
+ if (isl_basic_set_dim_residue_class(set->p[i], pos, &m, &r) < 0)
+ goto error;
+ isl_int_gcd(*modulo, *modulo, m);
+ isl_int_sub(m, *residue, r);
+ isl_int_gcd(*modulo, *modulo, m);
+ if (!isl_int_is_zero(*modulo))
+ isl_int_fdiv_r(*residue, *residue, *modulo);
+ if (isl_int_is_one(*modulo))
+ break;
+ }
+
+ isl_int_clear(m);
+ isl_int_clear(r);
+
+ return 0;
+error:
+ isl_int_clear(m);
+ isl_int_clear(r);
+ return -1;
+}
+
+/* Check if dimension "dim" belongs to a residue class
+ * i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+int isl_set_dim_residue_class_val(__isl_keep isl_set *set,
+ int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue)
+{
+ *modulo = NULL;
+ *residue = NULL;
+ if (!set)
+ return -1;
+ *modulo = isl_val_alloc(isl_set_get_ctx(set));
+ *residue = isl_val_alloc(isl_set_get_ctx(set));
+ if (!*modulo || !*residue)
+ goto error;
+ if (isl_set_dim_residue_class(set, pos,
+ &(*modulo)->n, &(*residue)->n) < 0)
+ goto error;
+ isl_int_set_si((*modulo)->d, 1);
+ isl_int_set_si((*residue)->d, 1);
+ return 0;
+error:
+ isl_val_free(*modulo);
+ isl_val_free(*residue);
+ return -1;
+}
Added: polly/trunk/lib/External/isl/isl_equalities.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_equalities.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_equalities.h (added)
+++ polly/trunk/lib/External/isl/isl_equalities.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_EQUALITIES_H
+#define ISL_EQUALITIES_H
+
+#include <isl/set.h>
+#include <isl/mat.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+ __isl_give isl_mat **T2);
+struct isl_mat *isl_mat_parameter_compression(
+ struct isl_mat *B, struct isl_vec *d);
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+ __isl_take isl_mat *A);
+struct isl_basic_set *isl_basic_set_remove_equalities(
+ struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
Added: polly/trunk/lib/External/isl/isl_factorization.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_factorization.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_factorization.c (added)
+++ polly/trunk/lib/External/isl/isl_factorization.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_map_private.h>
+#include <isl_factorization.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+
+static __isl_give isl_factorizer *isl_factorizer_alloc(
+ __isl_take isl_morph *morph, int n_group)
+{
+ isl_factorizer *f = NULL;
+ int *len = NULL;
+
+ if (!morph)
+ return NULL;
+
+ if (n_group > 0) {
+ len = isl_alloc_array(morph->dom->ctx, int, n_group);
+ if (!len)
+ goto error;
+ }
+
+ f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer);
+ if (!f)
+ goto error;
+
+ f->morph = morph;
+ f->n_group = n_group;
+ f->len = len;
+
+ return f;
+error:
+ free(len);
+ isl_morph_free(morph);
+ return NULL;
+}
+
+void isl_factorizer_free(__isl_take isl_factorizer *f)
+{
+ if (!f)
+ return;
+
+ isl_morph_free(f->morph);
+ free(f->len);
+ free(f);
+}
+
+void isl_factorizer_dump(__isl_take isl_factorizer *f)
+{
+ int i;
+
+ if (!f)
+ return;
+
+ isl_morph_print_internal(f->morph, stderr);
+ fprintf(stderr, "[");
+ for (i = 0; i < f->n_group; ++i) {
+ if (i)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "%d", f->len[i]);
+ }
+ fprintf(stderr, "]\n");
+}
+
+__isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset)
+{
+ return isl_factorizer_alloc(isl_morph_identity(bset), 0);
+}
+
+__isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset,
+ __isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len)
+{
+ int i;
+ unsigned nvar;
+ unsigned ovar;
+ isl_space *dim;
+ isl_basic_set *dom;
+ isl_basic_set *ran;
+ isl_morph *morph;
+ isl_factorizer *f;
+ isl_mat *id;
+
+ if (!bset || !Q || !U)
+ goto error;
+
+ ovar = 1 + isl_space_offset(bset->dim, isl_dim_set);
+ id = isl_mat_identity(bset->ctx, ovar);
+ Q = isl_mat_diagonal(isl_mat_copy(id), Q);
+ U = isl_mat_diagonal(id, U);
+
+ nvar = isl_basic_set_dim(bset, isl_dim_set);
+ dim = isl_basic_set_get_space(bset);
+ dom = isl_basic_set_universe(isl_space_copy(dim));
+ dim = isl_space_drop_dims(dim, isl_dim_set, 0, nvar);
+ dim = isl_space_add_dims(dim, isl_dim_set, nvar);
+ ran = isl_basic_set_universe(dim);
+ morph = isl_morph_alloc(dom, ran, Q, U);
+ f = isl_factorizer_alloc(morph, n);
+ if (!f)
+ return NULL;
+ for (i = 0; i < n; ++i)
+ f->len[i] = len[i];
+ return f;
+error:
+ isl_mat_free(Q);
+ isl_mat_free(U);
+ return NULL;
+}
+
+struct isl_factor_groups {
+ int *pos; /* for each column: row position of pivot */
+ int *group; /* group to which a column belongs */
+ int *cnt; /* number of columns in the group */
+ int *rowgroup; /* group to which a constraint belongs */
+};
+
+/* Initialize isl_factor_groups structure: find pivot row positions,
+ * each column initially belongs to its own group and the groups
+ * of the constraints are still unknown.
+ */
+static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+ int i, j;
+
+ if (!H)
+ return -1;
+
+ g->pos = isl_alloc_array(H->ctx, int, H->n_col);
+ g->group = isl_alloc_array(H->ctx, int, H->n_col);
+ g->cnt = isl_alloc_array(H->ctx, int, H->n_col);
+ g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row);
+
+ if (!g->pos || !g->group || !g->cnt || !g->rowgroup)
+ return -1;
+
+ for (i = 0; i < H->n_row; ++i)
+ g->rowgroup[i] = -1;
+ for (i = 0, j = 0; i < H->n_col; ++i) {
+ for ( ; j < H->n_row; ++j)
+ if (!isl_int_is_zero(H->row[j][i]))
+ break;
+ g->pos[i] = j;
+ }
+ for (i = 0; i < H->n_col; ++i) {
+ g->group[i] = i;
+ g->cnt[i] = 1;
+ }
+
+ return 0;
+}
+
+/* Update group[k] to the group column k belongs to.
+ * When merging two groups, only the group of the current
+ * group leader is changed. Here we change the group of
+ * the other members to also point to the group that the
+ * old group leader now points to.
+ */
+static void update_group(struct isl_factor_groups *g, int k)
+{
+ int p = g->group[k];
+ while (g->cnt[p] == 0)
+ p = g->group[p];
+ g->group[k] = p;
+}
+
+/* Merge group i with all groups of the subsequent columns
+ * with non-zero coefficients in row j of H.
+ * (The previous columns are all zero; otherwise we would have handled
+ * the row before.)
+ */
+static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j,
+ __isl_keep isl_mat *H)
+{
+ int k;
+
+ g->rowgroup[j] = g->group[i];
+ for (k = i + 1; k < H->n_col && j >= g->pos[k]; ++k) {
+ update_group(g, k);
+ update_group(g, i);
+ if (g->group[k] != g->group[i] &&
+ !isl_int_is_zero(H->row[j][k])) {
+ isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1);
+ isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1);
+ if (g->group[i] < g->group[k]) {
+ g->cnt[g->group[i]] += g->cnt[g->group[k]];
+ g->cnt[g->group[k]] = 0;
+ g->group[g->group[k]] = g->group[i];
+ } else {
+ g->cnt[g->group[k]] += g->cnt[g->group[i]];
+ g->cnt[g->group[i]] = 0;
+ g->group[g->group[i]] = g->group[k];
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Update the group information based on the constraint matrix.
+ */
+static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+ int i, j;
+
+ for (i = 0; i < H->n_col && g->cnt[0] < H->n_col; ++i) {
+ if (g->pos[i] == H->n_row)
+ continue; /* A line direction */
+ if (g->rowgroup[g->pos[i]] == -1)
+ g->rowgroup[g->pos[i]] = i;
+ for (j = g->pos[i] + 1; j < H->n_row; ++j) {
+ if (isl_int_is_zero(H->row[j][i]))
+ continue;
+ if (g->rowgroup[j] != -1)
+ continue;
+ if (update_group_i_with_row_j(g, i, j, H) < 0)
+ return -1;
+ }
+ }
+ for (i = 1; i < H->n_col; ++i)
+ update_group(g, i);
+
+ return 0;
+}
+
+static void clear_groups(struct isl_factor_groups *g)
+{
+ if (!g)
+ return;
+ free(g->pos);
+ free(g->group);
+ free(g->cnt);
+ free(g->rowgroup);
+}
+
+/* Determine if the set variables of the basic set can be factorized and
+ * return the results in an isl_factorizer.
+ *
+ * The algorithm works by first computing the Hermite normal form
+ * and then grouping columns linked by one or more constraints together,
+ * where a constraints "links" two or more columns if the constraint
+ * has nonzero coefficients in the columns.
+ */
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+ __isl_keep isl_basic_set *bset)
+{
+ int i, j, n, done;
+ isl_mat *H, *U, *Q;
+ unsigned nvar;
+ struct isl_factor_groups g = { 0 };
+ isl_factorizer *f;
+
+ if (!bset)
+ return NULL;
+
+ isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0,
+ return NULL);
+
+ nvar = isl_basic_set_dim(bset, isl_dim_set);
+ if (nvar <= 1)
+ return isl_factorizer_identity(bset);
+
+ H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar);
+ if (!H)
+ return NULL;
+ isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq,
+ 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+ isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq,
+ 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+ H = isl_mat_left_hermite(H, 0, &U, &Q);
+
+ if (init_groups(&g, H) < 0)
+ goto error;
+ if (update_groups(&g, H) < 0)
+ goto error;
+
+ if (g.cnt[0] == nvar) {
+ isl_mat_free(H);
+ isl_mat_free(U);
+ isl_mat_free(Q);
+ clear_groups(&g);
+
+ return isl_factorizer_identity(bset);
+ }
+
+ done = 0;
+ n = 0;
+ while (done != nvar) {
+ int group = g.group[done];
+ for (i = 1; i < g.cnt[group]; ++i) {
+ if (g.group[done + i] == group)
+ continue;
+ for (j = done + g.cnt[group]; j < nvar; ++j)
+ if (g.group[j] == group)
+ break;
+ if (j == nvar)
+ isl_die(bset->ctx, isl_error_internal,
+ "internal error", goto error);
+ g.group[j] = g.group[done + i];
+ Q = isl_mat_swap_rows(Q, done + i, j);
+ U = isl_mat_swap_cols(U, done + i, j);
+ }
+ done += g.cnt[group];
+ g.pos[n++] = g.cnt[group];
+ }
+
+ f = isl_factorizer_groups(bset, Q, U, n, g.pos);
+
+ isl_mat_free(H);
+ clear_groups(&g);
+
+ return f;
+error:
+ isl_mat_free(H);
+ isl_mat_free(U);
+ isl_mat_free(Q);
+ clear_groups(&g);
+ return NULL;
+}
Added: polly/trunk/lib/External/isl/isl_factorization.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_factorization.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_factorization.h (added)
+++ polly/trunk/lib/External/isl/isl_factorization.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,29 @@
+#include <isl/set.h>
+#include <isl_morph.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Data for factorizing a particular basic set.
+ * After applying "morph" to the basic set, there are "n_group"
+ * groups of consecutive set variables, each of length "len[i]",
+ * with 0 <= i < n_group.
+ * If no factorization is possible, then "n_group" is set to 0.
+ */
+struct isl_factorizer {
+ isl_morph *morph;
+ int n_group;
+ int *len;
+};
+typedef struct isl_factorizer isl_factorizer;
+
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+ __isl_keep isl_basic_set *bset);
+
+void isl_factorizer_free(__isl_take isl_factorizer *f);
+void isl_factorizer_dump(__isl_take isl_factorizer *f);
+
+#if defined(__cplusplus)
+}
+#endif
Added: polly/trunk/lib/External/isl/isl_farkas.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_farkas.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_farkas.c (added)
+++ polly/trunk/lib/External/isl/isl_farkas.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+
+/*
+ * Let C be a cone and define
+ *
+ * C' := { y | forall x in C : y x >= 0 }
+ *
+ * C' contains the coefficients of all linear constraints
+ * that are valid for C.
+ * Furthermore, C'' = C.
+ *
+ * If C is defined as { x | A x >= 0 }
+ * then any element in C' must be a non-negative combination
+ * of the rows of A, i.e., y = t A with t >= 0. That is,
+ *
+ * C' = { y | exists t >= 0 : y = t A }
+ *
+ * If any of the rows in A actually represents an equality, then
+ * also negative combinations of this row are allowed and so the
+ * non-negativity constraint on the corresponding element of t
+ * can be dropped.
+ *
+ * A polyhedron P = { x | b + A x >= 0 } can be represented
+ * in homogeneous coordinates by the cone
+ * C = { [z,x] | b z + A x >= and z >= 0 }
+ * The valid linear constraints on C correspond to the valid affine
+ * constraints on P.
+ * This is essentially Farkas' lemma.
+ *
+ * Since
+ * [ 1 0 ]
+ * [ w y ] = [t_0 t] [ b A ]
+ *
+ * we have
+ *
+ * C' = { w, y | exists t_0, t >= 0 : y = t A and w = t_0 + t b }
+ * or
+ *
+ * C' = { w, y | exists t >= 0 : y = t A and w - t b >= 0 }
+ *
+ * In practice, we introduce an extra variable (w), shifting all
+ * other variables to the right, and an extra inequality
+ * (w - t b >= 0) corresponding to the positivity constraint on
+ * the homogeneous coordinate.
+ *
+ * When going back from coefficients to solutions, we immediately
+ * plug in 1 for z, which corresponds to shifting all variables
+ * to the left, with the leftmost ending up in the constant position.
+ */
+
+/* Add the given prefix to all named isl_dim_set dimensions in "dim".
+ */
+static __isl_give isl_space *isl_space_prefix(__isl_take isl_space *dim,
+ const char *prefix)
+{
+ int i;
+ isl_ctx *ctx;
+ unsigned nvar;
+ size_t prefix_len = strlen(prefix);
+
+ if (!dim)
+ return NULL;
+
+ ctx = isl_space_get_ctx(dim);
+ nvar = isl_space_dim(dim, isl_dim_set);
+
+ for (i = 0; i < nvar; ++i) {
+ const char *name;
+ char *prefix_name;
+
+ name = isl_space_get_dim_name(dim, isl_dim_set, i);
+ if (!name)
+ continue;
+
+ prefix_name = isl_alloc_array(ctx, char,
+ prefix_len + strlen(name) + 1);
+ if (!prefix_name)
+ goto error;
+ memcpy(prefix_name, prefix, prefix_len);
+ strcpy(prefix_name + prefix_len, name);
+
+ dim = isl_space_set_dim_name(dim, isl_dim_set, i, prefix_name);
+ free(prefix_name);
+ }
+
+ return dim;
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+/* Given a dimension specification of the solutions space, construct
+ * a dimension specification for the space of coefficients.
+ *
+ * In particular transform
+ *
+ * [params] -> { S }
+ *
+ * to
+ *
+ * { coefficients[[cst, params] -> S] }
+ *
+ * and prefix each dimension name with "c_".
+ */
+static __isl_give isl_space *isl_space_coefficients(__isl_take isl_space *dim)
+{
+ isl_space *dim_param;
+ unsigned nvar;
+ unsigned nparam;
+
+ nvar = isl_space_dim(dim, isl_dim_set);
+ nparam = isl_space_dim(dim, isl_dim_param);
+ dim_param = isl_space_copy(dim);
+ dim_param = isl_space_drop_dims(dim_param, isl_dim_set, 0, nvar);
+ dim_param = isl_space_move_dims(dim_param, isl_dim_set, 0,
+ isl_dim_param, 0, nparam);
+ dim_param = isl_space_prefix(dim_param, "c_");
+ dim_param = isl_space_insert_dims(dim_param, isl_dim_set, 0, 1);
+ dim_param = isl_space_set_dim_name(dim_param, isl_dim_set, 0, "c_cst");
+ dim = isl_space_drop_dims(dim, isl_dim_param, 0, nparam);
+ dim = isl_space_prefix(dim, "c_");
+ dim = isl_space_join(isl_space_from_domain(dim_param),
+ isl_space_from_range(dim));
+ dim = isl_space_wrap(dim);
+ dim = isl_space_set_tuple_name(dim, isl_dim_set, "coefficients");
+
+ return dim;
+}
+
+/* Drop the given prefix from all named dimensions of type "type" in "dim".
+ */
+static __isl_give isl_space *isl_space_unprefix(__isl_take isl_space *dim,
+ enum isl_dim_type type, const char *prefix)
+{
+ int i;
+ unsigned n;
+ size_t prefix_len = strlen(prefix);
+
+ n = isl_space_dim(dim, type);
+
+ for (i = 0; i < n; ++i) {
+ const char *name;
+
+ name = isl_space_get_dim_name(dim, type, i);
+ if (!name)
+ continue;
+ if (strncmp(name, prefix, prefix_len))
+ continue;
+
+ dim = isl_space_set_dim_name(dim, type, i, name + prefix_len);
+ }
+
+ return dim;
+}
+
+/* Given a dimension specification of the space of coefficients, construct
+ * a dimension specification for the space of solutions.
+ *
+ * In particular transform
+ *
+ * { coefficients[[cst, params] -> S] }
+ *
+ * to
+ *
+ * [params] -> { S }
+ *
+ * and drop the "c_" prefix from the dimension names.
+ */
+static __isl_give isl_space *isl_space_solutions(__isl_take isl_space *dim)
+{
+ unsigned nparam;
+
+ dim = isl_space_unwrap(dim);
+ dim = isl_space_drop_dims(dim, isl_dim_in, 0, 1);
+ dim = isl_space_unprefix(dim, isl_dim_in, "c_");
+ dim = isl_space_unprefix(dim, isl_dim_out, "c_");
+ nparam = isl_space_dim(dim, isl_dim_in);
+ dim = isl_space_move_dims(dim, isl_dim_param, 0, isl_dim_in, 0, nparam);
+ dim = isl_space_range(dim);
+
+ return dim;
+}
+
+/* Return the rational universe basic set in the given space.
+ */
+static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space)
+{
+ isl_basic_set *bset;
+
+ bset = isl_basic_set_universe(space);
+ bset = isl_basic_set_set_rational(bset);
+
+ return bset;
+}
+
+/* Compute the dual of "bset" by applying Farkas' lemma.
+ * As explained above, we add an extra dimension to represent
+ * the coefficient of the constant term when going from solutions
+ * to coefficients (shift == 1) and we drop the extra dimension when going
+ * in the opposite direction (shift == -1). "dim" is the space in which
+ * the dual should be created.
+ *
+ * If "bset" is (obviously) empty, then the way this emptiness
+ * is represented by the constraints does not allow for the application
+ * of the standard farkas algorithm. We therefore handle this case
+ * specifically and return the universe basic set.
+ */
+static __isl_give isl_basic_set *farkas(__isl_take isl_space *space,
+ __isl_take isl_basic_set *bset, int shift)
+{
+ int i, j, k;
+ isl_basic_set *dual = NULL;
+ unsigned total;
+
+ if (isl_basic_set_plain_is_empty(bset)) {
+ isl_basic_set_free(bset);
+ return rational_universe(space);
+ }
+
+ total = isl_basic_set_total_dim(bset);
+
+ dual = isl_basic_set_alloc_space(space, bset->n_eq + bset->n_ineq,
+ total, bset->n_ineq + (shift > 0));
+ dual = isl_basic_set_set_rational(dual);
+
+ for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
+ k = isl_basic_set_alloc_div(dual);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(dual->div[k][0], 0);
+ }
+
+ for (i = 0; i < total; ++i) {
+ k = isl_basic_set_alloc_equality(dual);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(dual->eq[k], 1 + shift + total);
+ isl_int_set_si(dual->eq[k][1 + shift + i], -1);
+ for (j = 0; j < bset->n_eq; ++j)
+ isl_int_set(dual->eq[k][1 + shift + total + j],
+ bset->eq[j][1 + i]);
+ for (j = 0; j < bset->n_ineq; ++j)
+ isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
+ bset->ineq[j][1 + i]);
+ }
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ k = isl_basic_set_alloc_inequality(dual);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(dual->ineq[k],
+ 1 + shift + total + bset->n_eq + bset->n_ineq);
+ isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
+ }
+
+ if (shift > 0) {
+ k = isl_basic_set_alloc_inequality(dual);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(dual->ineq[k], 2 + total);
+ isl_int_set_si(dual->ineq[k][1], 1);
+ for (j = 0; j < bset->n_eq; ++j)
+ isl_int_neg(dual->ineq[k][2 + total + j],
+ bset->eq[j][0]);
+ for (j = 0; j < bset->n_ineq; ++j)
+ isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
+ bset->ineq[j][0]);
+ }
+
+ dual = isl_basic_set_remove_divs(dual);
+ isl_basic_set_simplify(dual);
+ isl_basic_set_finalize(dual);
+
+ isl_basic_set_free(bset);
+ return dual;
+error:
+ isl_basic_set_free(bset);
+ isl_basic_set_free(dual);
+ return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+ __isl_take isl_basic_set *bset)
+{
+ isl_space *dim;
+
+ if (!bset)
+ return NULL;
+ if (bset->n_div)
+ isl_die(bset->ctx, isl_error_invalid,
+ "input set not allowed to have local variables",
+ goto error);
+
+ dim = isl_basic_set_get_space(bset);
+ dim = isl_space_coefficients(dim);
+
+ return farkas(dim, bset, 1);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_solutions(
+ __isl_take isl_basic_set *bset)
+{
+ isl_space *dim;
+
+ if (!bset)
+ return NULL;
+ if (bset->n_div)
+ isl_die(bset->ctx, isl_error_invalid,
+ "input set not allowed to have local variables",
+ goto error);
+
+ dim = isl_basic_set_get_space(bset);
+ dim = isl_space_solutions(dim);
+
+ return farkas(dim, bset, -1);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given set.
+ */
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
+{
+ int i;
+ isl_basic_set *coeff;
+
+ if (!set)
+ return NULL;
+ if (set->n == 0) {
+ isl_space *space = isl_set_get_space(set);
+ space = isl_space_coefficients(space);
+ isl_set_free(set);
+ return rational_universe(space);
+ }
+
+ coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
+
+ for (i = 1; i < set->n; ++i) {
+ isl_basic_set *bset, *coeff_i;
+ bset = isl_basic_set_copy(set->p[i]);
+ coeff_i = isl_basic_set_coefficients(bset);
+ coeff = isl_basic_set_intersect(coeff, coeff_i);
+ }
+
+ isl_set_free(set);
+ return coeff;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given set.
+ */
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
+{
+ int i;
+ isl_basic_set *sol;
+
+ if (!set)
+ return NULL;
+ if (set->n == 0) {
+ isl_space *space = isl_set_get_space(set);
+ space = isl_space_solutions(space);
+ isl_set_free(set);
+ return rational_universe(space);
+ }
+
+ sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
+
+ for (i = 1; i < set->n; ++i) {
+ isl_basic_set *bset, *sol_i;
+ bset = isl_basic_set_copy(set->p[i]);
+ sol_i = isl_basic_set_solutions(bset);
+ sol = isl_basic_set_intersect(sol, sol_i);
+ }
+
+ isl_set_free(set);
+ return sol;
+}
Added: polly/trunk/lib/External/isl/isl_flow.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_flow.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_flow.c (added)
+++ polly/trunk/lib/External/isl/isl_flow.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,1496 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ * Copyright 2012 Universiteit Leiden
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/flow.h>
+#include <isl_sort.h>
+
+enum isl_restriction_type {
+ isl_restriction_type_empty,
+ isl_restriction_type_none,
+ isl_restriction_type_input,
+ isl_restriction_type_output
+};
+
+struct isl_restriction {
+ enum isl_restriction_type type;
+
+ isl_set *source;
+ isl_set *sink;
+};
+
+/* Create a restriction of the given type.
+ */
+static __isl_give isl_restriction *isl_restriction_alloc(
+ __isl_take isl_map *source_map, enum isl_restriction_type type)
+{
+ isl_ctx *ctx;
+ isl_restriction *restr;
+
+ if (!source_map)
+ return NULL;
+
+ ctx = isl_map_get_ctx(source_map);
+ restr = isl_calloc_type(ctx, struct isl_restriction);
+ if (!restr)
+ goto error;
+
+ restr->type = type;
+
+ isl_map_free(source_map);
+ return restr;
+error:
+ isl_map_free(source_map);
+ return NULL;
+}
+
+/* Create a restriction that doesn't restrict anything.
+ */
+__isl_give isl_restriction *isl_restriction_none(__isl_take isl_map *source_map)
+{
+ return isl_restriction_alloc(source_map, isl_restriction_type_none);
+}
+
+/* Create a restriction that removes everything.
+ */
+__isl_give isl_restriction *isl_restriction_empty(
+ __isl_take isl_map *source_map)
+{
+ return isl_restriction_alloc(source_map, isl_restriction_type_empty);
+}
+
+/* Create a restriction on the input of the maximization problem
+ * based on the given source and sink restrictions.
+ */
+__isl_give isl_restriction *isl_restriction_input(
+ __isl_take isl_set *source_restr, __isl_take isl_set *sink_restr)
+{
+ isl_ctx *ctx;
+ isl_restriction *restr;
+
+ if (!source_restr || !sink_restr)
+ goto error;
+
+ ctx = isl_set_get_ctx(source_restr);
+ restr = isl_calloc_type(ctx, struct isl_restriction);
+ if (!restr)
+ goto error;
+
+ restr->type = isl_restriction_type_input;
+ restr->source = source_restr;
+ restr->sink = sink_restr;
+
+ return restr;
+error:
+ isl_set_free(source_restr);
+ isl_set_free(sink_restr);
+ return NULL;
+}
+
+/* Create a restriction on the output of the maximization problem
+ * based on the given source restriction.
+ */
+__isl_give isl_restriction *isl_restriction_output(
+ __isl_take isl_set *source_restr)
+{
+ isl_ctx *ctx;
+ isl_restriction *restr;
+
+ if (!source_restr)
+ return NULL;
+
+ ctx = isl_set_get_ctx(source_restr);
+ restr = isl_calloc_type(ctx, struct isl_restriction);
+ if (!restr)
+ goto error;
+
+ restr->type = isl_restriction_type_output;
+ restr->source = source_restr;
+
+ return restr;
+error:
+ isl_set_free(source_restr);
+ return NULL;
+}
+
+__isl_null isl_restriction *isl_restriction_free(
+ __isl_take isl_restriction *restr)
+{
+ if (!restr)
+ return NULL;
+
+ isl_set_free(restr->source);
+ isl_set_free(restr->sink);
+ free(restr);
+ return NULL;
+}
+
+isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr)
+{
+ return restr ? isl_set_get_ctx(restr->source) : NULL;
+}
+
+/* A private structure to keep track of a mapping together with
+ * a user-specified identifier and a boolean indicating whether
+ * the map represents a must or may access/dependence.
+ */
+struct isl_labeled_map {
+ struct isl_map *map;
+ void *data;
+ int must;
+};
+
+/* A structure containing the input for dependence analysis:
+ * - a sink
+ * - n_must + n_may (<= max_source) sources
+ * - a function for determining the relative order of sources and sink
+ * The must sources are placed before the may sources.
+ *
+ * domain_map is an auxiliary map that maps the sink access relation
+ * to the domain of this access relation.
+ *
+ * restrict_fn is a callback that (if not NULL) will be called
+ * right before any lexicographical maximization.
+ */
+struct isl_access_info {
+ isl_map *domain_map;
+ struct isl_labeled_map sink;
+ isl_access_level_before level_before;
+
+ isl_access_restrict restrict_fn;
+ void *restrict_user;
+
+ int max_source;
+ int n_must;
+ int n_may;
+ struct isl_labeled_map source[1];
+};
+
+/* A structure containing the output of dependence analysis:
+ * - n_source dependences
+ * - a wrapped subset of the sink for which definitely no source could be found
+ * - a wrapped subset of the sink for which possibly no source could be found
+ */
+struct isl_flow {
+ isl_set *must_no_source;
+ isl_set *may_no_source;
+ int n_source;
+ struct isl_labeled_map *dep;
+};
+
+/* Construct an isl_access_info structure and fill it up with
+ * the given data. The number of sources is set to 0.
+ */
+__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink,
+ void *sink_user, isl_access_level_before fn, int max_source)
+{
+ isl_ctx *ctx;
+ struct isl_access_info *acc;
+
+ if (!sink)
+ return NULL;
+
+ ctx = isl_map_get_ctx(sink);
+ isl_assert(ctx, max_source >= 0, goto error);
+
+ acc = isl_calloc(ctx, struct isl_access_info,
+ sizeof(struct isl_access_info) +
+ (max_source - 1) * sizeof(struct isl_labeled_map));
+ if (!acc)
+ goto error;
+
+ acc->sink.map = sink;
+ acc->sink.data = sink_user;
+ acc->level_before = fn;
+ acc->max_source = max_source;
+ acc->n_must = 0;
+ acc->n_may = 0;
+
+ return acc;
+error:
+ isl_map_free(sink);
+ return NULL;
+}
+
+/* Free the given isl_access_info structure.
+ */
+__isl_null isl_access_info *isl_access_info_free(
+ __isl_take isl_access_info *acc)
+{
+ int i;
+
+ if (!acc)
+ return NULL;
+ isl_map_free(acc->domain_map);
+ isl_map_free(acc->sink.map);
+ for (i = 0; i < acc->n_must + acc->n_may; ++i)
+ isl_map_free(acc->source[i].map);
+ free(acc);
+ return NULL;
+}
+
+isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc)
+{
+ return acc ? isl_map_get_ctx(acc->sink.map) : NULL;
+}
+
+__isl_give isl_access_info *isl_access_info_set_restrict(
+ __isl_take isl_access_info *acc, isl_access_restrict fn, void *user)
+{
+ if (!acc)
+ return NULL;
+ acc->restrict_fn = fn;
+ acc->restrict_user = user;
+ return acc;
+}
+
+/* Add another source to an isl_access_info structure, making
+ * sure the "must" sources are placed before the "may" sources.
+ * This function may be called at most max_source times on a
+ * given isl_access_info structure, with max_source as specified
+ * in the call to isl_access_info_alloc that constructed the structure.
+ */
+__isl_give isl_access_info *isl_access_info_add_source(
+ __isl_take isl_access_info *acc, __isl_take isl_map *source,
+ int must, void *source_user)
+{
+ isl_ctx *ctx;
+
+ if (!acc)
+ goto error;
+ ctx = isl_map_get_ctx(acc->sink.map);
+ isl_assert(ctx, acc->n_must + acc->n_may < acc->max_source, goto error);
+
+ if (must) {
+ if (acc->n_may)
+ acc->source[acc->n_must + acc->n_may] =
+ acc->source[acc->n_must];
+ acc->source[acc->n_must].map = source;
+ acc->source[acc->n_must].data = source_user;
+ acc->source[acc->n_must].must = 1;
+ acc->n_must++;
+ } else {
+ acc->source[acc->n_must + acc->n_may].map = source;
+ acc->source[acc->n_must + acc->n_may].data = source_user;
+ acc->source[acc->n_must + acc->n_may].must = 0;
+ acc->n_may++;
+ }
+
+ return acc;
+error:
+ isl_map_free(source);
+ isl_access_info_free(acc);
+ return NULL;
+}
+
+/* Return -n, 0 or n (with n a positive value), depending on whether
+ * the source access identified by p1 should be sorted before, together
+ * or after that identified by p2.
+ *
+ * If p1 appears before p2, then it should be sorted first.
+ * For more generic initial schedules, it is possible that neither
+ * p1 nor p2 appears before the other, or at least not in any obvious way.
+ * We therefore also check if p2 appears before p1, in which case p2
+ * should be sorted first.
+ * If not, we try to order the two statements based on the description
+ * of the iteration domains. This results in an arbitrary, but fairly
+ * stable ordering.
+ */
+static int access_sort_cmp(const void *p1, const void *p2, void *user)
+{
+ isl_access_info *acc = user;
+ const struct isl_labeled_map *i1, *i2;
+ int level1, level2;
+ uint32_t h1, h2;
+ i1 = (const struct isl_labeled_map *) p1;
+ i2 = (const struct isl_labeled_map *) p2;
+
+ level1 = acc->level_before(i1->data, i2->data);
+ if (level1 % 2)
+ return -1;
+
+ level2 = acc->level_before(i2->data, i1->data);
+ if (level2 % 2)
+ return 1;
+
+ h1 = isl_map_get_hash(i1->map);
+ h2 = isl_map_get_hash(i2->map);
+ return h1 > h2 ? 1 : h1 < h2 ? -1 : 0;
+}
+
+/* Sort the must source accesses in their textual order.
+ */
+static __isl_give isl_access_info *isl_access_info_sort_sources(
+ __isl_take isl_access_info *acc)
+{
+ if (!acc)
+ return NULL;
+ if (acc->n_must <= 1)
+ return acc;
+
+ if (isl_sort(acc->source, acc->n_must, sizeof(struct isl_labeled_map),
+ access_sort_cmp, acc) < 0)
+ return isl_access_info_free(acc);
+
+ return acc;
+}
+
+/* Align the parameters of the two spaces if needed and then call
+ * isl_space_join.
+ */
+static __isl_give isl_space *space_align_and_join(__isl_take isl_space *left,
+ __isl_take isl_space *right)
+{
+ if (isl_space_match(left, isl_dim_param, right, isl_dim_param))
+ return isl_space_join(left, right);
+
+ left = isl_space_align_params(left, isl_space_copy(right));
+ right = isl_space_align_params(right, isl_space_copy(left));
+ return isl_space_join(left, right);
+}
+
+/* Initialize an empty isl_flow structure corresponding to a given
+ * isl_access_info structure.
+ * For each must access, two dependences are created (initialized
+ * to the empty relation), one for the resulting must dependences
+ * and one for the resulting may dependences. May accesses can
+ * only lead to may dependences, so only one dependence is created
+ * for each of them.
+ * This function is private as isl_flow structures are only supposed
+ * to be created by isl_access_info_compute_flow.
+ */
+static __isl_give isl_flow *isl_flow_alloc(__isl_keep isl_access_info *acc)
+{
+ int i, n;
+ struct isl_ctx *ctx;
+ struct isl_flow *dep;
+
+ if (!acc)
+ return NULL;
+
+ ctx = isl_map_get_ctx(acc->sink.map);
+ dep = isl_calloc_type(ctx, struct isl_flow);
+ if (!dep)
+ return NULL;
+
+ n = 2 * acc->n_must + acc->n_may;
+ dep->dep = isl_calloc_array(ctx, struct isl_labeled_map, n);
+ if (n && !dep->dep)
+ goto error;
+
+ dep->n_source = n;
+ for (i = 0; i < acc->n_must; ++i) {
+ isl_space *dim;
+ dim = space_align_and_join(
+ isl_map_get_space(acc->source[i].map),
+ isl_space_reverse(isl_map_get_space(acc->sink.map)));
+ dep->dep[2 * i].map = isl_map_empty(dim);
+ dep->dep[2 * i + 1].map = isl_map_copy(dep->dep[2 * i].map);
+ dep->dep[2 * i].data = acc->source[i].data;
+ dep->dep[2 * i + 1].data = acc->source[i].data;
+ dep->dep[2 * i].must = 1;
+ dep->dep[2 * i + 1].must = 0;
+ if (!dep->dep[2 * i].map || !dep->dep[2 * i + 1].map)
+ goto error;
+ }
+ for (i = acc->n_must; i < acc->n_must + acc->n_may; ++i) {
+ isl_space *dim;
+ dim = space_align_and_join(
+ isl_map_get_space(acc->source[i].map),
+ isl_space_reverse(isl_map_get_space(acc->sink.map)));
+ dep->dep[acc->n_must + i].map = isl_map_empty(dim);
+ dep->dep[acc->n_must + i].data = acc->source[i].data;
+ dep->dep[acc->n_must + i].must = 0;
+ if (!dep->dep[acc->n_must + i].map)
+ goto error;
+ }
+
+ return dep;
+error:
+ isl_flow_free(dep);
+ return NULL;
+}
+
+/* Iterate over all sources and for each resulting flow dependence
+ * that is not empty, call the user specfied function.
+ * The second argument in this function call identifies the source,
+ * while the third argument correspond to the final argument of
+ * the isl_flow_foreach call.
+ */
+int isl_flow_foreach(__isl_keep isl_flow *deps,
+ int (*fn)(__isl_take isl_map *dep, int must, void *dep_user, void *user),
+ void *user)
+{
+ int i;
+
+ if (!deps)
+ return -1;
+
+ for (i = 0; i < deps->n_source; ++i) {
+ if (isl_map_plain_is_empty(deps->dep[i].map))
+ continue;
+ if (fn(isl_map_copy(deps->dep[i].map), deps->dep[i].must,
+ deps->dep[i].data, user) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Return a copy of the subset of the sink for which no source could be found.
+ */
+__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must)
+{
+ if (!deps)
+ return NULL;
+
+ if (must)
+ return isl_set_unwrap(isl_set_copy(deps->must_no_source));
+ else
+ return isl_set_unwrap(isl_set_copy(deps->may_no_source));
+}
+
+void isl_flow_free(__isl_take isl_flow *deps)
+{
+ int i;
+
+ if (!deps)
+ return;
+ isl_set_free(deps->must_no_source);
+ isl_set_free(deps->may_no_source);
+ if (deps->dep) {
+ for (i = 0; i < deps->n_source; ++i)
+ isl_map_free(deps->dep[i].map);
+ free(deps->dep);
+ }
+ free(deps);
+}
+
+isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps)
+{
+ return deps ? isl_set_get_ctx(deps->must_no_source) : NULL;
+}
+
+/* Return a map that enforces that the domain iteration occurs after
+ * the range iteration at the given level.
+ * If level is odd, then the domain iteration should occur after
+ * the target iteration in their shared level/2 outermost loops.
+ * In this case we simply need to enforce that these outermost
+ * loop iterations are the same.
+ * If level is even, then the loop iterator of the domain should
+ * be greater than the loop iterator of the range at the last
+ * of the level/2 shared loops, i.e., loop level/2 - 1.
+ */
+static __isl_give isl_map *after_at_level(__isl_take isl_space *dim, int level)
+{
+ struct isl_basic_map *bmap;
+
+ if (level % 2)
+ bmap = isl_basic_map_equal(dim, level/2);
+ else
+ bmap = isl_basic_map_more_at(dim, level/2 - 1);
+
+ return isl_map_from_basic_map(bmap);
+}
+
+/* Compute the partial lexicographic maximum of "dep" on domain "sink",
+ * but first check if the user has set acc->restrict_fn and if so
+ * update either the input or the output of the maximization problem
+ * with respect to the resulting restriction.
+ *
+ * Since the user expects a mapping from sink iterations to source iterations,
+ * whereas the domain of "dep" is a wrapped map, mapping sink iterations
+ * to accessed array elements, we first need to project out the accessed
+ * sink array elements by applying acc->domain_map.
+ * Similarly, the sink restriction specified by the user needs to be
+ * converted back to the wrapped map.
+ */
+static __isl_give isl_map *restricted_partial_lexmax(
+ __isl_keep isl_access_info *acc, __isl_take isl_map *dep,
+ int source, __isl_take isl_set *sink, __isl_give isl_set **empty)
+{
+ isl_map *source_map;
+ isl_restriction *restr;
+ isl_set *sink_domain;
+ isl_set *sink_restr;
+ isl_map *res;
+
+ if (!acc->restrict_fn)
+ return isl_map_partial_lexmax(dep, sink, empty);
+
+ source_map = isl_map_copy(dep);
+ source_map = isl_map_apply_domain(source_map,
+ isl_map_copy(acc->domain_map));
+ sink_domain = isl_set_copy(sink);
+ sink_domain = isl_set_apply(sink_domain, isl_map_copy(acc->domain_map));
+ restr = acc->restrict_fn(source_map, sink_domain,
+ acc->source[source].data, acc->restrict_user);
+ isl_set_free(sink_domain);
+ isl_map_free(source_map);
+
+ if (!restr)
+ goto error;
+ if (restr->type == isl_restriction_type_input) {
+ dep = isl_map_intersect_range(dep, isl_set_copy(restr->source));
+ sink_restr = isl_set_copy(restr->sink);
+ sink_restr = isl_set_apply(sink_restr,
+ isl_map_reverse(isl_map_copy(acc->domain_map)));
+ sink = isl_set_intersect(sink, sink_restr);
+ } else if (restr->type == isl_restriction_type_empty) {
+ isl_space *space = isl_map_get_space(dep);
+ isl_map_free(dep);
+ dep = isl_map_empty(space);
+ }
+
+ res = isl_map_partial_lexmax(dep, sink, empty);
+
+ if (restr->type == isl_restriction_type_output)
+ res = isl_map_intersect_range(res, isl_set_copy(restr->source));
+
+ isl_restriction_free(restr);
+ return res;
+error:
+ isl_map_free(dep);
+ isl_set_free(sink);
+ *empty = NULL;
+ return NULL;
+}
+
+/* Compute the last iteration of must source j that precedes the sink
+ * at the given level for sink iterations in set_C.
+ * The subset of set_C for which no such iteration can be found is returned
+ * in *empty.
+ */
+static struct isl_map *last_source(struct isl_access_info *acc,
+ struct isl_set *set_C,
+ int j, int level, struct isl_set **empty)
+{
+ struct isl_map *read_map;
+ struct isl_map *write_map;
+ struct isl_map *dep_map;
+ struct isl_map *after;
+ struct isl_map *result;
+
+ read_map = isl_map_copy(acc->sink.map);
+ write_map = isl_map_copy(acc->source[j].map);
+ write_map = isl_map_reverse(write_map);
+ dep_map = isl_map_apply_range(read_map, write_map);
+ after = after_at_level(isl_map_get_space(dep_map), level);
+ dep_map = isl_map_intersect(dep_map, after);
+ result = restricted_partial_lexmax(acc, dep_map, j, set_C, empty);
+ result = isl_map_reverse(result);
+
+ return result;
+}
+
+/* For a given mapping between iterations of must source j and iterations
+ * of the sink, compute the last iteration of must source k preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source j at level
+ * after_level.
+ */
+static struct isl_map *last_later_source(struct isl_access_info *acc,
+ struct isl_map *old_map,
+ int j, int before_level,
+ int k, int after_level,
+ struct isl_set **empty)
+{
+ isl_space *dim;
+ struct isl_set *set_C;
+ struct isl_map *read_map;
+ struct isl_map *write_map;
+ struct isl_map *dep_map;
+ struct isl_map *after_write;
+ struct isl_map *before_read;
+ struct isl_map *result;
+
+ set_C = isl_map_range(isl_map_copy(old_map));
+ read_map = isl_map_copy(acc->sink.map);
+ write_map = isl_map_copy(acc->source[k].map);
+
+ write_map = isl_map_reverse(write_map);
+ dep_map = isl_map_apply_range(read_map, write_map);
+ dim = space_align_and_join(isl_map_get_space(acc->source[k].map),
+ isl_space_reverse(isl_map_get_space(acc->source[j].map)));
+ after_write = after_at_level(dim, after_level);
+ after_write = isl_map_apply_range(after_write, old_map);
+ after_write = isl_map_reverse(after_write);
+ dep_map = isl_map_intersect(dep_map, after_write);
+ before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+ dep_map = isl_map_intersect(dep_map, before_read);
+ result = restricted_partial_lexmax(acc, dep_map, k, set_C, empty);
+ result = isl_map_reverse(result);
+
+ return result;
+}
+
+/* Given a shared_level between two accesses, return 1 if the
+ * the first can precede the second at the requested target_level.
+ * If the target level is odd, i.e., refers to a statement level
+ * dimension, then first needs to precede second at the requested
+ * level, i.e., shared_level must be equal to target_level.
+ * If the target level is odd, then the two loops should share
+ * at least the requested number of outer loops.
+ */
+static int can_precede_at_level(int shared_level, int target_level)
+{
+ if (shared_level < target_level)
+ return 0;
+ if ((target_level % 2) && shared_level > target_level)
+ return 0;
+ return 1;
+}
+
+/* Given a possible flow dependence temp_rel[j] between source j and the sink
+ * at level sink_level, remove those elements for which
+ * there is an iteration of another source k < j that is closer to the sink.
+ * The flow dependences temp_rel[k] are updated with the improved sources.
+ * Any improved source needs to precede the sink at the same level
+ * and needs to follow source j at the same or a deeper level.
+ * The lower this level, the later the execution date of source k.
+ * We therefore consider lower levels first.
+ *
+ * If temp_rel[j] is empty, then there can be no improvement and
+ * we return immediately.
+ */
+static int intermediate_sources(__isl_keep isl_access_info *acc,
+ struct isl_map **temp_rel, int j, int sink_level)
+{
+ int k, level;
+ int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1;
+
+ if (isl_map_plain_is_empty(temp_rel[j]))
+ return 0;
+
+ for (k = j - 1; k >= 0; --k) {
+ int plevel, plevel2;
+ plevel = acc->level_before(acc->source[k].data, acc->sink.data);
+ if (!can_precede_at_level(plevel, sink_level))
+ continue;
+
+ plevel2 = acc->level_before(acc->source[j].data,
+ acc->source[k].data);
+
+ for (level = sink_level; level <= depth; ++level) {
+ struct isl_map *T;
+ struct isl_set *trest;
+ struct isl_map *copy;
+
+ if (!can_precede_at_level(plevel2, level))
+ continue;
+
+ copy = isl_map_copy(temp_rel[j]);
+ T = last_later_source(acc, copy, j, sink_level, k,
+ level, &trest);
+ if (isl_map_plain_is_empty(T)) {
+ isl_set_free(trest);
+ isl_map_free(T);
+ continue;
+ }
+ temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest);
+ temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T);
+ }
+ }
+
+ return 0;
+}
+
+/* Compute all iterations of may source j that precedes the sink at the given
+ * level for sink iterations in set_C.
+ */
+static __isl_give isl_map *all_sources(__isl_keep isl_access_info *acc,
+ __isl_take isl_set *set_C, int j, int level)
+{
+ isl_map *read_map;
+ isl_map *write_map;
+ isl_map *dep_map;
+ isl_map *after;
+
+ read_map = isl_map_copy(acc->sink.map);
+ read_map = isl_map_intersect_domain(read_map, set_C);
+ write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+ write_map = isl_map_reverse(write_map);
+ dep_map = isl_map_apply_range(read_map, write_map);
+ after = after_at_level(isl_map_get_space(dep_map), level);
+ dep_map = isl_map_intersect(dep_map, after);
+
+ return isl_map_reverse(dep_map);
+}
+
+/* For a given mapping between iterations of must source k and iterations
+ * of the sink, compute the all iteration of may source j preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source k at level
+ * after_level.
+ */
+static __isl_give isl_map *all_later_sources(__isl_keep isl_access_info *acc,
+ __isl_take isl_map *old_map,
+ int j, int before_level, int k, int after_level)
+{
+ isl_space *dim;
+ isl_set *set_C;
+ isl_map *read_map;
+ isl_map *write_map;
+ isl_map *dep_map;
+ isl_map *after_write;
+ isl_map *before_read;
+
+ set_C = isl_map_range(isl_map_copy(old_map));
+ read_map = isl_map_copy(acc->sink.map);
+ read_map = isl_map_intersect_domain(read_map, set_C);
+ write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+
+ write_map = isl_map_reverse(write_map);
+ dep_map = isl_map_apply_range(read_map, write_map);
+ dim = isl_space_join(isl_map_get_space(acc->source[acc->n_must + j].map),
+ isl_space_reverse(isl_map_get_space(acc->source[k].map)));
+ after_write = after_at_level(dim, after_level);
+ after_write = isl_map_apply_range(after_write, old_map);
+ after_write = isl_map_reverse(after_write);
+ dep_map = isl_map_intersect(dep_map, after_write);
+ before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+ dep_map = isl_map_intersect(dep_map, before_read);
+ return isl_map_reverse(dep_map);
+}
+
+/* Given the must and may dependence relations for the must accesses
+ * for level sink_level, check if there are any accesses of may access j
+ * that occur in between and return their union.
+ * If some of these accesses are intermediate with respect to
+ * (previously thought to be) must dependences, then these
+ * must dependences are turned into may dependences.
+ */
+static __isl_give isl_map *all_intermediate_sources(
+ __isl_keep isl_access_info *acc, __isl_take isl_map *map,
+ struct isl_map **must_rel, struct isl_map **may_rel,
+ int j, int sink_level)
+{
+ int k, level;
+ int depth = 2 * isl_map_dim(acc->source[acc->n_must + j].map,
+ isl_dim_in) + 1;
+
+ for (k = 0; k < acc->n_must; ++k) {
+ int plevel;
+
+ if (isl_map_plain_is_empty(may_rel[k]) &&
+ isl_map_plain_is_empty(must_rel[k]))
+ continue;
+
+ plevel = acc->level_before(acc->source[k].data,
+ acc->source[acc->n_must + j].data);
+
+ for (level = sink_level; level <= depth; ++level) {
+ isl_map *T;
+ isl_map *copy;
+ isl_set *ran;
+
+ if (!can_precede_at_level(plevel, level))
+ continue;
+
+ copy = isl_map_copy(may_rel[k]);
+ T = all_later_sources(acc, copy, j, sink_level, k, level);
+ map = isl_map_union(map, T);
+
+ copy = isl_map_copy(must_rel[k]);
+ T = all_later_sources(acc, copy, j, sink_level, k, level);
+ ran = isl_map_range(isl_map_copy(T));
+ map = isl_map_union(map, T);
+ may_rel[k] = isl_map_union_disjoint(may_rel[k],
+ isl_map_intersect_range(isl_map_copy(must_rel[k]),
+ isl_set_copy(ran)));
+ T = isl_map_from_domain_and_range(
+ isl_set_universe(
+ isl_space_domain(isl_map_get_space(must_rel[k]))),
+ ran);
+ must_rel[k] = isl_map_subtract(must_rel[k], T);
+ }
+ }
+
+ return map;
+}
+
+/* Compute dependences for the case where all accesses are "may"
+ * accesses, which boils down to computing memory based dependences.
+ * The generic algorithm would also work in this case, but it would
+ * be overkill to use it.
+ */
+static __isl_give isl_flow *compute_mem_based_dependences(
+ __isl_keep isl_access_info *acc)
+{
+ int i;
+ isl_set *mustdo;
+ isl_set *maydo;
+ isl_flow *res;
+
+ res = isl_flow_alloc(acc);
+ if (!res)
+ return NULL;
+
+ mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+ maydo = isl_set_copy(mustdo);
+
+ for (i = 0; i < acc->n_may; ++i) {
+ int plevel;
+ int is_before;
+ isl_space *dim;
+ isl_map *before;
+ isl_map *dep;
+
+ plevel = acc->level_before(acc->source[i].data, acc->sink.data);
+ is_before = plevel & 1;
+ plevel >>= 1;
+
+ dim = isl_map_get_space(res->dep[i].map);
+ if (is_before)
+ before = isl_map_lex_le_first(dim, plevel);
+ else
+ before = isl_map_lex_lt_first(dim, plevel);
+ dep = isl_map_apply_range(isl_map_copy(acc->source[i].map),
+ isl_map_reverse(isl_map_copy(acc->sink.map)));
+ dep = isl_map_intersect(dep, before);
+ mustdo = isl_set_subtract(mustdo,
+ isl_map_range(isl_map_copy(dep)));
+ res->dep[i].map = isl_map_union(res->dep[i].map, dep);
+ }
+
+ res->may_no_source = isl_set_subtract(maydo, isl_set_copy(mustdo));
+ res->must_no_source = mustdo;
+
+ return res;
+}
+
+/* Compute dependences for the case where there is at least one
+ * "must" access.
+ *
+ * The core algorithm considers all levels in which a source may precede
+ * the sink, where a level may either be a statement level or a loop level.
+ * The outermost statement level is 1, the first loop level is 2, etc...
+ * The algorithm basically does the following:
+ * for all levels l of the read access from innermost to outermost
+ * for all sources w that may precede the sink access at that level
+ * compute the last iteration of the source that precedes the sink access
+ * at that level
+ * add result to possible last accesses at level l of source w
+ * for all sources w2 that we haven't considered yet at this level that may
+ * also precede the sink access
+ * for all levels l2 of w from l to innermost
+ * for all possible last accesses dep of w at l
+ * compute last iteration of w2 between the source and sink
+ * of dep
+ * add result to possible last accesses at level l of write w2
+ * and replace possible last accesses dep by the remainder
+ *
+ *
+ * The above algorithm is applied to the must access. During the course
+ * of the algorithm, we keep track of sink iterations that still
+ * need to be considered. These iterations are split into those that
+ * haven't been matched to any source access (mustdo) and those that have only
+ * been matched to may accesses (maydo).
+ * At the end of each level, we also consider the may accesses.
+ * In particular, we consider may accesses that precede the remaining
+ * sink iterations, moving elements from mustdo to maydo when appropriate,
+ * and may accesses that occur between a must source and a sink of any
+ * dependences found at the current level, turning must dependences into
+ * may dependences when appropriate.
+ *
+ */
+static __isl_give isl_flow *compute_val_based_dependences(
+ __isl_keep isl_access_info *acc)
+{
+ isl_ctx *ctx;
+ isl_flow *res;
+ isl_set *mustdo = NULL;
+ isl_set *maydo = NULL;
+ int level, j;
+ int depth;
+ isl_map **must_rel = NULL;
+ isl_map **may_rel = NULL;
+
+ if (!acc)
+ return NULL;
+
+ res = isl_flow_alloc(acc);
+ if (!res)
+ goto error;
+ ctx = isl_map_get_ctx(acc->sink.map);
+
+ depth = 2 * isl_map_dim(acc->sink.map, isl_dim_in) + 1;
+ mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+ maydo = isl_set_empty_like(mustdo);
+ if (!mustdo || !maydo)
+ goto error;
+ if (isl_set_plain_is_empty(mustdo))
+ goto done;
+
+ must_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_must);
+ may_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_must);
+ if (!must_rel || !may_rel)
+ goto error;
+
+ for (level = depth; level >= 1; --level) {
+ for (j = acc->n_must-1; j >=0; --j) {
+ must_rel[j] = isl_map_empty_like(res->dep[2 * j].map);
+ may_rel[j] = isl_map_copy(must_rel[j]);
+ }
+
+ for (j = acc->n_must - 1; j >= 0; --j) {
+ struct isl_map *T;
+ struct isl_set *rest;
+ int plevel;
+
+ plevel = acc->level_before(acc->source[j].data,
+ acc->sink.data);
+ if (!can_precede_at_level(plevel, level))
+ continue;
+
+ T = last_source(acc, mustdo, j, level, &rest);
+ must_rel[j] = isl_map_union_disjoint(must_rel[j], T);
+ mustdo = rest;
+
+ intermediate_sources(acc, must_rel, j, level);
+
+ T = last_source(acc, maydo, j, level, &rest);
+ may_rel[j] = isl_map_union_disjoint(may_rel[j], T);
+ maydo = rest;
+
+ intermediate_sources(acc, may_rel, j, level);
+
+ if (isl_set_plain_is_empty(mustdo) &&
+ isl_set_plain_is_empty(maydo))
+ break;
+ }
+ for (j = j - 1; j >= 0; --j) {
+ int plevel;
+
+ plevel = acc->level_before(acc->source[j].data,
+ acc->sink.data);
+ if (!can_precede_at_level(plevel, level))
+ continue;
+
+ intermediate_sources(acc, must_rel, j, level);
+ intermediate_sources(acc, may_rel, j, level);
+ }
+
+ for (j = 0; j < acc->n_may; ++j) {
+ int plevel;
+ isl_map *T;
+ isl_set *ran;
+
+ plevel = acc->level_before(acc->source[acc->n_must + j].data,
+ acc->sink.data);
+ if (!can_precede_at_level(plevel, level))
+ continue;
+
+ T = all_sources(acc, isl_set_copy(maydo), j, level);
+ res->dep[2 * acc->n_must + j].map =
+ isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+ T = all_sources(acc, isl_set_copy(mustdo), j, level);
+ ran = isl_map_range(isl_map_copy(T));
+ res->dep[2 * acc->n_must + j].map =
+ isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+ mustdo = isl_set_subtract(mustdo, isl_set_copy(ran));
+ maydo = isl_set_union_disjoint(maydo, ran);
+
+ T = res->dep[2 * acc->n_must + j].map;
+ T = all_intermediate_sources(acc, T, must_rel, may_rel,
+ j, level);
+ res->dep[2 * acc->n_must + j].map = T;
+ }
+
+ for (j = acc->n_must - 1; j >= 0; --j) {
+ res->dep[2 * j].map =
+ isl_map_union_disjoint(res->dep[2 * j].map,
+ must_rel[j]);
+ res->dep[2 * j + 1].map =
+ isl_map_union_disjoint(res->dep[2 * j + 1].map,
+ may_rel[j]);
+ }
+
+ if (isl_set_plain_is_empty(mustdo) &&
+ isl_set_plain_is_empty(maydo))
+ break;
+ }
+
+ free(must_rel);
+ free(may_rel);
+done:
+ res->must_no_source = mustdo;
+ res->may_no_source = maydo;
+ return res;
+error:
+ isl_flow_free(res);
+ isl_set_free(mustdo);
+ isl_set_free(maydo);
+ free(must_rel);
+ free(may_rel);
+ return NULL;
+}
+
+/* Given a "sink" access, a list of n "source" accesses,
+ * compute for each iteration of the sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a list of n relations between source and sink
+ * iterations and a subset of the domain of the sink access,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * To deal with multi-valued sink access relations, the sink iteration
+ * domain is first extended with dimensions that correspond to the data
+ * space. After the computation is finished, these extra dimensions are
+ * projected out again.
+ */
+__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc)
+{
+ int j;
+ struct isl_flow *res = NULL;
+
+ if (!acc)
+ return NULL;
+
+ acc->domain_map = isl_map_domain_map(isl_map_copy(acc->sink.map));
+ acc->sink.map = isl_map_range_map(acc->sink.map);
+ if (!acc->sink.map)
+ goto error;
+
+ if (acc->n_must == 0)
+ res = compute_mem_based_dependences(acc);
+ else {
+ acc = isl_access_info_sort_sources(acc);
+ res = compute_val_based_dependences(acc);
+ }
+ if (!res)
+ goto error;
+
+ for (j = 0; j < res->n_source; ++j) {
+ res->dep[j].map = isl_map_apply_range(res->dep[j].map,
+ isl_map_copy(acc->domain_map));
+ if (!res->dep[j].map)
+ goto error;
+ }
+ if (!res->must_no_source || !res->may_no_source)
+ goto error;
+
+ isl_access_info_free(acc);
+ return res;
+error:
+ isl_access_info_free(acc);
+ isl_flow_free(res);
+ return NULL;
+}
+
+
+/* Keep track of some information about a schedule for a given
+ * access. In particular, keep track of which dimensions
+ * have a constant value and of the actual constant values.
+ */
+struct isl_sched_info {
+ int *is_cst;
+ isl_vec *cst;
+};
+
+static void sched_info_free(__isl_take struct isl_sched_info *info)
+{
+ if (!info)
+ return;
+ isl_vec_free(info->cst);
+ free(info->is_cst);
+ free(info);
+}
+
+/* Extract information on the constant dimensions of the schedule
+ * for a given access. The "map" is of the form
+ *
+ * [S -> D] -> A
+ *
+ * with S the schedule domain, D the iteration domain and A the data domain.
+ */
+static __isl_give struct isl_sched_info *sched_info_alloc(
+ __isl_keep isl_map *map)
+{
+ isl_ctx *ctx;
+ isl_space *dim;
+ struct isl_sched_info *info;
+ int i, n;
+
+ if (!map)
+ return NULL;
+
+ dim = isl_space_unwrap(isl_space_domain(isl_map_get_space(map)));
+ if (!dim)
+ return NULL;
+ n = isl_space_dim(dim, isl_dim_in);
+ isl_space_free(dim);
+
+ ctx = isl_map_get_ctx(map);
+ info = isl_alloc_type(ctx, struct isl_sched_info);
+ if (!info)
+ return NULL;
+ info->is_cst = isl_alloc_array(ctx, int, n);
+ info->cst = isl_vec_alloc(ctx, n);
+ if (n && (!info->is_cst || !info->cst))
+ goto error;
+
+ for (i = 0; i < n; ++i) {
+ isl_val *v;
+
+ v = isl_map_plain_get_val_if_fixed(map, isl_dim_in, i);
+ if (!v)
+ goto error;
+ info->is_cst[i] = !isl_val_is_nan(v);
+ if (info->is_cst[i])
+ info->cst = isl_vec_set_element_val(info->cst, i, v);
+ else
+ isl_val_free(v);
+ }
+
+ return info;
+error:
+ sched_info_free(info);
+ return NULL;
+}
+
+struct isl_compute_flow_data {
+ isl_union_map *must_source;
+ isl_union_map *may_source;
+ isl_union_map *must_dep;
+ isl_union_map *may_dep;
+ isl_union_map *must_no_source;
+ isl_union_map *may_no_source;
+
+ int count;
+ int must;
+ isl_space *dim;
+ struct isl_sched_info *sink_info;
+ struct isl_sched_info **source_info;
+ isl_access_info *accesses;
+};
+
+static int count_matching_array(__isl_take isl_map *map, void *user)
+{
+ int eq;
+ isl_space *dim;
+ struct isl_compute_flow_data *data;
+
+ data = (struct isl_compute_flow_data *)user;
+
+ dim = isl_space_range(isl_map_get_space(map));
+
+ eq = isl_space_is_equal(dim, data->dim);
+
+ isl_space_free(dim);
+ isl_map_free(map);
+
+ if (eq < 0)
+ return -1;
+ if (eq)
+ data->count++;
+
+ return 0;
+}
+
+static int collect_matching_array(__isl_take isl_map *map, void *user)
+{
+ int eq;
+ isl_space *dim;
+ struct isl_sched_info *info;
+ struct isl_compute_flow_data *data;
+
+ data = (struct isl_compute_flow_data *)user;
+
+ dim = isl_space_range(isl_map_get_space(map));
+
+ eq = isl_space_is_equal(dim, data->dim);
+
+ isl_space_free(dim);
+
+ if (eq < 0)
+ goto error;
+ if (!eq) {
+ isl_map_free(map);
+ return 0;
+ }
+
+ info = sched_info_alloc(map);
+ data->source_info[data->count] = info;
+
+ data->accesses = isl_access_info_add_source(data->accesses,
+ map, data->must, info);
+
+ data->count++;
+
+ return 0;
+error:
+ isl_map_free(map);
+ return -1;
+}
+
+/* Determine the shared nesting level and the "textual order" of
+ * the given accesses.
+ *
+ * We first determine the minimal schedule dimension for both accesses.
+ *
+ * If among those dimensions, we can find one where both have a fixed
+ * value and if moreover those values are different, then the previous
+ * dimension is the last shared nesting level and the textual order
+ * is determined based on the order of the fixed values.
+ * If no such fixed values can be found, then we set the shared
+ * nesting level to the minimal schedule dimension, with no textual ordering.
+ */
+static int before(void *first, void *second)
+{
+ struct isl_sched_info *info1 = first;
+ struct isl_sched_info *info2 = second;
+ int n1, n2;
+ int i;
+
+ n1 = isl_vec_size(info1->cst);
+ n2 = isl_vec_size(info2->cst);
+
+ if (n2 < n1)
+ n1 = n2;
+
+ for (i = 0; i < n1; ++i) {
+ int r;
+ int cmp;
+
+ if (!info1->is_cst[i])
+ continue;
+ if (!info2->is_cst[i])
+ continue;
+ cmp = isl_vec_cmp_element(info1->cst, info2->cst, i);
+ if (cmp == 0)
+ continue;
+
+ r = 2 * i + (cmp < 0);
+
+ return r;
+ }
+
+ return 2 * n1;
+}
+
+/* Given a sink access, look for all the source accesses that access
+ * the same array and perform dataflow analysis on them using
+ * isl_access_info_compute_flow.
+ */
+static int compute_flow(__isl_take isl_map *map, void *user)
+{
+ int i;
+ isl_ctx *ctx;
+ struct isl_compute_flow_data *data;
+ isl_flow *flow;
+
+ data = (struct isl_compute_flow_data *)user;
+
+ ctx = isl_map_get_ctx(map);
+
+ data->accesses = NULL;
+ data->sink_info = NULL;
+ data->source_info = NULL;
+ data->count = 0;
+ data->dim = isl_space_range(isl_map_get_space(map));
+
+ if (isl_union_map_foreach_map(data->must_source,
+ &count_matching_array, data) < 0)
+ goto error;
+ if (isl_union_map_foreach_map(data->may_source,
+ &count_matching_array, data) < 0)
+ goto error;
+
+ data->sink_info = sched_info_alloc(map);
+ data->source_info = isl_calloc_array(ctx, struct isl_sched_info *,
+ data->count);
+
+ data->accesses = isl_access_info_alloc(isl_map_copy(map),
+ data->sink_info, &before, data->count);
+ if (!data->sink_info || (data->count && !data->source_info) ||
+ !data->accesses)
+ goto error;
+ data->count = 0;
+ data->must = 1;
+ if (isl_union_map_foreach_map(data->must_source,
+ &collect_matching_array, data) < 0)
+ goto error;
+ data->must = 0;
+ if (isl_union_map_foreach_map(data->may_source,
+ &collect_matching_array, data) < 0)
+ goto error;
+
+ flow = isl_access_info_compute_flow(data->accesses);
+ data->accesses = NULL;
+
+ if (!flow)
+ goto error;
+
+ data->must_no_source = isl_union_map_union(data->must_no_source,
+ isl_union_map_from_map(isl_flow_get_no_source(flow, 1)));
+ data->may_no_source = isl_union_map_union(data->may_no_source,
+ isl_union_map_from_map(isl_flow_get_no_source(flow, 0)));
+
+ for (i = 0; i < flow->n_source; ++i) {
+ isl_union_map *dep;
+ dep = isl_union_map_from_map(isl_map_copy(flow->dep[i].map));
+ if (flow->dep[i].must)
+ data->must_dep = isl_union_map_union(data->must_dep, dep);
+ else
+ data->may_dep = isl_union_map_union(data->may_dep, dep);
+ }
+
+ isl_flow_free(flow);
+
+ sched_info_free(data->sink_info);
+ if (data->source_info) {
+ for (i = 0; i < data->count; ++i)
+ sched_info_free(data->source_info[i]);
+ free(data->source_info);
+ }
+ isl_space_free(data->dim);
+ isl_map_free(map);
+
+ return 0;
+error:
+ isl_access_info_free(data->accesses);
+ sched_info_free(data->sink_info);
+ if (data->source_info) {
+ for (i = 0; i < data->count; ++i)
+ sched_info_free(data->source_info[i]);
+ free(data->source_info);
+ }
+ isl_space_free(data->dim);
+ isl_map_free(map);
+
+ return -1;
+}
+
+/* Given a collection of "sink" and "source" accesses,
+ * compute for each iteration of a sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a relations between source and sink
+ * iterations and a subset of the domain of the sink accesses,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * We first prepend the schedule dimensions to the domain
+ * of the accesses so that we can easily compare their relative order.
+ * Then we consider each sink access individually in compute_flow.
+ */
+int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
+ __isl_take isl_union_map *must_source,
+ __isl_take isl_union_map *may_source,
+ __isl_take isl_union_map *schedule,
+ __isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep,
+ __isl_give isl_union_map **must_no_source,
+ __isl_give isl_union_map **may_no_source)
+{
+ isl_space *dim;
+ isl_union_map *range_map = NULL;
+ struct isl_compute_flow_data data;
+
+ sink = isl_union_map_align_params(sink,
+ isl_union_map_get_space(must_source));
+ sink = isl_union_map_align_params(sink,
+ isl_union_map_get_space(may_source));
+ sink = isl_union_map_align_params(sink,
+ isl_union_map_get_space(schedule));
+ dim = isl_union_map_get_space(sink);
+ must_source = isl_union_map_align_params(must_source, isl_space_copy(dim));
+ may_source = isl_union_map_align_params(may_source, isl_space_copy(dim));
+ schedule = isl_union_map_align_params(schedule, isl_space_copy(dim));
+
+ schedule = isl_union_map_reverse(schedule);
+ range_map = isl_union_map_range_map(schedule);
+ schedule = isl_union_map_reverse(isl_union_map_copy(range_map));
+ sink = isl_union_map_apply_domain(sink, isl_union_map_copy(schedule));
+ must_source = isl_union_map_apply_domain(must_source,
+ isl_union_map_copy(schedule));
+ may_source = isl_union_map_apply_domain(may_source, schedule);
+
+ data.must_source = must_source;
+ data.may_source = may_source;
+ data.must_dep = must_dep ?
+ isl_union_map_empty(isl_space_copy(dim)) : NULL;
+ data.may_dep = may_dep ? isl_union_map_empty(isl_space_copy(dim)) : NULL;
+ data.must_no_source = must_no_source ?
+ isl_union_map_empty(isl_space_copy(dim)) : NULL;
+ data.may_no_source = may_no_source ?
+ isl_union_map_empty(isl_space_copy(dim)) : NULL;
+
+ isl_space_free(dim);
+
+ if (isl_union_map_foreach_map(sink, &compute_flow, &data) < 0)
+ goto error;
+
+ isl_union_map_free(sink);
+ isl_union_map_free(must_source);
+ isl_union_map_free(may_source);
+
+ if (must_dep) {
+ data.must_dep = isl_union_map_apply_domain(data.must_dep,
+ isl_union_map_copy(range_map));
+ data.must_dep = isl_union_map_apply_range(data.must_dep,
+ isl_union_map_copy(range_map));
+ *must_dep = data.must_dep;
+ }
+ if (may_dep) {
+ data.may_dep = isl_union_map_apply_domain(data.may_dep,
+ isl_union_map_copy(range_map));
+ data.may_dep = isl_union_map_apply_range(data.may_dep,
+ isl_union_map_copy(range_map));
+ *may_dep = data.may_dep;
+ }
+ if (must_no_source) {
+ data.must_no_source = isl_union_map_apply_domain(
+ data.must_no_source, isl_union_map_copy(range_map));
+ *must_no_source = data.must_no_source;
+ }
+ if (may_no_source) {
+ data.may_no_source = isl_union_map_apply_domain(
+ data.may_no_source, isl_union_map_copy(range_map));
+ *may_no_source = data.may_no_source;
+ }
+
+ isl_union_map_free(range_map);
+
+ return 0;
+error:
+ isl_union_map_free(range_map);
+ isl_union_map_free(sink);
+ isl_union_map_free(must_source);
+ isl_union_map_free(may_source);
+ isl_union_map_free(data.must_dep);
+ isl_union_map_free(data.may_dep);
+ isl_union_map_free(data.must_no_source);
+ isl_union_map_free(data.may_no_source);
+
+ if (must_dep)
+ *must_dep = NULL;
+ if (may_dep)
+ *may_dep = NULL;
+ if (must_no_source)
+ *must_no_source = NULL;
+ if (may_no_source)
+ *may_no_source = NULL;
+ return -1;
+}
Added: polly/trunk/lib/External/isl/isl_fold.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_fold.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_fold.c (added)
+++ polly/trunk/lib/External/isl/isl_fold.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,1711 @@
+/*
+ * Copyright 2010 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#define ISL_DIM_H
+#include <isl_map_private.h>
+#include <isl_union_map_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_point_private.h>
+#include <isl_space_private.h>
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_config.h>
+#include <isl/deprecated/polynomial_int.h>
+
+enum isl_fold isl_fold_type_negate(enum isl_fold type)
+{
+ switch (type) {
+ case isl_fold_min:
+ return isl_fold_max;
+ case isl_fold_max:
+ return isl_fold_min;
+ case isl_fold_list:
+ return isl_fold_list;
+ }
+
+ isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
+}
+
+static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
+ enum isl_fold type, __isl_take isl_space *dim, int n)
+{
+ isl_qpolynomial_fold *fold;
+
+ if (!dim)
+ goto error;
+
+ isl_assert(dim->ctx, n >= 0, goto error);
+ fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold,
+ sizeof(struct isl_qpolynomial_fold) +
+ (n - 1) * sizeof(struct isl_qpolynomial *));
+ if (!fold)
+ goto error;
+
+ fold->ref = 1;
+ fold->size = n;
+ fold->n = 0;
+ fold->type = type;
+ fold->dim = dim;
+
+ return fold;
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
+{
+ return fold ? fold->dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
+ __isl_keep isl_qpolynomial_fold *fold)
+{
+ return fold ? isl_space_copy(fold->dim) : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_space(
+ __isl_keep isl_qpolynomial_fold *fold)
+{
+ isl_space *space;
+ if (!fold)
+ return NULL;
+ space = isl_space_copy(fold->dim);
+ space = isl_space_from_domain(space);
+ space = isl_space_add_dims(space, isl_dim_out, 1);
+ return space;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+ int i;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold || !dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
+ isl_space_copy(dim));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_space_free(fold->dim);
+ fold->dim = dim;
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_space_free(dim);
+ return NULL;
+}
+
+/* Reset the space of "fold". This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain. It therefore passes along both.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
+ __isl_take isl_space *domain)
+{
+ isl_space_free(space);
+ return isl_qpolynomial_fold_reset_domain_space(fold, domain);
+}
+
+int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!fold)
+ return -1;
+ if (fold->n == 0 || n == 0)
+ return 0;
+
+ for (i = 0; i < fold->n; ++i) {
+ int involves = isl_qpolynomial_involves_dims(fold->qp[i],
+ type, first, n);
+ if (involves < 0 || involves)
+ return involves;
+ }
+ return 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
+ __isl_take isl_qpolynomial_fold *fold,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ int i;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+ fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
+ type, pos, s);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
+ __isl_take isl_qpolynomial_fold *fold,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+ enum isl_dim_type set_type;
+
+ if (!fold)
+ return NULL;
+ if (n == 0)
+ return fold;
+
+ set_type = type == isl_dim_in ? isl_dim_set : type;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+ fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
+ type, first, n);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
+ __isl_take isl_qpolynomial_fold *fold,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!fold)
+ return NULL;
+ if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
+ return fold;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+ fold->dim = isl_space_insert_dims(fold->dim, type, first, n);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
+ type, first, n);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
+{
+ struct isl_upoly_cst *cst;
+
+ cst = isl_upoly_as_cst(qp->upoly);
+ if (!cst)
+ return 0;
+
+ return isl_int_sgn(cst->n) < 0 ? -1 : 1;
+}
+
+static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
+ __isl_keep isl_qpolynomial *qp)
+{
+ enum isl_lp_result res;
+ isl_vec *aff;
+ isl_int opt;
+ int sgn = 0;
+
+ aff = isl_qpolynomial_extract_affine(qp);
+ if (!aff)
+ return 0;
+
+ isl_int_init(opt);
+
+ res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
+ &opt, NULL, NULL);
+ if (res == isl_lp_error)
+ goto done;
+ if (res == isl_lp_empty ||
+ (res == isl_lp_ok && !isl_int_is_neg(opt))) {
+ sgn = 1;
+ goto done;
+ }
+
+ res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
+ &opt, NULL, NULL);
+ if (res == isl_lp_ok && !isl_int_is_pos(opt))
+ sgn = -1;
+
+done:
+ isl_int_clear(opt);
+ isl_vec_free(aff);
+ return sgn;
+}
+
+/* Determine, if possible, the sign of the quasipolynomial "qp" on
+ * the domain "set".
+ *
+ * If qp is a constant, then the problem is trivial.
+ * If qp is linear, then we check if the minimum of the corresponding
+ * affine constraint is non-negative or if the maximum is non-positive.
+ *
+ * Otherwise, we check if the outermost variable "v" has a lower bound "l"
+ * in "set". If so, we write qp(v,v') as
+ *
+ * q(v,v') * (v - l) + r(v')
+ *
+ * if q(v,v') and r(v') have the same known sign, then the original
+ * quasipolynomial has the same sign as well.
+ *
+ * Return
+ * -1 if qp <= 0
+ * 1 if qp >= 0
+ * 0 if unknown
+ */
+static int isl_qpolynomial_sign(__isl_keep isl_set *set,
+ __isl_keep isl_qpolynomial *qp)
+{
+ int d;
+ int i;
+ int is;
+ struct isl_upoly_rec *rec;
+ isl_vec *v;
+ isl_int l;
+ enum isl_lp_result res;
+ int sgn = 0;
+
+ is = isl_qpolynomial_is_cst(qp, NULL, NULL);
+ if (is < 0)
+ return 0;
+ if (is)
+ return isl_qpolynomial_cst_sign(qp);
+
+ is = isl_qpolynomial_is_affine(qp);
+ if (is < 0)
+ return 0;
+ if (is)
+ return isl_qpolynomial_aff_sign(set, qp);
+
+ if (qp->div->n_row > 0)
+ return 0;
+
+ rec = isl_upoly_as_rec(qp->upoly);
+ if (!rec)
+ return 0;
+
+ d = isl_space_dim(qp->dim, isl_dim_all);
+ v = isl_vec_alloc(set->ctx, 2 + d);
+ if (!v)
+ return 0;
+
+ isl_seq_clr(v->el + 1, 1 + d);
+ isl_int_set_si(v->el[0], 1);
+ isl_int_set_si(v->el[2 + qp->upoly->var], 1);
+
+ isl_int_init(l);
+
+ res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
+ if (res == isl_lp_ok) {
+ isl_qpolynomial *min;
+ isl_qpolynomial *base;
+ isl_qpolynomial *r, *q;
+ isl_qpolynomial *t;
+
+ min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
+ base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
+ qp->upoly->var, 1);
+
+ r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+ isl_upoly_copy(rec->p[rec->n - 1]));
+ q = isl_qpolynomial_copy(r);
+
+ for (i = rec->n - 2; i >= 0; --i) {
+ r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
+ t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+ isl_upoly_copy(rec->p[i]));
+ r = isl_qpolynomial_add(r, t);
+ if (i == 0)
+ break;
+ q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
+ q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
+ }
+
+ if (isl_qpolynomial_is_zero(q))
+ sgn = isl_qpolynomial_sign(set, r);
+ else if (isl_qpolynomial_is_zero(r))
+ sgn = isl_qpolynomial_sign(set, q);
+ else {
+ int sgn_q, sgn_r;
+ sgn_r = isl_qpolynomial_sign(set, r);
+ sgn_q = isl_qpolynomial_sign(set, q);
+ if (sgn_r == sgn_q)
+ sgn = sgn_r;
+ }
+
+ isl_qpolynomial_free(min);
+ isl_qpolynomial_free(base);
+ isl_qpolynomial_free(q);
+ isl_qpolynomial_free(r);
+ }
+
+ isl_int_clear(l);
+
+ isl_vec_free(v);
+
+ return sgn;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
+ __isl_keep isl_set *set,
+ __isl_take isl_qpolynomial_fold *fold1,
+ __isl_take isl_qpolynomial_fold *fold2)
+{
+ int i, j;
+ int n1;
+ struct isl_qpolynomial_fold *res = NULL;
+ int better;
+
+ if (!fold1 || !fold2)
+ goto error;
+
+ isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+ isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+ goto error);
+
+ better = fold1->type == isl_fold_max ? -1 : 1;
+
+ if (isl_qpolynomial_fold_is_empty(fold1)) {
+ isl_qpolynomial_fold_free(fold1);
+ return fold2;
+ }
+
+ if (isl_qpolynomial_fold_is_empty(fold2)) {
+ isl_qpolynomial_fold_free(fold2);
+ return fold1;
+ }
+
+ res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+ fold1->n + fold2->n);
+ if (!res)
+ goto error;
+
+ for (i = 0; i < fold1->n; ++i) {
+ res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+ if (!res->qp[res->n])
+ goto error;
+ res->n++;
+ }
+ n1 = res->n;
+
+ for (i = 0; i < fold2->n; ++i) {
+ for (j = n1 - 1; j >= 0; --j) {
+ isl_qpolynomial *d;
+ int sgn;
+ d = isl_qpolynomial_sub(
+ isl_qpolynomial_copy(res->qp[j]),
+ isl_qpolynomial_copy(fold2->qp[i]));
+ sgn = isl_qpolynomial_sign(set, d);
+ isl_qpolynomial_free(d);
+ if (sgn == 0)
+ continue;
+ if (sgn != better)
+ break;
+ isl_qpolynomial_free(res->qp[j]);
+ if (j != n1 - 1)
+ res->qp[j] = res->qp[n1 - 1];
+ n1--;
+ if (n1 != res->n - 1)
+ res->qp[n1] = res->qp[res->n - 1];
+ res->n--;
+ }
+ if (j >= 0)
+ continue;
+ res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+ if (!res->qp[res->n])
+ goto error;
+ res->n++;
+ }
+
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+
+ return res;
+error:
+ isl_qpolynomial_fold_free(res);
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
+{
+ int i;
+
+ if (!fold || !qp)
+ goto error;
+
+ if (isl_qpolynomial_is_zero(qp)) {
+ isl_qpolynomial_free(qp);
+ return fold;
+ }
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
+ isl_qpolynomial_copy(qp));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_qpolynomial_free(qp);
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_qpolynomial_free(qp);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
+ __isl_keep isl_set *dom,
+ __isl_take isl_qpolynomial_fold *fold1,
+ __isl_take isl_qpolynomial_fold *fold2)
+{
+ int i;
+ isl_qpolynomial_fold *res = NULL;
+
+ if (!fold1 || !fold2)
+ goto error;
+
+ if (isl_qpolynomial_fold_is_empty(fold1)) {
+ isl_qpolynomial_fold_free(fold1);
+ return fold2;
+ }
+
+ if (isl_qpolynomial_fold_is_empty(fold2)) {
+ isl_qpolynomial_fold_free(fold2);
+ return fold1;
+ }
+
+ if (fold1->n == 1 && fold2->n != 1)
+ return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
+
+ if (fold2->n == 1) {
+ res = isl_qpolynomial_fold_add_qpolynomial(fold1,
+ isl_qpolynomial_copy(fold2->qp[0]));
+ isl_qpolynomial_fold_free(fold2);
+ return res;
+ }
+
+ res = isl_qpolynomial_fold_add_qpolynomial(
+ isl_qpolynomial_fold_copy(fold1),
+ isl_qpolynomial_copy(fold2->qp[0]));
+
+ for (i = 1; i < fold2->n; ++i) {
+ isl_qpolynomial_fold *res_i;
+ res_i = isl_qpolynomial_fold_add_qpolynomial(
+ isl_qpolynomial_fold_copy(fold1),
+ isl_qpolynomial_copy(fold2->qp[i]));
+ res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
+ }
+
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+ return res;
+error:
+ isl_qpolynomial_fold_free(res);
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
+{
+ int i;
+
+ if (!fold || !eq)
+ goto error;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
+ isl_basic_set_copy(eq));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_basic_set_free(eq);
+ return fold;
+error:
+ isl_basic_set_free(eq);
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+ int i;
+
+ if (!fold || !context)
+ goto error;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
+ isl_set_copy(context));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_set_free(context);
+ return fold;
+error:
+ isl_set_free(context);
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+ isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+ isl_set *dom_context = isl_set_universe(space);
+ dom_context = isl_set_intersect_params(dom_context, context);
+ return isl_qpolynomial_fold_gist(fold, dom_context);
+}
+
+#define HAS_TYPE
+
+#undef PW
+#define PW isl_pw_qpolynomial_fold
+#undef EL
+#define EL isl_qpolynomial_fold
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_empty
+#undef ZERO
+#define ZERO zero
+#undef IS_ZERO
+#define IS_ZERO is_zero
+#undef FIELD
+#define FIELD fold
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 1
+
+#define NO_NEG
+#define NO_PULLBACK
+
+#include <isl_pw_templ.c>
+
+#undef UNION
+#define UNION isl_union_pw_qpolynomial_fold
+#undef PART
+#define PART isl_pw_qpolynomial_fold
+#undef PARTS
+#define PARTS pw_qpolynomial_fold
+#define ALIGN_DOMAIN
+
+#define NO_SUB
+
+#include <isl_union_templ.c>
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
+ __isl_take isl_space *dim)
+{
+ return qpolynomial_fold_alloc(type, dim, 0);
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
+ enum isl_fold type, __isl_take isl_qpolynomial *qp)
+{
+ isl_qpolynomial_fold *fold;
+
+ if (!qp)
+ return NULL;
+
+ fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1);
+ if (!fold)
+ goto error;
+
+ fold->qp[0] = qp;
+ fold->n++;
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_qpolynomial_free(qp);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
+ __isl_keep isl_qpolynomial_fold *fold)
+{
+ if (!fold)
+ return NULL;
+
+ fold->ref++;
+ return fold;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
+ __isl_keep isl_qpolynomial_fold *fold)
+{
+ int i;
+ isl_qpolynomial_fold *dup;
+
+ if (!fold)
+ return NULL;
+ dup = qpolynomial_fold_alloc(fold->type,
+ isl_space_copy(fold->dim), fold->n);
+ if (!dup)
+ return NULL;
+
+ dup->n = fold->n;
+ for (i = 0; i < fold->n; ++i) {
+ dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
+ if (!dup->qp[i])
+ goto error;
+ }
+
+ return dup;
+error:
+ isl_qpolynomial_fold_free(dup);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
+ __isl_take isl_qpolynomial_fold *fold)
+{
+ if (!fold)
+ return NULL;
+
+ if (fold->ref == 1)
+ return fold;
+ fold->ref--;
+ return isl_qpolynomial_fold_dup(fold);
+}
+
+void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold)
+{
+ int i;
+
+ if (!fold)
+ return;
+ if (--fold->ref > 0)
+ return;
+
+ for (i = 0; i < fold->n; ++i)
+ isl_qpolynomial_free(fold->qp[i]);
+ isl_space_free(fold->dim);
+ free(fold);
+}
+
+int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
+{
+ if (!fold)
+ return -1;
+
+ return fold->n == 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
+ __isl_take isl_qpolynomial_fold *fold1,
+ __isl_take isl_qpolynomial_fold *fold2)
+{
+ int i;
+ struct isl_qpolynomial_fold *res = NULL;
+
+ if (!fold1 || !fold2)
+ goto error;
+
+ isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+ isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+ goto error);
+
+ if (isl_qpolynomial_fold_is_empty(fold1)) {
+ isl_qpolynomial_fold_free(fold1);
+ return fold2;
+ }
+
+ if (isl_qpolynomial_fold_is_empty(fold2)) {
+ isl_qpolynomial_fold_free(fold2);
+ return fold1;
+ }
+
+ res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+ fold1->n + fold2->n);
+ if (!res)
+ goto error;
+
+ for (i = 0; i < fold1->n; ++i) {
+ res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+ if (!res->qp[res->n])
+ goto error;
+ res->n++;
+ }
+
+ for (i = 0; i < fold2->n; ++i) {
+ res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+ if (!res->qp[res->n])
+ goto error;
+ res->n++;
+ }
+
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+
+ return res;
+error:
+ isl_qpolynomial_fold_free(res);
+ isl_qpolynomial_fold_free(fold1);
+ isl_qpolynomial_fold_free(fold2);
+ return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
+ __isl_take isl_pw_qpolynomial_fold *pw1,
+ __isl_take isl_pw_qpolynomial_fold *pw2)
+{
+ int i, j, n;
+ struct isl_pw_qpolynomial_fold *res;
+ isl_set *set;
+
+ if (!pw1 || !pw2)
+ goto error;
+
+ isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+ if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
+ isl_pw_qpolynomial_fold_free(pw1);
+ return pw2;
+ }
+
+ if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
+ isl_pw_qpolynomial_fold_free(pw2);
+ return pw1;
+ }
+
+ if (pw1->type != pw2->type)
+ isl_die(pw1->dim->ctx, isl_error_invalid,
+ "fold types don't match", goto error);
+
+ n = (pw1->n + 1) * (pw2->n + 1);
+ res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
+ pw1->type, n);
+
+ for (i = 0; i < pw1->n; ++i) {
+ set = isl_set_copy(pw1->p[i].set);
+ for (j = 0; j < pw2->n; ++j) {
+ struct isl_set *common;
+ isl_qpolynomial_fold *sum;
+ set = isl_set_subtract(set,
+ isl_set_copy(pw2->p[j].set));
+ common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
+ isl_set_copy(pw2->p[j].set));
+ if (isl_set_plain_is_empty(common)) {
+ isl_set_free(common);
+ continue;
+ }
+
+ sum = isl_qpolynomial_fold_fold_on_domain(common,
+ isl_qpolynomial_fold_copy(pw1->p[i].fold),
+ isl_qpolynomial_fold_copy(pw2->p[j].fold));
+
+ res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
+ }
+ res = isl_pw_qpolynomial_fold_add_piece(res, set,
+ isl_qpolynomial_fold_copy(pw1->p[i].fold));
+ }
+
+ for (j = 0; j < pw2->n; ++j) {
+ set = isl_set_copy(pw2->p[j].set);
+ for (i = 0; i < pw1->n; ++i)
+ set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
+ res = isl_pw_qpolynomial_fold_add_piece(res, set,
+ isl_qpolynomial_fold_copy(pw2->p[j].fold));
+ }
+
+ isl_pw_qpolynomial_fold_free(pw1);
+ isl_pw_qpolynomial_fold_free(pw2);
+
+ return res;
+error:
+ isl_pw_qpolynomial_fold_free(pw1);
+ isl_pw_qpolynomial_fold_free(pw2);
+ return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+ __isl_take isl_union_pw_qpolynomial_fold *u,
+ __isl_take isl_pw_qpolynomial_fold *part)
+{
+ uint32_t hash;
+ struct isl_hash_table_entry *entry;
+
+ u = isl_union_pw_qpolynomial_fold_cow(u);
+
+ if (!part || !u)
+ goto error;
+
+ isl_assert(u->space->ctx,
+ isl_space_match(part->dim, isl_dim_param, u->space, isl_dim_param),
+ goto error);
+
+ hash = isl_space_get_hash(part->dim);
+ entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
+ &has_same_domain_space, part->dim, 1);
+ if (!entry)
+ goto error;
+
+ if (!entry->data)
+ entry->data = part;
+ else {
+ entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
+ isl_pw_qpolynomial_fold_copy(part));
+ if (!entry->data)
+ goto error;
+ isl_pw_qpolynomial_fold_free(part);
+ }
+
+ return u;
+error:
+ isl_pw_qpolynomial_fold_free(part);
+ isl_union_pw_qpolynomial_fold_free(u);
+ return NULL;
+}
+
+static int fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
+{
+ isl_union_pw_qpolynomial_fold **u;
+ u = (isl_union_pw_qpolynomial_fold **)user;
+
+ *u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
+
+ return 0;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
+ __isl_take isl_union_pw_qpolynomial_fold *u1,
+ __isl_take isl_union_pw_qpolynomial_fold *u2)
+{
+ u1 = isl_union_pw_qpolynomial_fold_cow(u1);
+
+ if (!u1 || !u2)
+ goto error;
+
+ if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
+ &fold_part, &u1) < 0)
+ goto error;
+
+ isl_union_pw_qpolynomial_fold_free(u2);
+
+ return u1;
+error:
+ isl_union_pw_qpolynomial_fold_free(u1);
+ isl_union_pw_qpolynomial_fold_free(u2);
+ return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
+ enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
+{
+ int i;
+ isl_pw_qpolynomial_fold *pwf;
+
+ if (!pwqp)
+ return NULL;
+
+ pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
+ type, pwqp->n);
+
+ for (i = 0; i < pwqp->n; ++i)
+ pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
+ isl_set_copy(pwqp->p[i].set),
+ isl_qpolynomial_fold_alloc(type,
+ isl_qpolynomial_copy(pwqp->p[i].qp)));
+
+ isl_pw_qpolynomial_free(pwqp);
+
+ return pwf;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
+ __isl_take isl_pw_qpolynomial_fold *pwf1,
+ __isl_take isl_pw_qpolynomial_fold *pwf2)
+{
+ return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
+}
+
+int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
+ __isl_keep isl_qpolynomial_fold *fold2)
+{
+ int i;
+
+ if (!fold1 || !fold2)
+ return -1;
+
+ if (fold1->n != fold2->n)
+ return 0;
+
+ /* We probably want to sort the qps first... */
+ for (i = 0; i < fold1->n; ++i) {
+ int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
+ if (eq < 0 || !eq)
+ return eq;
+ }
+
+ return 1;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_eval(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
+{
+ isl_ctx *ctx;
+ isl_val *v;
+
+ if (!fold || !pnt)
+ goto error;
+ ctx = isl_point_get_ctx(pnt);
+ isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
+ isl_assert(pnt->dim->ctx,
+ fold->type == isl_fold_max || fold->type == isl_fold_min,
+ goto error);
+
+ if (fold->n == 0)
+ v = isl_val_zero(ctx);
+ else {
+ int i;
+ v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
+ isl_point_copy(pnt));
+ for (i = 1; i < fold->n; ++i) {
+ isl_val *v_i;
+ v_i = isl_qpolynomial_eval(
+ isl_qpolynomial_copy(fold->qp[i]),
+ isl_point_copy(pnt));
+ if (fold->type == isl_fold_max)
+ v = isl_val_max(v, v_i);
+ else
+ v = isl_val_min(v, v_i);
+ }
+ }
+ isl_qpolynomial_fold_free(fold);
+ isl_point_free(pnt);
+
+ return v;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_point_free(pnt);
+ return NULL;
+}
+
+size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+ int i;
+ size_t n = 0;
+
+ for (i = 0; i < pwf->n; ++i)
+ n += pwf->p[i].fold->n;
+
+ return n;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
+{
+ int i;
+ isl_val *opt;
+
+ if (!set || !fold)
+ goto error;
+
+ if (fold->n == 0) {
+ opt = isl_val_zero(isl_set_get_ctx(set));
+ isl_set_free(set);
+ isl_qpolynomial_fold_free(fold);
+ return opt;
+ }
+
+ opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
+ isl_set_copy(set), max);
+ for (i = 1; i < fold->n; ++i) {
+ isl_val *opt_i;
+ opt_i = isl_qpolynomial_opt_on_domain(
+ isl_qpolynomial_copy(fold->qp[i]),
+ isl_set_copy(set), max);
+ if (max)
+ opt = isl_val_max(opt, opt_i);
+ else
+ opt = isl_val_min(opt, opt_i);
+ }
+
+ isl_set_free(set);
+ isl_qpolynomial_fold_free(fold);
+
+ return opt;
+error:
+ isl_set_free(set);
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+/* Check whether for each quasi-polynomial in "fold2" there is
+ * a quasi-polynomial in "fold1" that dominates it on "set".
+ */
+static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
+ __isl_keep isl_qpolynomial_fold *fold1,
+ __isl_keep isl_qpolynomial_fold *fold2)
+{
+ int i, j;
+ int covers;
+
+ if (!set || !fold1 || !fold2)
+ return -1;
+
+ covers = fold1->type == isl_fold_max ? 1 : -1;
+
+ for (i = 0; i < fold2->n; ++i) {
+ for (j = 0; j < fold1->n; ++j) {
+ isl_qpolynomial *d;
+ int sgn;
+
+ d = isl_qpolynomial_sub(
+ isl_qpolynomial_copy(fold1->qp[j]),
+ isl_qpolynomial_copy(fold2->qp[i]));
+ sgn = isl_qpolynomial_sign(set, d);
+ isl_qpolynomial_free(d);
+ if (sgn == covers)
+ break;
+ }
+ if (j >= fold1->n)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
+ * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
+ * that of pwf2.
+ */
+int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
+ __isl_keep isl_pw_qpolynomial_fold *pwf2)
+{
+ int i, j;
+ isl_set *dom1, *dom2;
+ int is_subset;
+
+ if (!pwf1 || !pwf2)
+ return -1;
+
+ if (pwf2->n == 0)
+ return 1;
+ if (pwf1->n == 0)
+ return 0;
+
+ dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
+ dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
+ is_subset = isl_set_is_subset(dom2, dom1);
+ isl_set_free(dom1);
+ isl_set_free(dom2);
+
+ if (is_subset < 0 || !is_subset)
+ return is_subset;
+
+ for (i = 0; i < pwf2->n; ++i) {
+ for (j = 0; j < pwf1->n; ++j) {
+ int is_empty;
+ isl_set *common;
+ int covers;
+
+ common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
+ isl_set_copy(pwf2->p[i].set));
+ is_empty = isl_set_is_empty(common);
+ if (is_empty < 0 || is_empty) {
+ isl_set_free(common);
+ if (is_empty < 0)
+ return -1;
+ continue;
+ }
+ covers = qpolynomial_fold_covers_on_domain(common,
+ pwf1->p[j].fold, pwf2->p[i].fold);
+ isl_set_free(common);
+ if (covers < 0 || !covers)
+ return covers;
+ }
+ }
+
+ return 1;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
+{
+ int i;
+ isl_ctx *ctx;
+
+ if (!fold || !morph)
+ goto error;
+
+ ctx = fold->dim->ctx;
+ isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error);
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ goto error;
+
+ isl_space_free(fold->dim);
+ fold->dim = isl_space_copy(morph->ran->dim);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
+ isl_morph_copy(morph));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_morph_free(morph);
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_morph_free(morph);
+ return NULL;
+}
+
+enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
+{
+ if (!fold)
+ return isl_fold_list;
+ return fold->type;
+}
+
+enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
+ __isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+ if (!upwf)
+ return isl_fold_list;
+ return upwf->type;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+ int i;
+
+ if (!fold || !dim)
+ goto error;
+
+ if (isl_space_is_equal(fold->dim, dim)) {
+ isl_space_free(dim);
+ return fold;
+ }
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ goto error;
+
+ isl_space_free(fold->dim);
+ fold->dim = isl_space_copy(dim);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
+ isl_space_copy(dim));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_space_free(dim);
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_space_free(dim);
+ return NULL;
+}
+
+int isl_qpolynomial_fold_foreach_qpolynomial(
+ __isl_keep isl_qpolynomial_fold *fold,
+ int (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
+{
+ int i;
+
+ if (!fold)
+ return -1;
+
+ for (i = 0; i < fold->n; ++i)
+ if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
+ return -1;
+
+ return 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
+ __isl_take isl_qpolynomial_fold *fold,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ int i;
+
+ if (n == 0)
+ return fold;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+
+ fold->dim = isl_space_move_dims(fold->dim, dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!fold->dim)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
+ dst_type, dst_pos, src_type, src_pos, n);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+/* For each 0 <= i < "n", replace variable "first" + i of type "type"
+ * in fold->qp[k] by subs[i].
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
+ __isl_take isl_qpolynomial_fold *fold,
+ enum isl_dim_type type, unsigned first, unsigned n,
+ __isl_keep isl_qpolynomial **subs)
+{
+ int i;
+
+ if (n == 0)
+ return fold;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
+ type, first, n, subs);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+static int add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+ isl_ctx *ctx;
+ isl_pw_qpolynomial_fold *pwf;
+ isl_union_pw_qpolynomial_fold **upwf;
+ uint32_t hash;
+ struct isl_hash_table_entry *entry;
+
+ upwf = (isl_union_pw_qpolynomial_fold **)user;
+
+ ctx = pwqp->dim->ctx;
+ hash = isl_space_get_hash(pwqp->dim);
+ entry = isl_hash_table_find(ctx, &(*upwf)->table, hash,
+ &has_same_domain_space, pwqp->dim, 1);
+ if (!entry)
+ goto error;
+
+ pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
+ if (!entry->data)
+ entry->data = pwf;
+ else {
+ entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
+ if (!entry->data)
+ return -1;
+ if (isl_pw_qpolynomial_fold_is_zero(entry->data)) {
+ isl_pw_qpolynomial_fold_free(entry->data);
+ isl_hash_table_remove(ctx, &(*upwf)->table, entry);
+ }
+ }
+
+ return 0;
+error:
+ isl_pw_qpolynomial_free(pwqp);
+ return -1;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
+ __isl_take isl_union_pw_qpolynomial_fold *upwf,
+ __isl_take isl_union_pw_qpolynomial *upwqp)
+{
+ upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+ isl_union_pw_qpolynomial_get_space(upwqp));
+ upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
+ isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+ upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
+ if (!upwf || !upwqp)
+ goto error;
+
+ if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
+ &upwf) < 0)
+ goto error;
+
+ isl_union_pw_qpolynomial_free(upwqp);
+
+ return upwf;
+error:
+ isl_union_pw_qpolynomial_fold_free(upwf);
+ isl_union_pw_qpolynomial_free(upwqp);
+ return NULL;
+}
+
+static int join_compatible(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
+{
+ int m;
+ m = isl_space_match(dim1, isl_dim_param, dim2, isl_dim_param);
+ if (m < 0 || !m)
+ return m;
+ return isl_space_tuple_is_equal(dim1, isl_dim_out, dim2, isl_dim_in);
+}
+
+/* Compute the intersection of the range of the map and the domain
+ * of the piecewise quasipolynomial reduction and then compute a bound
+ * on the associated quasipolynomial reduction over all elements
+ * in this intersection.
+ *
+ * We first introduce some unconstrained dimensions in the
+ * piecewise quasipolynomial, intersect the resulting domain
+ * with the wrapped map and the compute the sum.
+ */
+__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
+ __isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
+ int *tight)
+{
+ isl_ctx *ctx;
+ isl_set *dom;
+ isl_space *map_dim;
+ isl_space *pwf_dim;
+ unsigned n_in;
+ int ok;
+
+ ctx = isl_map_get_ctx(map);
+ if (!ctx)
+ goto error;
+
+ map_dim = isl_map_get_space(map);
+ pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+ ok = join_compatible(map_dim, pwf_dim);
+ isl_space_free(map_dim);
+ isl_space_free(pwf_dim);
+ if (!ok)
+ isl_die(ctx, isl_error_invalid, "incompatible dimensions",
+ goto error);
+
+ n_in = isl_map_dim(map, isl_dim_in);
+ pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
+
+ dom = isl_map_wrap(map);
+ pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
+ isl_set_get_space(dom));
+
+ pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
+ pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
+
+ return pwf;
+error:
+ isl_map_free(map);
+ isl_pw_qpolynomial_fold_free(pwf);
+ return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
+ __isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
+ int *tight)
+{
+ return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
+}
+
+struct isl_apply_fold_data {
+ isl_union_pw_qpolynomial_fold *upwf;
+ isl_union_pw_qpolynomial_fold *res;
+ isl_map *map;
+ int tight;
+};
+
+static int pw_qpolynomial_fold_apply(__isl_take isl_pw_qpolynomial_fold *pwf,
+ void *user)
+{
+ isl_space *map_dim;
+ isl_space *pwf_dim;
+ struct isl_apply_fold_data *data = user;
+ int ok;
+
+ map_dim = isl_map_get_space(data->map);
+ pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+ ok = join_compatible(map_dim, pwf_dim);
+ isl_space_free(map_dim);
+ isl_space_free(pwf_dim);
+
+ if (ok) {
+ pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
+ pwf, data->tight ? &data->tight : NULL);
+ data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+ data->res, pwf);
+ } else
+ isl_pw_qpolynomial_fold_free(pwf);
+
+ return 0;
+}
+
+static int map_apply(__isl_take isl_map *map, void *user)
+{
+ struct isl_apply_fold_data *data = user;
+ int r;
+
+ data->map = map;
+ r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
+ data->upwf, &pw_qpolynomial_fold_apply, data);
+
+ isl_map_free(map);
+ return r;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
+ __isl_take isl_union_map *umap,
+ __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+ isl_space *dim;
+ enum isl_fold type;
+ struct isl_apply_fold_data data;
+
+ upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+ isl_union_map_get_space(umap));
+ umap = isl_union_map_align_params(umap,
+ isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+ data.upwf = upwf;
+ data.tight = tight ? 1 : 0;
+ dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
+ type = isl_union_pw_qpolynomial_fold_get_type(upwf);
+ data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
+ if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
+ goto error;
+
+ isl_union_map_free(umap);
+ isl_union_pw_qpolynomial_fold_free(upwf);
+
+ if (tight)
+ *tight = data.tight;
+
+ return data.res;
+error:
+ isl_union_map_free(umap);
+ isl_union_pw_qpolynomial_fold_free(upwf);
+ isl_union_pw_qpolynomial_fold_free(data.res);
+ return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
+ __isl_take isl_union_set *uset,
+ __isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+ return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
+}
+
+/* Reorder the dimension of "fold" according to the given reordering.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
+{
+ int i;
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold || !r)
+ goto error;
+
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
+ isl_reordering_copy(r));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ fold = isl_qpolynomial_fold_reset_domain_space(fold,
+ isl_space_copy(r->dim));
+
+ isl_reordering_free(r);
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ isl_reordering_free(r);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
+ __isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+ int i;
+
+ if (isl_int_is_one(v))
+ return fold;
+ if (fold && isl_int_is_zero(v)) {
+ isl_qpolynomial_fold *zero;
+ isl_space *dim = isl_space_copy(fold->dim);
+ zero = isl_qpolynomial_fold_empty(fold->type, dim);
+ isl_qpolynomial_fold_free(fold);
+ return zero;
+ }
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ return NULL;
+
+ if (isl_int_is_neg(v))
+ fold->type = isl_fold_type_negate(fold->type);
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ return fold;
+error:
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
+ __isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+ return isl_qpolynomial_fold_mul_isl_int(fold, v);
+}
+
+/* Multiply "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+ int i;
+
+ if (!fold || !v)
+ goto error;
+
+ if (isl_val_is_one(v)) {
+ isl_val_free(v);
+ return fold;
+ }
+ if (isl_val_is_zero(v)) {
+ isl_qpolynomial_fold *zero;
+ isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+ zero = isl_qpolynomial_fold_empty(fold->type, space);
+ isl_qpolynomial_fold_free(fold);
+ isl_val_free(v);
+ return zero;
+ }
+ if (!isl_val_is_rat(v))
+ isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
+ "expecting rational factor", goto error);
+
+ fold = isl_qpolynomial_fold_cow(fold);
+ if (!fold)
+ goto error;
+
+ if (isl_val_is_neg(v))
+ fold->type = isl_fold_type_negate(fold->type);
+ for (i = 0; i < fold->n; ++i) {
+ fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
+ isl_val_copy(v));
+ if (!fold->qp[i])
+ goto error;
+ }
+
+ isl_val_free(v);
+ return fold;
+error:
+ isl_val_free(v);
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
+
+/* Divide "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
+ __isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+ if (!fold || !v)
+ goto error;
+
+ if (isl_val_is_one(v)) {
+ isl_val_free(v);
+ return fold;
+ }
+ if (!isl_val_is_rat(v))
+ isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
+ "expecting rational factor", goto error);
+ if (isl_val_is_zero(v))
+ isl_die(isl_val_get_ctx(v), isl_error_invalid,
+ "cannot scale down by zero", goto error);
+
+ return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
+error:
+ isl_val_free(v);
+ isl_qpolynomial_fold_free(fold);
+ return NULL;
+}
Added: polly/trunk/lib/External/isl/isl_gmp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_gmp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_gmp.c (added)
+++ polly/trunk/lib/External/isl/isl_gmp.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_int.h>
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash)
+{
+ int sa = v[0]._mp_size;
+ int abs_sa = sa < 0 ? -sa : sa;
+ unsigned char *data = (unsigned char *)v[0]._mp_d;
+ unsigned char *end = data + abs_sa * sizeof(v[0]._mp_d[0]);
+
+ if (sa < 0)
+ isl_hash_byte(hash, 0xFF);
+ for (; data < end; ++data)
+ isl_hash_byte(hash, *data);
+ return hash;
+}
Added: polly/trunk/lib/External/isl/isl_hash.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hash.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hash.c (added)
+++ polly/trunk/lib/External/isl/isl_hash.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <isl/hash.h>
+#include <isl/ctx.h>
+#include "isl_config.h"
+
+uint32_t isl_hash_string(uint32_t hash, const char *s)
+{
+ for (; *s; s++)
+ isl_hash_byte(hash, *s);
+ return hash;
+}
+
+uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
+{
+ int i;
+ const char *s = p;
+ for (i = 0; i < len; ++i)
+ isl_hash_byte(hash, s[i]);
+ return hash;
+}
+
+static unsigned int round_up(unsigned int v)
+{
+ int old_v = v;
+
+ while (v) {
+ old_v = v;
+ v ^= v & -v;
+ }
+ return old_v << 1;
+}
+
+int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
+ int min_size)
+{
+ size_t size;
+
+ if (!table)
+ return -1;
+
+ if (min_size < 2)
+ min_size = 2;
+ table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
+ table->n = 0;
+
+ size = 1 << table->bits;
+ table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+ size);
+ if (!table->entries)
+ return -1;
+
+ return 0;
+}
+
+/* Dummy comparison function that always returns false.
+ */
+static int no(const void *entry, const void *val)
+{
+ return 0;
+}
+
+/* Extend "table" to twice its size.
+ * Return 0 on success and -1 on error.
+ *
+ * We reuse isl_hash_table_find to create entries in the extended table.
+ * Since all entries in the original table are assumed to be different,
+ * there is no need to compare them against each other.
+ */
+static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+ int n;
+ size_t old_size, size;
+ struct isl_hash_table_entry *entries;
+ uint32_t h;
+
+ entries = table->entries;
+ old_size = 1 << table->bits;
+ size = 2 * old_size;
+ table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+ size);
+ if (!table->entries) {
+ table->entries = entries;
+ return -1;
+ }
+
+ n = table->n;
+ table->n = 0;
+ table->bits++;
+
+ for (h = 0; h < old_size; ++h) {
+ struct isl_hash_table_entry *entry;
+
+ if (!entries[h].data)
+ continue;
+
+ entry = isl_hash_table_find(ctx, table, entries[h].hash,
+ &no, NULL, 1);
+ if (!entry) {
+ table->bits--;
+ free(table->entries);
+ table->entries = entries;
+ table->n = n;
+ return -1;
+ }
+
+ *entry = entries[h];
+ }
+
+ free(entries);
+
+ return 0;
+}
+
+struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
+{
+ struct isl_hash_table *table = NULL;
+
+ table = isl_alloc_type(ctx, struct isl_hash_table);
+ if (isl_hash_table_init(ctx, table, min_size))
+ goto error;
+ return table;
+error:
+ isl_hash_table_free(ctx, table);
+ return NULL;
+}
+
+void isl_hash_table_clear(struct isl_hash_table *table)
+{
+ if (!table)
+ return;
+ free(table->entries);
+}
+
+void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+ if (!table)
+ return;
+ isl_hash_table_clear(table);
+ free(table);
+}
+
+struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
+ struct isl_hash_table *table,
+ uint32_t key_hash,
+ int (*eq)(const void *entry, const void *val),
+ const void *val, int reserve)
+{
+ size_t size;
+ uint32_t h, key_bits;
+
+ key_bits = isl_hash_bits(key_hash, table->bits);
+ size = 1 << table->bits;
+ for (h = key_bits; table->entries[h].data; h = (h+1) % size)
+ if (table->entries[h].hash == key_hash &&
+ eq(table->entries[h].data, val))
+ return &table->entries[h];
+
+ if (!reserve)
+ return NULL;
+
+ if (4 * table->n >= 3 * size) {
+ if (grow_table(ctx, table) < 0)
+ return NULL;
+ return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
+ }
+
+ table->n++;
+ table->entries[h].hash = key_hash;
+
+ return &table->entries[h];
+}
+
+int isl_hash_table_foreach(struct isl_ctx *ctx,
+ struct isl_hash_table *table,
+ int (*fn)(void **entry, void *user), void *user)
+{
+ size_t size;
+ uint32_t h;
+
+ if (!table->entries)
+ return -1;
+
+ size = 1 << table->bits;
+ for (h = 0; h < size; ++ h)
+ if (table->entries[h].data &&
+ fn(&table->entries[h].data, user) < 0)
+ return -1;
+
+ return 0;
+}
+
+void isl_hash_table_remove(struct isl_ctx *ctx,
+ struct isl_hash_table *table,
+ struct isl_hash_table_entry *entry)
+{
+ int h, h2;
+ size_t size;
+
+ if (!table || !entry)
+ return;
+
+ size = 1 << table->bits;
+ h = entry - table->entries;
+ isl_assert(ctx, h >= 0 && h < size, return);
+
+ for (h2 = h+1; table->entries[h2 % size].data; h2++) {
+ uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
+ table->bits);
+ uint32_t offset = (size + bits - (h+1)) % size;
+ if (offset <= h2 - (h+1))
+ continue;
+ *entry = table->entries[h2 % size];
+ h = h2;
+ entry = &table->entries[h % size];
+ }
+
+ entry->hash = 0;
+ entry->data = NULL;
+ table->n--;
+}
Added: polly/trunk/lib/External/isl/isl_hide_deprecated.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hide_deprecated.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hide_deprecated.h (added)
+++ polly/trunk/lib/External/isl/isl_hide_deprecated.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,53 @@
+#define isl_aff_get_constant isl_gmp_aff_get_constant
+#define isl_aff_get_coefficient isl_gmp_aff_get_coefficient
+#define isl_aff_get_denominator isl_gmp_aff_get_denominator
+#define isl_aff_set_constant isl_gmp_aff_set_constant
+#define isl_aff_set_coefficient isl_gmp_aff_set_coefficient
+#define isl_aff_set_denominator isl_gmp_aff_set_denominator
+#define isl_aff_add_constant isl_gmp_aff_add_constant
+#define isl_aff_add_constant_num isl_gmp_aff_add_constant_num
+#define isl_aff_add_coefficient isl_gmp_aff_add_coefficient
+#define isl_aff_mod isl_gmp_aff_mod
+#define isl_aff_scale isl_gmp_aff_scale
+#define isl_aff_scale_down isl_gmp_aff_scale_down
+#define isl_pw_aff_mod isl_gmp_pw_aff_mod
+#define isl_pw_aff_scale isl_gmp_pw_aff_scale
+#define isl_pw_aff_scale_down isl_gmp_pw_aff_scale_down
+#define isl_multi_aff_scale isl_gmp_multi_aff_scale
+#define isl_ast_expr_get_int isl_gmp_ast_expr_get_int
+#define isl_constraint_get_constant isl_gmp_constraint_get_constant
+#define isl_constraint_get_coefficient isl_gmp_constraint_get_coefficient
+#define isl_constraint_set_constant isl_gmp_constraint_set_constant
+#define isl_constraint_set_coefficient isl_gmp_constraint_set_coefficient
+#define isl_basic_set_max isl_gmp_basic_set_max
+#define isl_set_min isl_gmp_set_min
+#define isl_set_max isl_gmp_set_max
+#define isl_gmp_hash isl_gmp_gmp_hash
+#define isl_basic_map_plain_is_fixed isl_gmp_basic_map_plain_is_fixed
+#define isl_map_fix isl_gmp_map_fix
+#define isl_map_plain_is_fixed isl_gmp_map_plain_is_fixed
+#define isl_map_fast_is_fixed isl_gmp_map_fast_is_fixed
+#define isl_map_fixed_power isl_gmp_map_fixed_power
+#define isl_mat_get_element isl_gmp_mat_get_element
+#define isl_mat_set_element isl_gmp_mat_set_element
+#define isl_point_get_coordinate isl_gmp_point_get_coordinate
+#define isl_point_set_coordinate isl_gmp_point_set_coordinate
+#define isl_qpolynomial_rat_cst_on_domain isl_gmp_qpolynomial_rat_cst_on_domain
+#define isl_qpolynomial_is_cst isl_gmp_qpolynomial_is_cst
+#define isl_qpolynomial_scale isl_gmp_qpolynomial_scale
+#define isl_term_get_num isl_gmp_term_get_num
+#define isl_term_get_den isl_gmp_term_get_den
+#define isl_qpolynomial_fold_scale isl_gmp_qpolynomial_fold_scale
+#define isl_pw_qpolynomial_fold_fix_dim isl_gmp_pw_qpolynomial_fold_fix_dim
+#define isl_basic_set_fix isl_gmp_basic_set_fix
+#define isl_set_lower_bound isl_gmp_set_lower_bound
+#define isl_set_upper_bound isl_gmp_set_upper_bound
+#define isl_set_fix isl_gmp_set_fix
+#define isl_set_plain_is_fixed isl_gmp_set_plain_is_fixed
+#define isl_union_map_fixed_power isl_gmp_union_map_fixed_power
+#define isl_val_int_from_isl_int isl_gmp_val_int_from_isl_int
+#define isl_val_get_num_isl_int isl_gmp_val_get_num_isl_int
+#define isl_vec_get_element isl_gmp_vec_get_element
+#define isl_vec_set_element isl_gmp_vec_set_element
+#define isl_vec_set isl_gmp_vec_set
+#define isl_vec_fdiv_r isl_gmp_vec_fdiv_r
Added: polly/trunk/lib/External/isl/isl_hmap_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_hmap_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_hmap_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_hmap_templ.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2011 INRIA Saclay
+ * Copyright 2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+#include <isl/ctx.h>
+#include <isl/hash.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#define KEY CAT(isl_,KEY_BASE)
+#define VAL CAT(isl_,VAL_BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xHMAP(KEY,VAL_BASE) KEY ## _to_ ## VAL_BASE
+#define yHMAP(KEY,VAL_BASE) xHMAP(KEY,VAL_BASE)
+#define HMAP yHMAP(KEY,VAL_BASE)
+#define HMAP_BASE yHMAP(KEY_BASE,VAL_BASE)
+#define xS(TYPE1,TYPE2,NAME) struct isl_ ## TYPE1 ## _ ## TYPE2 ## _ ## NAME
+#define yS(TYPE1,TYPE2,NAME) xS(TYPE1,TYPE2,NAME)
+#define S(NAME) yS(KEY_BASE,VAL_BASE,NAME)
+
+struct HMAP {
+ int ref;
+ isl_ctx *ctx;
+ struct isl_hash_table table;
+};
+
+S(pair) {
+ KEY *key;
+ VAL *val;
+};
+
+__isl_give HMAP *FN(HMAP,alloc)(isl_ctx *ctx, int min_size)
+{
+ HMAP *hmap;
+
+ hmap = isl_calloc_type(ctx, HMAP);
+ if (!hmap)
+ return NULL;
+
+ hmap->ctx = ctx;
+ isl_ctx_ref(ctx);
+ hmap->ref = 1;
+
+ if (isl_hash_table_init(ctx, &hmap->table, min_size) < 0)
+ return FN(HMAP,free)(hmap);
+
+ return hmap;
+}
+
+static int free_pair(void **entry, void *user)
+{
+ S(pair) *pair = *entry;
+ FN(KEY,free)(pair->key);
+ FN(VAL,free)(pair->val);
+ free(pair);
+ *entry = NULL;
+ return 0;
+}
+
+__isl_null HMAP *FN(HMAP,free)(__isl_take HMAP *hmap)
+{
+ if (!hmap)
+ return NULL;
+ if (--hmap->ref > 0)
+ return NULL;
+ isl_hash_table_foreach(hmap->ctx, &hmap->table, &free_pair, NULL);
+ isl_hash_table_clear(&hmap->table);
+ isl_ctx_deref(hmap->ctx);
+ free(hmap);
+ return NULL;
+}
+
+isl_ctx *FN(HMAP,get_ctx)(__isl_keep HMAP *hmap)
+{
+ return hmap ? hmap->ctx : NULL;
+}
+
+/* Add a mapping from "key" to "val" to the associative array
+ * pointed to by user.
+ */
+static int add_key_val(__isl_take KEY *key, __isl_take VAL *val, void *user)
+{
+ HMAP **hmap = (HMAP **) user;
+
+ *hmap = FN(HMAP,set)(*hmap, key, val);
+
+ if (!*hmap)
+ return -1;
+
+ return 0;
+}
+
+__isl_give HMAP *FN(HMAP,dup)(__isl_keep HMAP *hmap)
+{
+ HMAP *dup;
+
+ if (!hmap)
+ return NULL;
+
+ dup = FN(HMAP,alloc)(hmap->ctx, hmap->table.n);
+ if (FN(HMAP,foreach)(hmap, &add_key_val, &dup) < 0)
+ return FN(HMAP,free)(dup);
+
+ return dup;
+}
+
+__isl_give HMAP *FN(HMAP,cow)(__isl_take HMAP *hmap)
+{
+ if (!hmap)
+ return NULL;
+
+ if (hmap->ref == 1)
+ return hmap;
+ hmap->ref--;
+ return FN(HMAP,dup)(hmap);
+}
+
+__isl_give HMAP *FN(HMAP,copy)(__isl_keep HMAP *hmap)
+{
+ if (!hmap)
+ return NULL;
+
+ hmap->ref++;
+ return hmap;
+}
+
+static int has_key(const void *entry, const void *c_key)
+{
+ const S(pair) *pair = entry;
+ KEY *key = (KEY *) c_key;
+
+ return KEY_EQUAL(pair->key, key);
+}
+
+int FN(HMAP,has)(__isl_keep HMAP *hmap, __isl_keep KEY *key)
+{
+ uint32_t hash;
+
+ if (!hmap)
+ return -1;
+
+ hash = FN(KEY,get_hash)(key);
+ return !!isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 0);
+}
+
+__isl_give VAL *FN(HMAP,get)(__isl_keep HMAP *hmap, __isl_take KEY *key)
+{
+ struct isl_hash_table_entry *entry;
+ S(pair) *pair;
+ uint32_t hash;
+
+ if (!hmap || !key)
+ goto error;
+
+ hash = FN(KEY,get_hash)(key);
+ entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 0);
+ FN(KEY,free)(key);
+
+ if (!entry)
+ return NULL;
+
+ pair = entry->data;
+
+ return FN(VAL,copy)(pair->val);
+error:
+ FN(KEY,free)(key);
+ return NULL;
+}
+
+/* Remove the mapping between "key" and its associated value (if any)
+ * from "hmap".
+ *
+ * If "key" is not mapped to anything, then we leave "hmap" untouched"
+ */
+__isl_give HMAP *FN(HMAP,drop)(__isl_take HMAP *hmap, __isl_take KEY *key)
+{
+ struct isl_hash_table_entry *entry;
+ S(pair) *pair;
+ uint32_t hash;
+
+ if (!hmap || !key)
+ goto error;
+
+ hash = FN(KEY,get_hash)(key);
+ entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 0);
+ if (!entry) {
+ FN(KEY,free)(key);
+ return hmap;
+ }
+
+ hmap = FN(HMAP,cow)(hmap);
+ if (!hmap)
+ goto error;
+ entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 0);
+ FN(KEY,free)(key);
+
+ if (!entry)
+ isl_die(hmap->ctx, isl_error_internal,
+ "missing entry" , goto error);
+
+ pair = entry->data;
+ isl_hash_table_remove(hmap->ctx, &hmap->table, entry);
+ FN(KEY,free)(pair->key);
+ FN(VAL,free)(pair->val);
+ free(pair);
+
+ return hmap;
+error:
+ FN(KEY,free)(key);
+ FN(HMAP,free)(hmap);
+ return NULL;
+}
+
+/* Add a mapping from "key" to "val" to "hmap".
+ * If "key" was already mapped to something else, then that mapping
+ * is replaced.
+ * If key happened to be mapped to "val" already, then we leave
+ * "hmap" untouched.
+ */
+__isl_give HMAP *FN(HMAP,set)(__isl_take HMAP *hmap,
+ __isl_take KEY *key, __isl_take VAL *val)
+{
+ struct isl_hash_table_entry *entry;
+ S(pair) *pair;
+ uint32_t hash;
+
+ if (!hmap || !key || !val)
+ goto error;
+
+ hash = FN(KEY,get_hash)(key);
+ entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 0);
+ if (entry) {
+ int equal;
+ pair = entry->data;
+ equal = VAL_EQUAL(pair->val, val);
+ if (equal < 0)
+ goto error;
+ if (equal) {
+ FN(KEY,free)(key);
+ FN(VAL,free)(val);
+ return hmap;
+ }
+ }
+
+ hmap = FN(HMAP,cow)(hmap);
+ if (!hmap)
+ goto error;
+
+ entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+ &has_key, key, 1);
+
+ if (!entry)
+ goto error;
+
+ if (entry->data) {
+ pair = entry->data;
+ FN(VAL,free)(pair->val);
+ pair->val = val;
+ FN(KEY,free)(key);
+ return hmap;
+ }
+
+ pair = isl_alloc_type(hmap->ctx, S(pair));
+ if (!pair)
+ goto error;
+
+ entry->data = pair;
+ pair->key = key;
+ pair->val = val;
+ return hmap;
+error:
+ FN(KEY,free)(key);
+ FN(VAL,free)(val);
+ return FN(HMAP,free)(hmap);
+}
+
+/* Internal data structure for isl_map_to_basic_set_foreach.
+ *
+ * fn is the function that should be called on each entry.
+ * user is the user-specified final argument to fn.
+ */
+S(foreach_data) {
+ int (*fn)(__isl_take KEY *key, __isl_take VAL *val, void *user);
+ void *user;
+};
+
+/* Call data->fn on a copy of the key and value in *entry.
+ */
+static int call_on_copy(void **entry, void *user)
+{
+ S(pair) *pair = *entry;
+ S(foreach_data) *data = (S(foreach_data) *) user;
+
+ return data->fn(FN(KEY,copy)(pair->key), FN(VAL,copy)(pair->val),
+ data->user);
+}
+
+/* Call "fn" on each pair of key and value in "hmap".
+ */
+int FN(HMAP,foreach)(__isl_keep HMAP *hmap,
+ int (*fn)(__isl_take KEY *key, __isl_take VAL *val, void *user),
+ void *user)
+{
+ S(foreach_data) data = { fn, user };
+
+ if (!hmap)
+ return -1;
+
+ return isl_hash_table_foreach(hmap->ctx, &hmap->table,
+ &call_on_copy, &data);
+}
+
+/* Internal data structure for print_pair.
+ *
+ * p is the printer on which the associative array is being printed.
+ * first is set if the current key-value pair is the first to be printed.
+ */
+S(print_data) {
+ isl_printer *p;
+ int first;
+};
+
+/* Print the given key-value pair to data->p.
+ */
+static int print_pair(__isl_take KEY *key, __isl_take VAL *val, void *user)
+{
+ S(print_data) *data = user;
+
+ if (!data->first)
+ data->p = isl_printer_print_str(data->p, ", ");
+ data->p = FN(isl_printer_print,KEY_BASE)(data->p, key);
+ data->p = isl_printer_print_str(data->p, ": ");
+ data->p = FN(isl_printer_print,VAL_BASE)(data->p, val);
+ data->first = 0;
+
+ FN(KEY,free)(key);
+ FN(VAL,free)(val);
+ return 0;
+}
+
+/* Print the associative array to "p".
+ */
+__isl_give isl_printer *FN(isl_printer_print,HMAP_BASE)(
+ __isl_take isl_printer *p, __isl_keep HMAP *hmap)
+{
+ S(print_data) data;
+
+ if (!p || !hmap)
+ return isl_printer_free(p);
+
+ p = isl_printer_print_str(p, "{");
+ data.p = p;
+ data.first = 1;
+ if (FN(HMAP,foreach)(hmap, &print_pair, &data) < 0)
+ data.p = isl_printer_free(data.p);
+ p = data.p;
+ p = isl_printer_print_str(p, "}");
+
+ return p;
+}
+
+void FN(HMAP,dump)(__isl_keep HMAP *hmap)
+{
+ isl_printer *printer;
+
+ if (!hmap)
+ return;
+
+ printer = isl_printer_to_file(FN(HMAP,get_ctx)(hmap), stderr);
+ printer = FN(isl_printer_print,HMAP_BASE)(printer, hmap);
+ printer = isl_printer_end_line(printer);
+
+ isl_printer_free(printer);
+}
Added: polly/trunk/lib/External/isl/isl_id.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id.c (added)
+++ polly/trunk/lib/External/isl/isl_id.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_id_private.h>
+
+#undef BASE
+#define BASE id
+
+#include <isl_list_templ.c>
+
+/* A special, static isl_id to use as domains (and ranges)
+ * of sets and parameters domains.
+ * The user should never get a hold on this isl_id.
+ */
+isl_id isl_id_none = {
+ .ref = -1,
+ .ctx = NULL,
+ .name = "#none",
+ .user = NULL
+};
+
+isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id)
+{
+ return id ? id->ctx : NULL;
+}
+
+void *isl_id_get_user(__isl_keep isl_id *id)
+{
+ return id ? id->user : NULL;
+}
+
+const char *isl_id_get_name(__isl_keep isl_id *id)
+{
+ return id ? id->name : NULL;
+}
+
+static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+ const char *copy = name ? strdup(name) : NULL;
+ isl_id *id;
+
+ if (name && !copy)
+ return NULL;
+ id = isl_calloc_type(ctx, struct isl_id);
+ if (!id)
+ goto error;
+
+ id->ctx = ctx;
+ isl_ctx_ref(id->ctx);
+ id->ref = 1;
+ id->name = copy;
+ id->user = user;
+
+ id->hash = isl_hash_init();
+ if (name)
+ id->hash = isl_hash_string(id->hash, name);
+ else
+ id->hash = isl_hash_builtin(id->hash, user);
+
+ return id;
+error:
+ free((char *)copy);
+ return NULL;
+}
+
+uint32_t isl_id_get_hash(__isl_keep isl_id *id)
+{
+ return id ? id->hash : 0;
+}
+
+struct isl_name_and_user {
+ const char *name;
+ void *user;
+};
+
+static int isl_id_has_name_and_user(const void *entry, const void *val)
+{
+ isl_id *id = (isl_id *)entry;
+ struct isl_name_and_user *nu = (struct isl_name_and_user *) val;
+
+ if (id->user != nu->user)
+ return 0;
+ if (!id->name && !nu->name)
+ return 1;
+
+ return !strcmp(id->name, nu->name);
+}
+
+__isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+ struct isl_hash_table_entry *entry;
+ uint32_t id_hash;
+ struct isl_name_and_user nu = { name, user };
+
+ if (!ctx)
+ return NULL;
+
+ id_hash = isl_hash_init();
+ if (name)
+ id_hash = isl_hash_string(id_hash, name);
+ else
+ id_hash = isl_hash_builtin(id_hash, user);
+ entry = isl_hash_table_find(ctx, &ctx->id_table, id_hash,
+ isl_id_has_name_and_user, &nu, 1);
+ if (!entry)
+ return NULL;
+ if (entry->data)
+ return isl_id_copy(entry->data);
+ entry->data = id_alloc(ctx, name, user);
+ if (!entry->data)
+ ctx->id_table.n--;
+ return entry->data;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * which should not be changed.
+ */
+__isl_give isl_id *isl_id_copy(isl_id *id)
+{
+ if (!id)
+ return NULL;
+
+ if (id->ref < 0)
+ return id;
+
+ id->ref++;
+ return id;
+}
+
+/* Compare two isl_ids.
+ *
+ * The order is fairly arbitrary. We do keep the comparison of
+ * the user pointers as a last resort since these pointer values
+ * may not be stable across different systems or even different runs.
+ */
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2)
+{
+ if (id1 == id2)
+ return 0;
+ if (!id1)
+ return -1;
+ if (!id2)
+ return 1;
+ if (!id1->name != !id2->name)
+ return !id1->name - !id2->name;
+ if (id1->name) {
+ int cmp = strcmp(id1->name, id2->name);
+ if (cmp != 0)
+ return cmp;
+ }
+ if (id1->user < id2->user)
+ return -1;
+ else
+ return 1;
+}
+
+static int isl_id_eq(const void *entry, const void *name)
+{
+ return entry == name;
+}
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id)
+{
+ if (id)
+ isl_hash_hash(hash, id->hash);
+
+ return hash;
+}
+
+/* Replace the free_user callback by "free_user".
+ */
+__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id,
+ __isl_give void (*free_user)(void *user))
+{
+ if (!id)
+ return NULL;
+
+ id->free_user = free_user;
+
+ return id;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * and should not be freed.
+ */
+__isl_null isl_id *isl_id_free(__isl_take isl_id *id)
+{
+ struct isl_hash_table_entry *entry;
+
+ if (!id)
+ return NULL;
+
+ if (id->ref < 0)
+ return NULL;
+
+ if (--id->ref > 0)
+ return NULL;
+
+ entry = isl_hash_table_find(id->ctx, &id->ctx->id_table, id->hash,
+ isl_id_eq, id, 0);
+ if (!entry)
+ isl_die(id->ctx, isl_error_unknown,
+ "unable to find id", (void)0);
+ else
+ isl_hash_table_remove(id->ctx, &id->ctx->id_table, entry);
+
+ if (id->free_user)
+ id->free_user(id->user);
+
+ free((char *)id->name);
+ isl_ctx_deref(id->ctx);
+ free(id);
+
+ return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p,
+ __isl_keep isl_id *id)
+{
+ if (!id)
+ goto error;
+
+ if (id->name)
+ p = isl_printer_print_str(p, id->name);
+ if (id->user) {
+ char buffer[50];
+ snprintf(buffer, sizeof(buffer), "@%p", id->user);
+ p = isl_printer_print_str(p, buffer);
+ }
+ return p;
+error:
+ isl_printer_free(p);
+ return NULL;
+}
Added: polly/trunk/lib/External/isl/isl_id_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_private.h (added)
+++ polly/trunk/lib/External/isl/isl_id_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_ID_PRIVATE_H
+#define ISL_ID_PRIVATE_H
+
+#include <isl/id.h>
+
+/* Represent a name and/or user pointer.
+ *
+ * If "free_user" is set, then it will be called on "user" when
+ * the last instance of the isl_id is freed.
+ */
+struct isl_id {
+ int ref;
+ isl_ctx *ctx;
+
+ const char *name;
+ void *user;
+ uint32_t hash;
+
+ __isl_give void (*free_user)(void *user);
+};
+
+#undef EL
+#define EL isl_id
+
+#include <isl_list_templ.h>
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id);
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2);
+
+extern isl_id isl_id_none;
+
+#endif
Added: polly/trunk/lib/External/isl/isl_id_to_ast_expr.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_to_ast_expr.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_to_ast_expr.c (added)
+++ polly/trunk/lib/External/isl/isl_id_to_ast_expr.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,11 @@
+#include <isl/id_to_ast_expr.h>
+#include <isl/ast.h>
+
+#define isl_id_is_equal(id1,id2) id1 == id2
+
+#define KEY_BASE id
+#define KEY_EQUAL isl_id_is_equal
+#define VAL_BASE ast_expr
+#define VAL_EQUAL isl_ast_expr_is_equal
+
+#include <isl_hmap_templ.c>
Added: polly/trunk/lib/External/isl/isl_id_to_pw_aff.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_id_to_pw_aff.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_id_to_pw_aff.c (added)
+++ polly/trunk/lib/External/isl/isl_id_to_pw_aff.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,11 @@
+#include <isl/id_to_pw_aff.h>
+#include <isl/aff.h>
+
+#define isl_id_is_equal(id1,id2) id1 == id2
+
+#define KEY_BASE id
+#define KEY_EQUAL isl_id_is_equal
+#define VAL_BASE pw_aff
+#define VAL_EQUAL isl_pw_aff_plain_is_equal
+
+#include <isl_hmap_templ.c>
Added: polly/trunk/lib/External/isl/isl_ilp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ilp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ilp.c (added)
+++ polly/trunk/lib/External/isl/isl_ilp.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/ilp.h>
+#include "isl_sample.h"
+#include <isl_seq.h>
+#include "isl_equalities.h"
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_lp_private.h>
+#include <isl_ilp_private.h>
+#include <isl/deprecated/ilp_int.h>
+
+/* Given a basic set "bset", construct a basic set U such that for
+ * each element x in U, the whole unit box positioned at x is inside
+ * the given basic set.
+ * Note that U may not contain all points that satisfy this property.
+ *
+ * We simply add the sum of all negative coefficients to the constant
+ * term. This ensures that if x satisfies the resulting constraints,
+ * then x plus any sum of unit vectors satisfies the original constraints.
+ */
+static struct isl_basic_set *unit_box_base_points(struct isl_basic_set *bset)
+{
+ int i, j, k;
+ struct isl_basic_set *unit_box = NULL;
+ unsigned total;
+
+ if (!bset)
+ goto error;
+
+ if (bset->n_eq != 0) {
+ unit_box = isl_basic_set_empty_like(bset);
+ isl_basic_set_free(bset);
+ return unit_box;
+ }
+
+ total = isl_basic_set_total_dim(bset);
+ unit_box = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
+ 0, 0, bset->n_ineq);
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ k = isl_basic_set_alloc_inequality(unit_box);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(unit_box->ineq[k], bset->ineq[i], 1 + total);
+ for (j = 0; j < total; ++j) {
+ if (isl_int_is_nonneg(unit_box->ineq[k][1 + j]))
+ continue;
+ isl_int_add(unit_box->ineq[k][0],
+ unit_box->ineq[k][0], unit_box->ineq[k][1 + j]);
+ }
+ }
+
+ isl_basic_set_free(bset);
+ return unit_box;
+error:
+ isl_basic_set_free(bset);
+ isl_basic_set_free(unit_box);
+ return NULL;
+}
+
+/* Find an integer point in "bset", preferably one that is
+ * close to minimizing "f".
+ *
+ * We first check if we can easily put unit boxes inside bset.
+ * If so, we take the best base point of any of the unit boxes we can find
+ * and round it up to the nearest integer.
+ * If not, we simply pick any integer point in "bset".
+ */
+static struct isl_vec *initial_solution(struct isl_basic_set *bset, isl_int *f)
+{
+ enum isl_lp_result res;
+ struct isl_basic_set *unit_box;
+ struct isl_vec *sol;
+
+ unit_box = unit_box_base_points(isl_basic_set_copy(bset));
+
+ res = isl_basic_set_solve_lp(unit_box, 0, f, bset->ctx->one,
+ NULL, NULL, &sol);
+ if (res == isl_lp_ok) {
+ isl_basic_set_free(unit_box);
+ return isl_vec_ceil(sol);
+ }
+
+ isl_basic_set_free(unit_box);
+
+ return isl_basic_set_sample_vec(isl_basic_set_copy(bset));
+}
+
+/* Restrict "bset" to those points with values for f in the interval [l, u].
+ */
+static struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
+ isl_int *f, isl_int l, isl_int u)
+{
+ int k;
+ unsigned total;
+
+ total = isl_basic_set_total_dim(bset);
+ bset = isl_basic_set_extend_constraints(bset, 0, 2);
+
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bset->ineq[k], f, 1 + total);
+ isl_int_sub(bset->ineq[k][0], bset->ineq[k][0], l);
+
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_seq_neg(bset->ineq[k], f, 1 + total);
+ isl_int_add(bset->ineq[k][0], bset->ineq[k][0], u);
+
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Find an integer point in "bset" that minimizes f (in any) such that
+ * the value of f lies inside the interval [l, u].
+ * Return this integer point if it can be found.
+ * Otherwise, return sol.
+ *
+ * We perform a number of steps until l > u.
+ * In each step, we look for an integer point with value in either
+ * the whole interval [l, u] or half of the interval [l, l+floor(u-l-1/2)].
+ * The choice depends on whether we have found an integer point in the
+ * previous step. If so, we look for the next point in half of the remaining
+ * interval.
+ * If we find a point, the current solution is updated and u is set
+ * to its value minus 1.
+ * If no point can be found, we update l to the upper bound of the interval
+ * we checked (u or l+floor(u-l-1/2)) plus 1.
+ */
+static struct isl_vec *solve_ilp_search(struct isl_basic_set *bset,
+ isl_int *f, isl_int *opt, struct isl_vec *sol, isl_int l, isl_int u)
+{
+ isl_int tmp;
+ int divide = 1;
+
+ isl_int_init(tmp);
+
+ while (isl_int_le(l, u)) {
+ struct isl_basic_set *slice;
+ struct isl_vec *sample;
+
+ if (!divide)
+ isl_int_set(tmp, u);
+ else {
+ isl_int_sub(tmp, u, l);
+ isl_int_fdiv_q_ui(tmp, tmp, 2);
+ isl_int_add(tmp, tmp, l);
+ }
+ slice = add_bounds(isl_basic_set_copy(bset), f, l, tmp);
+ sample = isl_basic_set_sample_vec(slice);
+ if (!sample) {
+ isl_vec_free(sol);
+ sol = NULL;
+ break;
+ }
+ if (sample->size > 0) {
+ isl_vec_free(sol);
+ sol = sample;
+ isl_seq_inner_product(f, sol->el, sol->size, opt);
+ isl_int_sub_ui(u, *opt, 1);
+ divide = 1;
+ } else {
+ isl_vec_free(sample);
+ if (!divide)
+ break;
+ isl_int_add_ui(l, tmp, 1);
+ divide = 0;
+ }
+ }
+
+ isl_int_clear(tmp);
+
+ return sol;
+}
+
+/* Find an integer point in "bset" that minimizes f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * The algorithm maintains a currently best solution and an interval [l, u]
+ * of values of f for which integer solutions could potentially still be found.
+ * The initial value of the best solution so far is any solution.
+ * The initial value of l is minimal value of f over the rationals
+ * (rounded up to the nearest integer).
+ * The initial value of u is the value of f at the initial solution minus 1.
+ *
+ * We then call solve_ilp_search to perform a binary search on the interval.
+ */
+static enum isl_lp_result solve_ilp(struct isl_basic_set *bset,
+ isl_int *f, isl_int *opt,
+ struct isl_vec **sol_p)
+{
+ enum isl_lp_result res;
+ isl_int l, u;
+ struct isl_vec *sol;
+
+ res = isl_basic_set_solve_lp(bset, 0, f, bset->ctx->one,
+ opt, NULL, &sol);
+ if (res == isl_lp_ok && isl_int_is_one(sol->el[0])) {
+ if (sol_p)
+ *sol_p = sol;
+ else
+ isl_vec_free(sol);
+ return isl_lp_ok;
+ }
+ isl_vec_free(sol);
+ if (res == isl_lp_error || res == isl_lp_empty)
+ return res;
+
+ sol = initial_solution(bset, f);
+ if (!sol)
+ return isl_lp_error;
+ if (sol->size == 0) {
+ isl_vec_free(sol);
+ return isl_lp_empty;
+ }
+ if (res == isl_lp_unbounded) {
+ isl_vec_free(sol);
+ return isl_lp_unbounded;
+ }
+
+ isl_int_init(l);
+ isl_int_init(u);
+
+ isl_int_set(l, *opt);
+
+ isl_seq_inner_product(f, sol->el, sol->size, opt);
+ isl_int_sub_ui(u, *opt, 1);
+
+ sol = solve_ilp_search(bset, f, opt, sol, l, u);
+ if (!sol)
+ res = isl_lp_error;
+
+ isl_int_clear(l);
+ isl_int_clear(u);
+
+ if (sol_p)
+ *sol_p = sol;
+ else
+ isl_vec_free(sol);
+
+ return res;
+}
+
+static enum isl_lp_result solve_ilp_with_eq(struct isl_basic_set *bset, int max,
+ isl_int *f, isl_int *opt,
+ struct isl_vec **sol_p)
+{
+ unsigned dim;
+ enum isl_lp_result res;
+ struct isl_mat *T = NULL;
+ struct isl_vec *v;
+
+ bset = isl_basic_set_copy(bset);
+ dim = isl_basic_set_total_dim(bset);
+ v = isl_vec_alloc(bset->ctx, 1 + dim);
+ if (!v)
+ goto error;
+ isl_seq_cpy(v->el, f, 1 + dim);
+ bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+ v = isl_vec_mat_product(v, isl_mat_copy(T));
+ if (!v)
+ goto error;
+ res = isl_basic_set_solve_ilp(bset, max, v->el, opt, sol_p);
+ isl_vec_free(v);
+ if (res == isl_lp_ok && sol_p) {
+ *sol_p = isl_mat_vec_product(T, *sol_p);
+ if (!*sol_p)
+ res = isl_lp_error;
+ } else
+ isl_mat_free(T);
+ isl_basic_set_free(bset);
+ return res;
+error:
+ isl_mat_free(T);
+ isl_basic_set_free(bset);
+ return isl_lp_error;
+}
+
+/* Find an integer point in "bset" that minimizes (or maximizes if max is set)
+ * f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * If there is any equality among the points in "bset", then we first
+ * project it out. Otherwise, we continue with solve_ilp above.
+ */
+enum isl_lp_result isl_basic_set_solve_ilp(struct isl_basic_set *bset, int max,
+ isl_int *f, isl_int *opt,
+ struct isl_vec **sol_p)
+{
+ unsigned dim;
+ enum isl_lp_result res;
+
+ if (!bset)
+ return isl_lp_error;
+ if (sol_p)
+ *sol_p = NULL;
+
+ isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+
+ if (isl_basic_set_plain_is_empty(bset))
+ return isl_lp_empty;
+
+ if (bset->n_eq)
+ return solve_ilp_with_eq(bset, max, f, opt, sol_p);
+
+ dim = isl_basic_set_total_dim(bset);
+
+ if (max)
+ isl_seq_neg(f, f, 1 + dim);
+
+ res = solve_ilp(bset, f, opt, sol_p);
+
+ if (max) {
+ isl_seq_neg(f, f, 1 + dim);
+ isl_int_neg(*opt, *opt);
+ }
+
+ return res;
+error:
+ isl_basic_set_free(bset);
+ return isl_lp_error;
+}
+
+static enum isl_lp_result basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ enum isl_lp_result res;
+
+ if (!obj)
+ return isl_lp_error;
+ bset = isl_basic_set_copy(bset);
+ bset = isl_basic_set_underlying_set(bset);
+ res = isl_basic_set_solve_ilp(bset, max, obj->v->el + 1, opt, NULL);
+ isl_basic_set_free(bset);
+ return res;
+}
+
+static __isl_give isl_mat *extract_divs(__isl_keep isl_basic_set *bset)
+{
+ int i;
+ isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+ isl_mat *div;
+
+ div = isl_mat_alloc(ctx, bset->n_div,
+ 1 + 1 + isl_basic_set_total_dim(bset));
+ if (!div)
+ return NULL;
+
+ for (i = 0; i < bset->n_div; ++i)
+ isl_seq_cpy(div->row[i], bset->div[i], div->n_col);
+
+ return div;
+}
+
+enum isl_lp_result isl_basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ int *exp1 = NULL;
+ int *exp2 = NULL;
+ isl_ctx *ctx;
+ isl_mat *bset_div = NULL;
+ isl_mat *div = NULL;
+ enum isl_lp_result res;
+ int bset_n_div, obj_n_div;
+
+ if (!bset || !obj)
+ return isl_lp_error;
+
+ ctx = isl_aff_get_ctx(obj);
+ if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+ isl_die(ctx, isl_error_invalid,
+ "spaces don't match", return isl_lp_error);
+ if (!isl_int_is_one(obj->v->el[0]))
+ isl_die(ctx, isl_error_unsupported,
+ "expecting integer affine expression",
+ return isl_lp_error);
+
+ bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+ obj_n_div = isl_aff_dim(obj, isl_dim_div);
+ if (bset_n_div == 0 && obj_n_div == 0)
+ return basic_set_opt(bset, max, obj, opt);
+
+ bset = isl_basic_set_copy(bset);
+ obj = isl_aff_copy(obj);
+
+ bset_div = extract_divs(bset);
+ exp1 = isl_alloc_array(ctx, int, bset_n_div);
+ exp2 = isl_alloc_array(ctx, int, obj_n_div);
+ if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+ goto error;
+
+ div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+ bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+ obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+ res = basic_set_opt(bset, max, obj, opt);
+
+ isl_mat_free(bset_div);
+ isl_mat_free(div);
+ free(exp1);
+ free(exp2);
+ isl_basic_set_free(bset);
+ isl_aff_free(obj);
+
+ return res;
+error:
+ isl_mat_free(div);
+ isl_mat_free(bset_div);
+ free(exp1);
+ free(exp2);
+ isl_basic_set_free(bset);
+ isl_aff_free(obj);
+ return isl_lp_error;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static enum isl_lp_result isl_set_opt_aligned(__isl_keep isl_set *set, int max,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ int i;
+ enum isl_lp_result res;
+ int empty = 1;
+ isl_int opt_i;
+
+ if (!set || !obj)
+ return isl_lp_error;
+ if (set->n == 0)
+ return isl_lp_empty;
+
+ res = isl_basic_set_opt(set->p[0], max, obj, opt);
+ if (res == isl_lp_error || res == isl_lp_unbounded)
+ return res;
+ if (set->n == 1)
+ return res;
+ if (res == isl_lp_ok)
+ empty = 0;
+
+ isl_int_init(opt_i);
+ for (i = 1; i < set->n; ++i) {
+ res = isl_basic_set_opt(set->p[i], max, obj, &opt_i);
+ if (res == isl_lp_error || res == isl_lp_unbounded) {
+ isl_int_clear(opt_i);
+ return res;
+ }
+ if (res == isl_lp_ok)
+ empty = 0;
+ if (max ? isl_int_gt(opt_i, *opt) : isl_int_lt(opt_i, *opt))
+ isl_int_set(*opt, opt_i);
+ }
+ isl_int_clear(opt_i);
+
+ return empty ? isl_lp_empty : isl_lp_ok;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ */
+enum isl_lp_result isl_set_opt(__isl_keep isl_set *set, int max,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ enum isl_lp_result res;
+
+ if (!set || !obj)
+ return isl_lp_error;
+
+ if (isl_space_match(set->dim, isl_dim_param,
+ obj->ls->dim, isl_dim_param))
+ return isl_set_opt_aligned(set, max, obj, opt);
+
+ set = isl_set_copy(set);
+ obj = isl_aff_copy(obj);
+ set = isl_set_align_params(set, isl_aff_get_domain_space(obj));
+ obj = isl_aff_align_params(obj, isl_set_get_space(set));
+
+ res = isl_set_opt_aligned(set, max, obj, opt);
+
+ isl_set_free(set);
+ isl_aff_free(obj);
+
+ return res;
+}
+
+enum isl_lp_result isl_basic_set_max(__isl_keep isl_basic_set *bset,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ return isl_basic_set_opt(bset, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ return isl_set_opt(set, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_min(__isl_keep isl_set *set,
+ __isl_keep isl_aff *obj, isl_int *opt)
+{
+ return isl_set_opt(set, 0, obj, opt);
+}
+
+/* Convert the result of a function that returns an isl_lp_result
+ * to an isl_val. The numerator of "v" is set to the optimal value
+ * if lp_res is isl_lp_ok. "max" is set if a maximum was computed.
+ *
+ * Return "v" with denominator set to 1 if lp_res is isl_lp_ok.
+ * Return NULL on error.
+ * Return a NaN if lp_res is isl_lp_empty.
+ * Return infinity or negative infinity if lp_res is isl_lp_unbounded,
+ * depending on "max".
+ */
+static __isl_give isl_val *convert_lp_result(enum isl_lp_result lp_res,
+ __isl_take isl_val *v, int max)
+{
+ isl_ctx *ctx;
+
+ if (lp_res == isl_lp_ok) {
+ isl_int_set_si(v->d, 1);
+ return isl_val_normalize(v);
+ }
+ ctx = isl_val_get_ctx(v);
+ isl_val_free(v);
+ if (lp_res == isl_lp_error)
+ return NULL;
+ if (lp_res == isl_lp_empty)
+ return isl_val_nan(ctx);
+ if (max)
+ return isl_val_infty(ctx);
+ else
+ return isl_val_neginfty(ctx);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_basic_set_opt_val(__isl_keep isl_basic_set *bset,
+ int max, __isl_keep isl_aff *obj)
+{
+ isl_ctx *ctx;
+ isl_val *res;
+ enum isl_lp_result lp_res;
+
+ if (!bset || !obj)
+ return NULL;
+
+ ctx = isl_aff_get_ctx(obj);
+ res = isl_val_alloc(ctx);
+ if (!res)
+ return NULL;
+ lp_res = isl_basic_set_opt(bset, max, obj, &res->n);
+ return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset,
+ __isl_keep isl_aff *obj)
+{
+ return isl_basic_set_opt_val(bset, 1, obj);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_set_opt_val(__isl_keep isl_set *set, int max,
+ __isl_keep isl_aff *obj)
+{
+ isl_ctx *ctx;
+ isl_val *res;
+ enum isl_lp_result lp_res;
+
+ if (!set || !obj)
+ return NULL;
+
+ ctx = isl_aff_get_ctx(obj);
+ res = isl_val_alloc(ctx);
+ if (!res)
+ return NULL;
+ lp_res = isl_set_opt(set, max, obj, &res->n);
+ return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the minimum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set,
+ __isl_keep isl_aff *obj)
+{
+ return isl_set_opt_val(set, 0, obj);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set,
+ __isl_keep isl_aff *obj)
+{
+ return isl_set_opt_val(set, 1, obj);
+}
Added: polly/trunk/lib/External/isl/isl_ilp_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_ilp_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_ilp_private.h (added)
+++ polly/trunk/lib/External/isl/isl_ilp_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,11 @@
+#ifndef ISL_ILP_PRIVATE_H
+#define ISL_ILP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/set.h>
+
+enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset,
+ int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_imath.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_imath.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_imath.c (added)
+++ polly/trunk/lib/External/isl/isl_imath.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,53 @@
+#include <isl_int.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash)
+{
+ unsigned const char *data = (unsigned char *)v->digits;
+ unsigned const char *end = data + v->used * sizeof(v->digits[0]);
+
+ if (v->sign == 1)
+ isl_hash_byte(hash, 0xFF);
+ for (; data < end; ++data)
+ isl_hash_byte(hash, *data);
+ return hash;
+}
+
+/* Try a standard conversion that fits into a long.
+ */
+int isl_imath_fits_slong_p(mp_int op)
+{
+ unsigned long out;
+ mp_result res = mp_int_to_int(op, &out);
+ return res == MP_OK;
+}
+
+/* Try a standard conversion that fits into an unsigned long.
+ */
+int isl_imath_fits_ulong_p(mp_int op)
+{
+ unsigned long out;
+ mp_result res = mp_int_to_uint(op, &out);
+ return res == MP_OK;
+}
+
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+ isl_int temp;
+ isl_int_init(temp);
+
+ isl_int_set_ui(temp, op2);
+ isl_int_addmul(rop, op1, temp);
+
+ isl_int_clear(temp);
+}
+
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+ isl_int temp;
+ isl_int_init(temp);
+
+ isl_int_set_ui(temp, op2);
+ isl_int_submul(rop, op1, temp);
+
+ isl_int_clear(temp);
+}
Added: polly/trunk/lib/External/isl/isl_imath.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_imath.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_imath.h (added)
+++ polly/trunk/lib/External/isl/isl_imath.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,8 @@
+#include <imath.h>
+#include <gmp_compat.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+int isl_imath_fits_ulong_p(mp_int op);
+int isl_imath_fits_slong_p(mp_int op);
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2);
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2);
Added: polly/trunk/lib/External/isl/isl_input.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_input.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_input.c (added)
+++ polly/trunk/lib/External/isl/isl_input.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,3370 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_stream_private.h>
+#include <isl/obj.h>
+#include "isl_polynomial_private.h"
+#include <isl/union_map.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl/list.h>
+#include <isl_val_private.h>
+
+struct variable {
+ char *name;
+ int pos;
+ struct variable *next;
+};
+
+struct vars {
+ struct isl_ctx *ctx;
+ int n;
+ struct variable *v;
+};
+
+static struct vars *vars_new(struct isl_ctx *ctx)
+{
+ struct vars *v;
+ v = isl_alloc_type(ctx, struct vars);
+ if (!v)
+ return NULL;
+ v->ctx = ctx;
+ v->n = 0;
+ v->v = NULL;
+ return v;
+}
+
+static void variable_free(struct variable *var)
+{
+ while (var) {
+ struct variable *next = var->next;
+ free(var->name);
+ free(var);
+ var = next;
+ }
+}
+
+static void vars_free(struct vars *v)
+{
+ if (!v)
+ return;
+ variable_free(v->v);
+ free(v);
+}
+
+static void vars_drop(struct vars *v, int n)
+{
+ struct variable *var;
+
+ if (!v || !v->v)
+ return;
+
+ v->n -= n;
+
+ var = v->v;
+ while (--n >= 0) {
+ struct variable *next = var->next;
+ free(var->name);
+ free(var);
+ var = next;
+ }
+ v->v = var;
+}
+
+static struct variable *variable_new(struct vars *v, const char *name, int len,
+ int pos)
+{
+ struct variable *var;
+ var = isl_calloc_type(v->ctx, struct variable);
+ if (!var)
+ goto error;
+ var->name = strdup(name);
+ var->name[len] = '\0';
+ var->pos = pos;
+ var->next = v->v;
+ return var;
+error:
+ variable_free(v->v);
+ return NULL;
+}
+
+static int vars_pos(struct vars *v, const char *s, int len)
+{
+ int pos;
+ struct variable *q;
+
+ if (len == -1)
+ len = strlen(s);
+ for (q = v->v; q; q = q->next) {
+ if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0')
+ break;
+ }
+ if (q)
+ pos = q->pos;
+ else {
+ pos = v->n;
+ v->v = variable_new(v, s, len, v->n);
+ if (!v->v)
+ return -1;
+ v->n++;
+ }
+ return pos;
+}
+
+static int vars_add_anon(struct vars *v)
+{
+ v->v = variable_new(v, "", 0, v->n);
+
+ if (!v->v)
+ return -1;
+ v->n++;
+
+ return 0;
+}
+
+/* Obtain next token, with some preprocessing.
+ * In particular, evaluate expressions of the form x^y,
+ * with x and y values.
+ */
+static struct isl_token *next_token(struct isl_stream *s)
+{
+ struct isl_token *tok, *tok2;
+
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE)
+ return tok;
+ if (!isl_stream_eat_if_available(s, '^'))
+ return tok;
+ tok2 = isl_stream_next_token(s);
+ if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok2, "expecting constant value");
+ goto error;
+ }
+
+ isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
+
+ isl_token_free(tok2);
+ return tok;
+error:
+ isl_token_free(tok);
+ isl_token_free(tok2);
+ return NULL;
+}
+
+/* Read an isl_val from "s".
+ *
+ * The following token sequences are recognized
+ *
+ * "infty" -> infty
+ * "-" "infty" -> -infty
+ * "NaN" -> NaN
+ * n "/" d -> n/d
+ * v -> v
+ *
+ * where n, d and v are integer constants.
+ */
+__isl_give isl_val *isl_stream_read_val(struct isl_stream *s)
+{
+ struct isl_token *tok = NULL;
+ struct isl_token *tok2 = NULL;
+ isl_val *val;
+
+ tok = next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok->type == ISL_TOKEN_INFTY) {
+ isl_token_free(tok);
+ return isl_val_infty(s->ctx);
+ }
+ if (tok->type == '-' &&
+ isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) {
+ isl_token_free(tok);
+ return isl_val_neginfty(s->ctx);
+ }
+ if (tok->type == ISL_TOKEN_NAN) {
+ isl_token_free(tok);
+ return isl_val_nan(s->ctx);
+ }
+ if (tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting value");
+ goto error;
+ }
+
+ if (isl_stream_eat_if_available(s, '/')) {
+ tok2 = next_token(s);
+ if (!tok2) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok2->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok2, "expecting value");
+ goto error;
+ }
+ val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v);
+ val = isl_val_normalize(val);
+ } else {
+ val = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+ }
+
+ isl_token_free(tok);
+ isl_token_free(tok2);
+ return val;
+error:
+ isl_token_free(tok);
+ isl_token_free(tok2);
+ return NULL;
+}
+
+/* Read an isl_val from "str".
+ */
+struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ isl_val *val;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ val = isl_stream_read_val(s);
+ isl_stream_free(s);
+ return val;
+}
+
+static int accept_cst_factor(struct isl_stream *s, isl_int *f)
+{
+ struct isl_token *tok;
+
+ tok = next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting constant value");
+ goto error;
+ }
+
+ isl_int_mul(*f, *f, tok->u.v);
+
+ isl_token_free(tok);
+
+ if (isl_stream_eat_if_available(s, '*'))
+ return accept_cst_factor(s, f);
+
+ return 0;
+error:
+ isl_token_free(tok);
+ return -1;
+}
+
+/* Given an affine expression aff, return an affine expression
+ * for aff % d, with d the next token on the stream, which is
+ * assumed to be a constant.
+ *
+ * We introduce an integer division q = [aff/d] and the result
+ * is set to aff - d q.
+ */
+static __isl_give isl_pw_aff *affine_mod(struct isl_stream *s,
+ struct vars *v, __isl_take isl_pw_aff *aff)
+{
+ struct isl_token *tok;
+ isl_pw_aff *q;
+
+ tok = next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting constant value");
+ goto error;
+ }
+
+ q = isl_pw_aff_copy(aff);
+ q = isl_pw_aff_scale_down(q, tok->u.v);
+ q = isl_pw_aff_floor(q);
+ q = isl_pw_aff_scale(q, tok->u.v);
+
+ aff = isl_pw_aff_sub(aff, q);
+
+ isl_token_free(tok);
+ return aff;
+error:
+ isl_pw_aff_free(aff);
+ isl_token_free(tok);
+ return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s,
+ __isl_take isl_space *space, struct vars *v);
+static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v);
+
+static __isl_give isl_pw_aff *accept_minmax(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v)
+{
+ struct isl_token *tok;
+ isl_pw_aff_list *list = NULL;
+ int min;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ goto error;
+ min = tok->type == ISL_TOKEN_MIN;
+ isl_token_free(tok);
+
+ if (isl_stream_eat(s, '('))
+ goto error;
+
+ list = accept_affine_list(s, isl_space_copy(dim), v);
+ if (!list)
+ goto error;
+
+ if (isl_stream_eat(s, ')'))
+ goto error;
+
+ isl_space_free(dim);
+ return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list);
+error:
+ isl_space_free(dim);
+ isl_pw_aff_list_free(list);
+ return NULL;
+}
+
+/* Is "tok" the start of an integer division?
+ */
+static int is_start_of_div(struct isl_token *tok)
+{
+ if (!tok)
+ return 0;
+ if (tok->type == '[')
+ return 1;
+ if (tok->type == ISL_TOKEN_FLOOR)
+ return 1;
+ if (tok->type == ISL_TOKEN_CEIL)
+ return 1;
+ if (tok->type == ISL_TOKEN_FLOORD)
+ return 1;
+ if (tok->type == ISL_TOKEN_CEILD)
+ return 1;
+ return 0;
+}
+
+/* Read an integer division from "s" and return it as an isl_pw_aff.
+ *
+ * The integer division can be of the form
+ *
+ * [<affine expression>]
+ * floor(<affine expression>)
+ * ceil(<affine expression>)
+ * floord(<affine expression>,<denominator>)
+ * ceild(<affine expression>,<denominator>)
+ */
+static __isl_give isl_pw_aff *accept_div(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v)
+{
+ struct isl_token *tok;
+ int f = 0;
+ int c = 0;
+ int extra = 0;
+ isl_pw_aff *pwaff = NULL;
+
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD))
+ extra = f = 1;
+ else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD))
+ extra = c = 1;
+ else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR))
+ f = 1;
+ else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL))
+ c = 1;
+ if (f || c) {
+ if (isl_stream_eat(s, '('))
+ goto error;
+ } else {
+ if (isl_stream_eat(s, '['))
+ goto error;
+ }
+
+ pwaff = accept_affine(s, isl_space_copy(dim), v);
+
+ if (extra) {
+ if (isl_stream_eat(s, ','))
+ goto error;
+
+ tok = next_token(s);
+ if (!tok)
+ goto error;
+ if (tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expected denominator");
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ isl_pw_aff_scale_down(pwaff, tok->u.v);
+ isl_token_free(tok);
+ }
+
+ if (c)
+ pwaff = isl_pw_aff_ceil(pwaff);
+ else
+ pwaff = isl_pw_aff_floor(pwaff);
+
+ if (f || c) {
+ if (isl_stream_eat(s, ')'))
+ goto error;
+ } else {
+ if (isl_stream_eat(s, ']'))
+ goto error;
+ }
+
+ isl_space_free(dim);
+ return pwaff;
+error:
+ isl_space_free(dim);
+ isl_pw_aff_free(pwaff);
+ return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine_factor(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v)
+{
+ struct isl_token *tok = NULL;
+ isl_pw_aff *res = NULL;
+
+ tok = next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+
+ if (tok->type == ISL_TOKEN_AFF) {
+ res = isl_pw_aff_copy(tok->u.pwaff);
+ isl_token_free(tok);
+ } else if (tok->type == ISL_TOKEN_IDENT) {
+ int n = v->n;
+ int pos = vars_pos(v, tok->u.s, -1);
+ isl_aff *aff;
+
+ if (pos < 0)
+ goto error;
+ if (pos >= n) {
+ vars_drop(v, v->n - n);
+ isl_stream_error(s, tok, "unknown identifier");
+ goto error;
+ }
+
+ aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(dim)));
+ if (!aff)
+ goto error;
+ isl_int_set_si(aff->v->el[2 + pos], 1);
+ res = isl_pw_aff_from_aff(aff);
+ isl_token_free(tok);
+ } else if (tok->type == ISL_TOKEN_VALUE) {
+ if (isl_stream_eat_if_available(s, '*')) {
+ res = accept_affine_factor(s, isl_space_copy(dim), v);
+ res = isl_pw_aff_scale(res, tok->u.v);
+ } else {
+ isl_local_space *ls;
+ isl_aff *aff;
+ ls = isl_local_space_from_space(isl_space_copy(dim));
+ aff = isl_aff_zero_on_domain(ls);
+ aff = isl_aff_add_constant(aff, tok->u.v);
+ res = isl_pw_aff_from_aff(aff);
+ }
+ isl_token_free(tok);
+ } else if (tok->type == '(') {
+ isl_token_free(tok);
+ tok = NULL;
+ res = accept_affine(s, isl_space_copy(dim), v);
+ if (!res)
+ goto error;
+ if (isl_stream_eat(s, ')'))
+ goto error;
+ } else if (is_start_of_div(tok)) {
+ isl_stream_push_token(s, tok);
+ tok = NULL;
+ res = accept_div(s, isl_space_copy(dim), v);
+ } else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) {
+ isl_stream_push_token(s, tok);
+ tok = NULL;
+ res = accept_minmax(s, isl_space_copy(dim), v);
+ } else {
+ isl_stream_error(s, tok, "expecting factor");
+ goto error;
+ }
+ if (isl_stream_eat_if_available(s, '%') ||
+ isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) {
+ isl_space_free(dim);
+ return affine_mod(s, v, res);
+ }
+ if (isl_stream_eat_if_available(s, '*')) {
+ isl_int f;
+ isl_int_init(f);
+ isl_int_set_si(f, 1);
+ if (accept_cst_factor(s, &f) < 0) {
+ isl_int_clear(f);
+ goto error2;
+ }
+ res = isl_pw_aff_scale(res, f);
+ isl_int_clear(f);
+ }
+ if (isl_stream_eat_if_available(s, '/')) {
+ isl_int f;
+ isl_int_init(f);
+ isl_int_set_si(f, 1);
+ if (accept_cst_factor(s, &f) < 0) {
+ isl_int_clear(f);
+ goto error2;
+ }
+ res = isl_pw_aff_scale_down(res, f);
+ isl_int_clear(f);
+ }
+
+ isl_space_free(dim);
+ return res;
+error:
+ isl_token_free(tok);
+error2:
+ isl_pw_aff_free(res);
+ isl_space_free(dim);
+ return NULL;
+}
+
+static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v)
+{
+ isl_aff *aff;
+ isl_space *space;
+
+ space = isl_pw_aff_get_domain_space(pwaff);
+ aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+ aff = isl_aff_add_constant(aff, v);
+
+ return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff));
+}
+
+/* Return a piecewise affine expression defined on the specified domain
+ * that represents NaN.
+ */
+static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space)
+{
+ isl_local_space *ls;
+
+ ls = isl_local_space_from_space(isl_space_copy(space));
+ return isl_pw_aff_nan_on_domain(ls);
+}
+
+static __isl_give isl_pw_aff *accept_affine(struct isl_stream *s,
+ __isl_take isl_space *space, struct vars *v)
+{
+ struct isl_token *tok = NULL;
+ isl_local_space *ls;
+ isl_pw_aff *res;
+ int sign = 1;
+
+ ls = isl_local_space_from_space(isl_space_copy(space));
+ res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
+ if (!res)
+ goto error;
+
+ for (;;) {
+ tok = next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok->type == '-') {
+ sign = -sign;
+ isl_token_free(tok);
+ continue;
+ }
+ if (tok->type == '(' || is_start_of_div(tok) ||
+ tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX ||
+ tok->type == ISL_TOKEN_IDENT ||
+ tok->type == ISL_TOKEN_AFF) {
+ isl_pw_aff *term;
+ isl_stream_push_token(s, tok);
+ tok = NULL;
+ term = accept_affine_factor(s,
+ isl_space_copy(space), v);
+ if (sign < 0)
+ res = isl_pw_aff_sub(res, term);
+ else
+ res = isl_pw_aff_add(res, term);
+ if (!res)
+ goto error;
+ sign = 1;
+ } else if (tok->type == ISL_TOKEN_VALUE) {
+ if (sign < 0)
+ isl_int_neg(tok->u.v, tok->u.v);
+ if (isl_stream_eat_if_available(s, '*') ||
+ isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
+ isl_pw_aff *term;
+ term = accept_affine_factor(s,
+ isl_space_copy(space), v);
+ term = isl_pw_aff_scale(term, tok->u.v);
+ res = isl_pw_aff_add(res, term);
+ if (!res)
+ goto error;
+ } else {
+ res = add_cst(res, tok->u.v);
+ }
+ sign = 1;
+ } else if (tok->type == ISL_TOKEN_NAN) {
+ res = isl_pw_aff_add(res, nan_on_domain(space));
+ } else {
+ isl_stream_error(s, tok, "unexpected isl_token");
+ isl_stream_push_token(s, tok);
+ isl_pw_aff_free(res);
+ isl_space_free(space);
+ return NULL;
+ }
+ isl_token_free(tok);
+
+ tok = next_token(s);
+ if (tok && tok->type == '-') {
+ sign = -sign;
+ isl_token_free(tok);
+ } else if (tok && tok->type == '+') {
+ /* nothing */
+ isl_token_free(tok);
+ } else if (tok && tok->type == ISL_TOKEN_VALUE &&
+ isl_int_is_neg(tok->u.v)) {
+ isl_stream_push_token(s, tok);
+ } else {
+ if (tok)
+ isl_stream_push_token(s, tok);
+ break;
+ }
+ }
+
+ isl_space_free(space);
+ return res;
+error:
+ isl_space_free(space);
+ isl_token_free(tok);
+ isl_pw_aff_free(res);
+ return NULL;
+}
+
+static int is_comparator(struct isl_token *tok)
+{
+ if (!tok)
+ return 0;
+
+ switch (tok->type) {
+ case ISL_TOKEN_LT:
+ case ISL_TOKEN_GT:
+ case ISL_TOKEN_LE:
+ case ISL_TOKEN_GE:
+ case ISL_TOKEN_NE:
+ case '=':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static __isl_give isl_map *read_formula(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational);
+static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v, int rational);
+
+/* Accept a ternary operator, given the first argument.
+ */
+static __isl_give isl_pw_aff *accept_ternary(struct isl_stream *s,
+ __isl_take isl_map *cond, struct vars *v, int rational)
+{
+ isl_space *dim;
+ isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond;
+
+ if (!cond)
+ return NULL;
+
+ if (isl_stream_eat(s, '?'))
+ goto error;
+
+ dim = isl_space_wrap(isl_map_get_space(cond));
+ pwaff1 = accept_extended_affine(s, dim, v, rational);
+ if (!pwaff1)
+ goto error;
+
+ if (isl_stream_eat(s, ':'))
+ goto error;
+
+ dim = isl_pw_aff_get_domain_space(pwaff1);
+ pwaff2 = accept_extended_affine(s, dim, v, rational);
+ if (!pwaff1)
+ goto error;
+
+ pa_cond = isl_set_indicator_function(isl_map_wrap(cond));
+ return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2);
+error:
+ isl_map_free(cond);
+ isl_pw_aff_free(pwaff1);
+ isl_pw_aff_free(pwaff2);
+ return NULL;
+}
+
+/* Set *line and *col to those of the next token, if any.
+ */
+static void set_current_line_col(struct isl_stream *s, int *line, int *col)
+{
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return;
+
+ *line = tok->line;
+ *col = tok->col;
+ isl_stream_push_token(s, tok);
+}
+
+/* Push a token encapsulating "pa" onto "s", with the given
+ * line and column.
+ */
+static int push_aff(struct isl_stream *s, int line, int col,
+ __isl_take isl_pw_aff *pa)
+{
+ struct isl_token *tok;
+
+ tok = isl_token_new(s->ctx, line, col, 0);
+ if (!tok)
+ goto error;
+ tok->type = ISL_TOKEN_AFF;
+ tok->u.pwaff = pa;
+ isl_stream_push_token(s, tok);
+
+ return 0;
+error:
+ isl_pw_aff_free(pa);
+ return -1;
+}
+
+/* Accept an affine expression that may involve ternary operators.
+ * We first read an affine expression.
+ * If it is not followed by a comparison operator, we simply return it.
+ * Otherwise, we assume the affine expression is part of the first
+ * argument of a ternary operator and try to parse that.
+ */
+static __isl_give isl_pw_aff *accept_extended_affine(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v, int rational)
+{
+ isl_space *space;
+ isl_map *cond;
+ isl_pw_aff *pwaff;
+ struct isl_token *tok;
+ int line = -1, col = -1;
+ int is_comp;
+
+ set_current_line_col(s, &line, &col);
+
+ pwaff = accept_affine(s, dim, v);
+ if (rational)
+ pwaff = isl_pw_aff_set_rational(pwaff);
+ if (!pwaff)
+ return NULL;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return isl_pw_aff_free(pwaff);
+
+ is_comp = is_comparator(tok);
+ isl_stream_push_token(s, tok);
+ if (!is_comp)
+ return pwaff;
+
+ space = isl_pw_aff_get_domain_space(pwaff);
+ cond = isl_map_universe(isl_space_unwrap(space));
+
+ if (push_aff(s, line, col, pwaff) < 0)
+ cond = isl_map_free(cond);
+ if (!cond)
+ return NULL;
+
+ cond = read_formula(s, v, cond, rational);
+
+ return accept_ternary(s, cond, v, rational);
+}
+
+static __isl_give isl_map *read_var_def(struct isl_stream *s,
+ __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+ int rational)
+{
+ isl_pw_aff *def;
+ int pos;
+ isl_map *def_map;
+
+ if (type == isl_dim_param)
+ pos = isl_map_dim(map, isl_dim_param);
+ else {
+ pos = isl_map_dim(map, isl_dim_in);
+ if (type == isl_dim_out)
+ pos += isl_map_dim(map, isl_dim_out);
+ type = isl_dim_in;
+ }
+ --pos;
+
+ def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)),
+ v, rational);
+ def_map = isl_map_from_pw_aff(def);
+ def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0);
+ def_map = isl_set_unwrap(isl_map_domain(def_map));
+
+ map = isl_map_intersect(map, def_map);
+
+ return map;
+}
+
+static __isl_give isl_pw_aff_list *accept_affine_list(struct isl_stream *s,
+ __isl_take isl_space *dim, struct vars *v)
+{
+ isl_pw_aff *pwaff;
+ isl_pw_aff_list *list;
+ struct isl_token *tok = NULL;
+
+ pwaff = accept_affine(s, isl_space_copy(dim), v);
+ list = isl_pw_aff_list_from_pw_aff(pwaff);
+ if (!list)
+ goto error;
+
+ for (;;) {
+ tok = isl_stream_next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok->type != ',') {
+ isl_stream_push_token(s, tok);
+ break;
+ }
+ isl_token_free(tok);
+
+ pwaff = accept_affine(s, isl_space_copy(dim), v);
+ list = isl_pw_aff_list_concat(list,
+ isl_pw_aff_list_from_pw_aff(pwaff));
+ if (!list)
+ goto error;
+ }
+
+ isl_space_free(dim);
+ return list;
+error:
+ isl_space_free(dim);
+ isl_pw_aff_list_free(list);
+ return NULL;
+}
+
+static __isl_give isl_map *read_defined_var_list(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ struct isl_token *tok;
+
+ while ((tok = isl_stream_next_token(s)) != NULL) {
+ int p;
+ int n = v->n;
+
+ if (tok->type != ISL_TOKEN_IDENT)
+ break;
+
+ p = vars_pos(v, tok->u.s, -1);
+ if (p < 0)
+ goto error;
+ if (p < n) {
+ isl_stream_error(s, tok, "expecting unique identifier");
+ goto error;
+ }
+
+ map = isl_map_add_dims(map, isl_dim_out, 1);
+
+ isl_token_free(tok);
+ tok = isl_stream_next_token(s);
+ if (tok && tok->type == '=') {
+ isl_token_free(tok);
+ map = read_var_def(s, map, isl_dim_out, v, rational);
+ tok = isl_stream_next_token(s);
+ }
+
+ if (!tok || tok->type != ',')
+ break;
+
+ isl_token_free(tok);
+ }
+ if (tok)
+ isl_stream_push_token(s, tok);
+
+ return map;
+error:
+ isl_token_free(tok);
+ isl_map_free(map);
+ return NULL;
+}
+
+static int next_is_tuple(struct isl_stream *s)
+{
+ struct isl_token *tok;
+ int is_tuple;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return 0;
+ if (tok->type == '[') {
+ isl_stream_push_token(s, tok);
+ return 1;
+ }
+ if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) {
+ isl_stream_push_token(s, tok);
+ return 0;
+ }
+
+ is_tuple = isl_stream_next_token_is(s, '[');
+
+ isl_stream_push_token(s, tok);
+
+ return is_tuple;
+}
+
+/* Allocate an initial tuple with zero dimensions and an anonymous,
+ * unstructured space.
+ * A tuple is represented as an isl_multi_pw_aff.
+ * The range space is the space of the tuple.
+ * The domain space is an anonymous space
+ * with a dimension for each variable in the set of variables in "v".
+ * If a given dimension is not defined in terms of earlier dimensions in
+ * the input, then the corresponding isl_pw_aff is set equal to one time
+ * the variable corresponding to the dimension being defined.
+ */
+static __isl_give isl_multi_pw_aff *tuple_alloc(struct vars *v)
+{
+ return isl_multi_pw_aff_alloc(isl_space_alloc(v->ctx, 0, v->n, 0));
+}
+
+/* Is "pa" an expression in term of earlier dimensions?
+ * The alternative is that the dimension is defined to be equal to itself,
+ * meaning that it has a universe domain and an expression that depends
+ * on itself. "i" is the position of the expression in a sequence
+ * of "n" expressions. The final dimensions of "pa" correspond to
+ * these "n" expressions.
+ */
+static int pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n)
+{
+ isl_aff *aff;
+
+ if (!pa)
+ return -1;
+ if (pa->n != 1)
+ return 1;
+ if (!isl_set_plain_is_universe(pa->p[0].set))
+ return 1;
+
+ aff = pa->p[0].aff;
+ if (isl_int_is_zero(aff->v->el[aff->v->size - n + i]))
+ return 1;
+ return 0;
+}
+
+/* Does the tuple contain any dimensions that are defined
+ * in terms of earlier dimensions?
+ */
+static int tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple)
+{
+ int i, n;
+ int has_expr = 0;
+ isl_pw_aff *pa;
+
+ if (!tuple)
+ return -1;
+ n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+ for (i = 0; i < n; ++i) {
+ pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+ has_expr = pw_aff_is_expr(pa, i, n);
+ isl_pw_aff_free(pa);
+ if (has_expr < 0 || has_expr)
+ break;
+ }
+
+ return has_expr;
+}
+
+/* Add a dimension to the given tuple.
+ * The dimension is initially undefined, so it is encoded
+ * as one times itself.
+ */
+static __isl_give isl_multi_pw_aff *tuple_add_dim(
+ __isl_take isl_multi_pw_aff *tuple, struct vars *v)
+{
+ isl_space *space;
+ isl_aff *aff;
+ isl_pw_aff *pa;
+
+ tuple = isl_multi_pw_aff_add_dims(tuple, isl_dim_in, 1);
+ space = isl_multi_pw_aff_get_domain_space(tuple);
+ aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+ aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n, 1);
+ pa = isl_pw_aff_from_aff(aff);
+ tuple = isl_multi_pw_aff_flat_range_product(tuple,
+ isl_multi_pw_aff_from_pw_aff(pa));
+
+ return tuple;
+}
+
+/* Set the name of dimension "pos" in "tuple" to "name".
+ * During printing, we add primes if the same name appears more than once
+ * to distinguish the occurrences. Here, we remove those primes from "name"
+ * before setting the name of the dimension.
+ */
+static __isl_give isl_multi_pw_aff *tuple_set_dim_name(
+ __isl_take isl_multi_pw_aff *tuple, int pos, char *name)
+{
+ char *prime;
+
+ if (!name)
+ return tuple;
+
+ prime = strchr(name, '\'');
+ if (prime)
+ *prime = '\0';
+ tuple = isl_multi_pw_aff_set_dim_name(tuple, isl_dim_set, pos, name);
+ if (prime)
+ *prime = '\'';
+
+ return tuple;
+}
+
+/* Accept a piecewise affine expression.
+ *
+ * At the outer level, the piecewise affine expression may be of the form
+ *
+ * aff1 : condition1; aff2 : conditions2; ...
+ *
+ * or simply
+ *
+ * aff
+ *
+ * each of the affine expressions may in turn include ternary operators.
+ *
+ * There may be parentheses around some subexpression of "aff1"
+ * around "aff1" itself, around "aff1 : condition1" and/or
+ * around the entire piecewise affine expression.
+ * We therefore remove the opening parenthesis (if any) from the stream
+ * in case the closing parenthesis follows the colon, but if the closing
+ * parenthesis is the first thing in the stream after the parsed affine
+ * expression, we push the parsed expression onto the stream and parse
+ * again in case the parentheses enclose some subexpression of "aff1".
+ */
+static __isl_give isl_pw_aff *accept_piecewise_affine(struct isl_stream *s,
+ __isl_take isl_space *space, struct vars *v, int rational)
+{
+ isl_pw_aff *res;
+ isl_space *res_space;
+
+ res_space = isl_space_from_domain(isl_space_copy(space));
+ res_space = isl_space_add_dims(res_space, isl_dim_out, 1);
+ res = isl_pw_aff_empty(res_space);
+ do {
+ isl_pw_aff *pa;
+ int seen_paren;
+ int line = -1, col = -1;
+
+ set_current_line_col(s, &line, &col);
+ seen_paren = isl_stream_eat_if_available(s, '(');
+ if (seen_paren)
+ pa = accept_piecewise_affine(s, isl_space_copy(space),
+ v, rational);
+ else
+ pa = accept_extended_affine(s, isl_space_copy(space),
+ v, rational);
+ if (seen_paren && isl_stream_eat_if_available(s, ')')) {
+ seen_paren = 0;
+ if (push_aff(s, line, col, pa) < 0)
+ goto error;
+ pa = accept_extended_affine(s, isl_space_copy(space),
+ v, rational);
+ }
+ if (isl_stream_eat_if_available(s, ':')) {
+ isl_space *dom_space;
+ isl_set *dom;
+
+ dom_space = isl_pw_aff_get_domain_space(pa);
+ dom = isl_set_universe(dom_space);
+ dom = read_formula(s, v, dom, rational);
+ pa = isl_pw_aff_intersect_domain(pa, dom);
+ }
+
+ res = isl_pw_aff_union_add(res, pa);
+
+ if (seen_paren && isl_stream_eat(s, ')'))
+ goto error;
+ } while (isl_stream_eat_if_available(s, ';'));
+
+ isl_space_free(space);
+
+ return res;
+error:
+ isl_space_free(space);
+ return isl_pw_aff_free(res);
+}
+
+/* Read an affine expression from "s" and replace the definition
+ * of dimension "pos" in "tuple" by this expression.
+ *
+ * accept_extended_affine requires a wrapped space as input.
+ * The domain space of "tuple", on the other hand is an anonymous space,
+ * so we have to adjust the space of the isl_pw_aff before adding it
+ * to "tuple".
+ */
+static __isl_give isl_multi_pw_aff *read_tuple_var_def(struct isl_stream *s,
+ __isl_take isl_multi_pw_aff *tuple, int pos, struct vars *v,
+ int rational)
+{
+ isl_space *space;
+ isl_pw_aff *def;
+
+ space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0));
+
+ def = accept_piecewise_affine(s, space, v, rational);
+
+ space = isl_space_set_alloc(s->ctx, 0, v->n);
+ def = isl_pw_aff_reset_domain_space(def, space);
+ tuple = isl_multi_pw_aff_set_pw_aff(tuple, pos, def);
+
+ return tuple;
+}
+
+/* Read a list of variables and/or affine expressions and return the list
+ * as an isl_multi_pw_aff.
+ * The elements in the list are separated by either "," or "][".
+ * If "comma" is set then only "," is allowed.
+ */
+static __isl_give isl_multi_pw_aff *read_tuple_var_list(struct isl_stream *s,
+ struct vars *v, int rational, int comma)
+{
+ int i = 0;
+ struct isl_token *tok;
+ isl_multi_pw_aff *res;
+
+ res = tuple_alloc(v);
+
+ if (isl_stream_next_token_is(s, ']'))
+ return res;
+
+ while ((tok = next_token(s)) != NULL) {
+ int new_name = 0;
+
+ res = tuple_add_dim(res, v);
+
+ if (tok->type == ISL_TOKEN_IDENT) {
+ int n = v->n;
+ int p = vars_pos(v, tok->u.s, -1);
+ if (p < 0)
+ goto error;
+ new_name = p >= n;
+ }
+
+ if (tok->type == '*') {
+ if (vars_add_anon(v) < 0)
+ goto error;
+ isl_token_free(tok);
+ } else if (new_name) {
+ res = tuple_set_dim_name(res, i, v->v->name);
+ isl_token_free(tok);
+ if (isl_stream_eat_if_available(s, '='))
+ res = read_tuple_var_def(s, res, i, v,
+ rational);
+ } else {
+ isl_stream_push_token(s, tok);
+ tok = NULL;
+ if (vars_add_anon(v) < 0)
+ goto error;
+ res = read_tuple_var_def(s, res, i, v, rational);
+ }
+
+ tok = isl_stream_next_token(s);
+ if (!comma && tok && tok->type == ']' &&
+ isl_stream_next_token_is(s, '[')) {
+ isl_token_free(tok);
+ tok = isl_stream_next_token(s);
+ } else if (!tok || tok->type != ',')
+ break;
+
+ isl_token_free(tok);
+ i++;
+ }
+ if (tok)
+ isl_stream_push_token(s, tok);
+
+ return res;
+error:
+ isl_token_free(tok);
+ return isl_multi_pw_aff_free(res);
+}
+
+/* Read a tuple and represent it as an isl_multi_pw_aff. See tuple_alloc.
+ */
+static __isl_give isl_multi_pw_aff *read_tuple(struct isl_stream *s,
+ struct vars *v, int rational, int comma)
+{
+ struct isl_token *tok;
+ char *name = NULL;
+ isl_multi_pw_aff *res = NULL;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ goto error;
+ if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) {
+ name = strdup(tok->u.s);
+ isl_token_free(tok);
+ if (!name)
+ goto error;
+ } else
+ isl_stream_push_token(s, tok);
+ if (isl_stream_eat(s, '['))
+ goto error;
+ if (next_is_tuple(s)) {
+ isl_multi_pw_aff *out;
+ int n;
+ res = read_tuple(s, v, rational, comma);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ out = read_tuple(s, v, rational, comma);
+ n = isl_multi_pw_aff_dim(out, isl_dim_out);
+ res = isl_multi_pw_aff_add_dims(res, isl_dim_in, n);
+ res = isl_multi_pw_aff_range_product(res, out);
+ } else
+ res = read_tuple_var_list(s, v, rational, comma);
+ if (isl_stream_eat(s, ']'))
+ goto error;
+
+ if (name) {
+ res = isl_multi_pw_aff_set_tuple_name(res, isl_dim_out, name);
+ free(name);
+ }
+
+ return res;
+error:
+ free(name);
+ return isl_multi_pw_aff_free(res);
+}
+
+/* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map".
+ * We first create the appropriate space in "map" based on the range
+ * space of this isl_multi_pw_aff. Then, we add equalities based
+ * on the affine expressions. These live in an anonymous space,
+ * however, so we first need to reset the space to that of "map".
+ */
+static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple,
+ __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+ int rational)
+{
+ int i, n;
+ isl_ctx *ctx;
+ isl_space *space = NULL;
+
+ if (!map || !tuple)
+ goto error;
+ ctx = isl_multi_pw_aff_get_ctx(tuple);
+ n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ if (!space)
+ goto error;
+
+ if (type == isl_dim_param) {
+ if (isl_space_has_tuple_name(space, isl_dim_set) ||
+ isl_space_is_wrapping(space)) {
+ isl_die(ctx, isl_error_invalid,
+ "parameter tuples cannot be named or nested",
+ goto error);
+ }
+ map = isl_map_add_dims(map, type, n);
+ for (i = 0; i < n; ++i) {
+ isl_id *id;
+ if (!isl_space_has_dim_name(space, isl_dim_set, i))
+ isl_die(ctx, isl_error_invalid,
+ "parameters must be named",
+ goto error);
+ id = isl_space_get_dim_id(space, isl_dim_set, i);
+ map = isl_map_set_dim_id(map, isl_dim_param, i, id);
+ }
+ } else if (type == isl_dim_in) {
+ isl_set *set;
+
+ set = isl_set_universe(isl_space_copy(space));
+ if (rational)
+ set = isl_set_set_rational(set);
+ set = isl_set_intersect_params(set, isl_map_params(map));
+ map = isl_map_from_domain(set);
+ } else {
+ isl_set *set;
+
+ set = isl_set_universe(isl_space_copy(space));
+ if (rational)
+ set = isl_set_set_rational(set);
+ map = isl_map_from_domain_and_range(isl_map_domain(map), set);
+ }
+
+ for (i = 0; i < n; ++i) {
+ isl_pw_aff *pa;
+ isl_space *space;
+ isl_aff *aff;
+ isl_set *set;
+ isl_map *map_i;
+
+ pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+ space = isl_pw_aff_get_domain_space(pa);
+ aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+ aff = isl_aff_add_coefficient_si(aff,
+ isl_dim_in, v->n - n + i, -1);
+ pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff));
+ if (rational)
+ pa = isl_pw_aff_set_rational(pa);
+ set = isl_pw_aff_zero_set(pa);
+ map_i = isl_map_from_range(set);
+ map_i = isl_map_reset_space(map_i, isl_map_get_space(map));
+ map = isl_map_intersect(map, map_i);
+ }
+
+ isl_space_free(space);
+ isl_multi_pw_aff_free(tuple);
+ return map;
+error:
+ isl_space_free(space);
+ isl_multi_pw_aff_free(tuple);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Read a tuple from "s" and add it to "map".
+ * The tuple is initially represented as an isl_multi_pw_aff and
+ * then added to "map".
+ */
+static __isl_give isl_map *read_map_tuple(struct isl_stream *s,
+ __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+ int rational, int comma)
+{
+ isl_multi_pw_aff *tuple;
+
+ tuple = read_tuple(s, v, rational, comma);
+ if (!tuple)
+ return isl_map_free(map);
+
+ return map_from_tuple(tuple, map, type, v, rational);
+}
+
+static __isl_give isl_set *construct_constraints(
+ __isl_take isl_set *set, int type,
+ __isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right,
+ int rational)
+{
+ isl_set *cond;
+
+ left = isl_pw_aff_list_copy(left);
+ right = isl_pw_aff_list_copy(right);
+ if (rational) {
+ left = isl_pw_aff_list_set_rational(left);
+ right = isl_pw_aff_list_set_rational(right);
+ }
+ if (type == ISL_TOKEN_LE)
+ cond = isl_pw_aff_list_le_set(left, right);
+ else if (type == ISL_TOKEN_GE)
+ cond = isl_pw_aff_list_ge_set(left, right);
+ else if (type == ISL_TOKEN_LT)
+ cond = isl_pw_aff_list_lt_set(left, right);
+ else if (type == ISL_TOKEN_GT)
+ cond = isl_pw_aff_list_gt_set(left, right);
+ else if (type == ISL_TOKEN_NE)
+ cond = isl_pw_aff_list_ne_set(left, right);
+ else
+ cond = isl_pw_aff_list_eq_set(left, right);
+
+ return isl_set_intersect(set, cond);
+}
+
+static __isl_give isl_map *add_constraint(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ struct isl_token *tok = NULL;
+ isl_pw_aff_list *list1 = NULL, *list2 = NULL;
+ isl_set *set;
+
+ set = isl_map_wrap(map);
+ list1 = accept_affine_list(s, isl_set_get_space(set), v);
+ if (!list1)
+ goto error;
+ tok = isl_stream_next_token(s);
+ if (!is_comparator(tok)) {
+ isl_stream_error(s, tok, "missing operator");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ tok = NULL;
+ goto error;
+ }
+ for (;;) {
+ list2 = accept_affine_list(s, isl_set_get_space(set), v);
+ if (!list2)
+ goto error;
+
+ set = construct_constraints(set, tok->type, list1, list2,
+ rational);
+ isl_token_free(tok);
+ isl_pw_aff_list_free(list1);
+ list1 = list2;
+
+ tok = isl_stream_next_token(s);
+ if (!is_comparator(tok)) {
+ if (tok)
+ isl_stream_push_token(s, tok);
+ break;
+ }
+ }
+ isl_pw_aff_list_free(list1);
+
+ return isl_set_unwrap(set);
+error:
+ if (tok)
+ isl_token_free(tok);
+ isl_pw_aff_list_free(list1);
+ isl_pw_aff_list_free(list2);
+ isl_set_free(set);
+ return NULL;
+}
+
+static __isl_give isl_map *read_exists(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ int n = v->n;
+ int seen_paren = isl_stream_eat_if_available(s, '(');
+
+ map = isl_map_from_domain(isl_map_wrap(map));
+ map = read_defined_var_list(s, v, map, rational);
+
+ if (isl_stream_eat(s, ':'))
+ goto error;
+
+ map = read_formula(s, v, map, rational);
+ map = isl_set_unwrap(isl_map_domain(map));
+
+ vars_drop(v, v->n - n);
+ if (seen_paren && isl_stream_eat(s, ')'))
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Parse an expression between parentheses and push the result
+ * back on the stream.
+ *
+ * The parsed expression may be either an affine expression
+ * or a condition. The first type is pushed onto the stream
+ * as an isl_pw_aff, while the second is pushed as an isl_map.
+ *
+ * If the initial token indicates the start of a condition,
+ * we parse it as such.
+ * Otherwise, we first parse an affine expression and push
+ * that onto the stream. If the affine expression covers the
+ * entire expression between parentheses, we return.
+ * Otherwise, we assume that the affine expression is the
+ * start of a condition and continue parsing.
+ */
+static int resolve_paren_expr(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ struct isl_token *tok, *tok2;
+ int line, col;
+ isl_pw_aff *pwaff;
+
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != '(')
+ goto error;
+
+ if (isl_stream_next_token_is(s, '('))
+ if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+ goto error;
+
+ if (isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) ||
+ isl_stream_next_token_is(s, ISL_TOKEN_NOT) ||
+ isl_stream_next_token_is(s, ISL_TOKEN_TRUE) ||
+ isl_stream_next_token_is(s, ISL_TOKEN_FALSE) ||
+ isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+ map = read_formula(s, v, map, rational);
+ if (isl_stream_eat(s, ')'))
+ goto error;
+ tok->type = ISL_TOKEN_MAP;
+ tok->u.map = map;
+ isl_stream_push_token(s, tok);
+ return 0;
+ }
+
+ tok2 = isl_stream_next_token(s);
+ if (!tok2)
+ goto error;
+ line = tok2->line;
+ col = tok2->col;
+ isl_stream_push_token(s, tok2);
+
+ pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v);
+ if (!pwaff)
+ goto error;
+
+ tok2 = isl_token_new(s->ctx, line, col, 0);
+ if (!tok2)
+ goto error2;
+ tok2->type = ISL_TOKEN_AFF;
+ tok2->u.pwaff = pwaff;
+
+ if (isl_stream_eat_if_available(s, ')')) {
+ isl_stream_push_token(s, tok2);
+ isl_token_free(tok);
+ isl_map_free(map);
+ return 0;
+ }
+
+ isl_stream_push_token(s, tok2);
+
+ map = read_formula(s, v, map, rational);
+ if (isl_stream_eat(s, ')'))
+ goto error;
+
+ tok->type = ISL_TOKEN_MAP;
+ tok->u.map = map;
+ isl_stream_push_token(s, tok);
+
+ return 0;
+error2:
+ isl_pw_aff_free(pwaff);
+error:
+ isl_token_free(tok);
+ isl_map_free(map);
+ return -1;
+}
+
+static __isl_give isl_map *read_conjunct(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ if (isl_stream_next_token_is(s, '('))
+ if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+ goto error;
+
+ if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+ struct isl_token *tok;
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ goto error;
+ isl_map_free(map);
+ map = isl_map_copy(tok->u.map);
+ isl_token_free(tok);
+ return map;
+ }
+
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
+ return read_exists(s, v, map, rational);
+
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
+ return map;
+
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
+ isl_space *dim = isl_map_get_space(map);
+ isl_map_free(map);
+ return isl_map_empty(dim);
+ }
+
+ return add_constraint(s, v, map, rational);
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+static __isl_give isl_map *read_conjuncts(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ isl_map *res;
+ int negate;
+
+ negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+ res = read_conjunct(s, v, isl_map_copy(map), rational);
+ if (negate)
+ res = isl_map_subtract(isl_map_copy(map), res);
+
+ while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
+ isl_map *res_i;
+
+ negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+ res_i = read_conjunct(s, v, isl_map_copy(map), rational);
+ if (negate)
+ res = isl_map_subtract(res, res_i);
+ else
+ res = isl_map_intersect(res, res_i);
+ }
+
+ isl_map_free(map);
+ return res;
+}
+
+static struct isl_map *read_disjuncts(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ isl_map *res;
+
+ if (isl_stream_next_token_is(s, '}')) {
+ isl_space *dim = isl_map_get_space(map);
+ isl_map_free(map);
+ return isl_map_universe(dim);
+ }
+
+ res = read_conjuncts(s, v, isl_map_copy(map), rational);
+ while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
+ isl_map *res_i;
+
+ res_i = read_conjuncts(s, v, isl_map_copy(map), rational);
+ res = isl_map_union(res, res_i);
+ }
+
+ isl_map_free(map);
+ return res;
+}
+
+/* Read a first order formula from "s", add the corresponding
+ * constraints to "map" and return the result.
+ *
+ * In particular, read a formula of the form
+ *
+ * a
+ *
+ * or
+ *
+ * a implies b
+ *
+ * where a and b are disjunctions.
+ *
+ * In the first case, map is replaced by
+ *
+ * map \cap { [..] : a }
+ *
+ * In the second case, it is replaced by
+ *
+ * (map \setminus { [..] : a}) \cup (map \cap { [..] : b })
+ */
+static __isl_give isl_map *read_formula(struct isl_stream *s,
+ struct vars *v, __isl_take isl_map *map, int rational)
+{
+ isl_map *res;
+
+ res = read_disjuncts(s, v, isl_map_copy(map), rational);
+
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) {
+ isl_map *res2;
+
+ res = isl_map_subtract(isl_map_copy(map), res);
+ res2 = read_disjuncts(s, v, map, rational);
+ res = isl_map_union(res, res2);
+ } else
+ isl_map_free(map);
+
+ return res;
+}
+
+static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
+{
+ if (pos < isl_basic_map_dim(bmap, isl_dim_out))
+ return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+ isl_basic_map_dim(bmap, isl_dim_in) + pos;
+ pos -= isl_basic_map_dim(bmap, isl_dim_out);
+
+ if (pos < isl_basic_map_dim(bmap, isl_dim_in))
+ return 1 + isl_basic_map_dim(bmap, isl_dim_param) + pos;
+ pos -= isl_basic_map_dim(bmap, isl_dim_in);
+
+ if (pos < isl_basic_map_dim(bmap, isl_dim_div))
+ return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+ isl_basic_map_dim(bmap, isl_dim_in) +
+ isl_basic_map_dim(bmap, isl_dim_out) + pos;
+ pos -= isl_basic_map_dim(bmap, isl_dim_div);
+
+ if (pos < isl_basic_map_dim(bmap, isl_dim_param))
+ return 1 + pos;
+
+ return 0;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib_constraint(
+ struct isl_stream *s, __isl_take isl_basic_map *bmap)
+{
+ int j;
+ struct isl_token *tok;
+ int type;
+ int k;
+ isl_int *c;
+ unsigned nparam;
+ unsigned dim;
+
+ if (!bmap)
+ return NULL;
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ dim = isl_basic_map_dim(bmap, isl_dim_out);
+
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting coefficient");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ if (!tok->on_new_line) {
+ isl_stream_error(s, tok, "coefficient should appear on new line");
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+
+ type = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ isl_assert(s->ctx, type == 0 || type == 1, goto error);
+ if (type == 0) {
+ k = isl_basic_map_alloc_equality(bmap);
+ c = bmap->eq[k];
+ } else {
+ k = isl_basic_map_alloc_inequality(bmap);
+ c = bmap->ineq[k];
+ }
+ if (k < 0)
+ goto error;
+
+ for (j = 0; j < 1 + isl_basic_map_total_dim(bmap); ++j) {
+ int pos;
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting coefficient");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ if (tok->on_new_line) {
+ isl_stream_error(s, tok,
+ "coefficient should not appear on new line");
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ pos = polylib_pos_to_isl_pos(bmap, j);
+ isl_int_set(c[pos], tok->u.v);
+ isl_token_free(tok);
+ }
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib(struct isl_stream *s)
+{
+ int i;
+ struct isl_token *tok;
+ struct isl_token *tok2;
+ int n_row, n_col;
+ int on_new_line;
+ unsigned in = 0, out, local = 0;
+ struct isl_basic_map *bmap = NULL;
+ int nparam = 0;
+
+ tok = isl_stream_next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ return NULL;
+ }
+ tok2 = isl_stream_next_token(s);
+ if (!tok2) {
+ isl_token_free(tok);
+ isl_stream_error(s, NULL, "unexpected EOF");
+ return NULL;
+ }
+ if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) {
+ isl_stream_push_token(s, tok2);
+ isl_stream_push_token(s, tok);
+ isl_stream_error(s, NULL,
+ "expecting constraint matrix dimensions");
+ return NULL;
+ }
+ n_row = isl_int_get_si(tok->u.v);
+ n_col = isl_int_get_si(tok2->u.v);
+ on_new_line = tok2->on_new_line;
+ isl_token_free(tok2);
+ isl_token_free(tok);
+ isl_assert(s->ctx, !on_new_line, return NULL);
+ isl_assert(s->ctx, n_row >= 0, return NULL);
+ isl_assert(s->ctx, n_col >= 2 + nparam, return NULL);
+ tok = isl_stream_next_token_on_same_line(s);
+ if (tok) {
+ if (tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok,
+ "expecting number of output dimensions");
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ out = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ tok = isl_stream_next_token_on_same_line(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok,
+ "expecting number of input dimensions");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ in = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ tok = isl_stream_next_token_on_same_line(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok,
+ "expecting number of existentials");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ local = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ tok = isl_stream_next_token_on_same_line(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok,
+ "expecting number of parameters");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ nparam = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+ if (n_col != 1 + out + in + local + nparam + 1) {
+ isl_stream_error(s, NULL,
+ "dimensions don't match");
+ goto error;
+ }
+ } else
+ out = n_col - 2 - nparam;
+ bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row);
+ if (!bmap)
+ return NULL;
+
+ for (i = 0; i < local; ++i) {
+ int k = isl_basic_map_alloc_div(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local);
+ }
+
+ for (i = 0; i < n_row; ++i)
+ bmap = basic_map_read_polylib_constraint(s, bmap);
+
+ tok = isl_stream_next_token_on_same_line(s);
+ if (tok) {
+ isl_stream_error(s, tok, "unexpected extra token on line");
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static struct isl_map *map_read_polylib(struct isl_stream *s)
+{
+ struct isl_token *tok;
+ struct isl_token *tok2;
+ int i, n;
+ struct isl_map *map;
+
+ tok = isl_stream_next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ return NULL;
+ }
+ tok2 = isl_stream_next_token_on_same_line(s);
+ if (tok2 && tok2->type == ISL_TOKEN_VALUE) {
+ isl_stream_push_token(s, tok2);
+ isl_stream_push_token(s, tok);
+ return isl_map_from_basic_map(basic_map_read_polylib(s));
+ }
+ if (tok2) {
+ isl_stream_error(s, tok2, "unexpected token");
+ isl_stream_push_token(s, tok2);
+ isl_stream_push_token(s, tok);
+ return NULL;
+ }
+ n = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ isl_assert(s->ctx, n >= 1, return NULL);
+
+ map = isl_map_from_basic_map(basic_map_read_polylib(s));
+
+ for (i = 1; map && i < n; ++i)
+ map = isl_map_union(map,
+ isl_map_from_basic_map(basic_map_read_polylib(s)));
+
+ return map;
+}
+
+static int optional_power(struct isl_stream *s)
+{
+ int pow;
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return 1;
+ if (tok->type != '^') {
+ isl_stream_push_token(s, tok);
+ return 1;
+ }
+ isl_token_free(tok);
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting exponent");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ return 1;
+ }
+ pow = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+ return pow;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s,
+ __isl_keep isl_map *map, struct vars *v);
+
+static __isl_give isl_pw_qpolynomial *read_factor(struct isl_stream *s,
+ __isl_keep isl_map *map, struct vars *v)
+{
+ isl_pw_qpolynomial *pwqp;
+ struct isl_token *tok;
+
+ tok = next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ return NULL;
+ }
+ if (tok->type == '(') {
+ int pow;
+
+ isl_token_free(tok);
+ pwqp = read_term(s, map, v);
+ if (!pwqp)
+ return NULL;
+ if (isl_stream_eat(s, ')'))
+ goto error;
+ pow = optional_power(s);
+ pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+ } else if (tok->type == ISL_TOKEN_VALUE) {
+ struct isl_token *tok2;
+ isl_qpolynomial *qp;
+
+ tok2 = isl_stream_next_token(s);
+ if (tok2 && tok2->type == '/') {
+ isl_token_free(tok2);
+ tok2 = next_token(s);
+ if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok2, "expected denominator");
+ isl_token_free(tok);
+ isl_token_free(tok2);
+ return NULL;
+ }
+ qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map),
+ tok->u.v, tok2->u.v);
+ isl_token_free(tok2);
+ } else {
+ isl_stream_push_token(s, tok2);
+ qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map),
+ tok->u.v);
+ }
+ isl_token_free(tok);
+ pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+ } else if (tok->type == ISL_TOKEN_INFTY) {
+ isl_qpolynomial *qp;
+ isl_token_free(tok);
+ qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map));
+ pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+ } else if (tok->type == ISL_TOKEN_NAN) {
+ isl_qpolynomial *qp;
+ isl_token_free(tok);
+ qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map));
+ pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+ } else if (tok->type == ISL_TOKEN_IDENT) {
+ int n = v->n;
+ int pos = vars_pos(v, tok->u.s, -1);
+ int pow;
+ isl_qpolynomial *qp;
+ if (pos < 0) {
+ isl_token_free(tok);
+ return NULL;
+ }
+ if (pos >= n) {
+ vars_drop(v, v->n - n);
+ isl_stream_error(s, tok, "unknown identifier");
+ isl_token_free(tok);
+ return NULL;
+ }
+ isl_token_free(tok);
+ pow = optional_power(s);
+ qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow);
+ pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+ } else if (is_start_of_div(tok)) {
+ isl_pw_aff *pwaff;
+ int pow;
+
+ isl_stream_push_token(s, tok);
+ pwaff = accept_div(s, isl_map_get_space(map), v);
+ pow = optional_power(s);
+ pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff);
+ pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+ } else if (tok->type == '-') {
+ isl_token_free(tok);
+ pwqp = read_factor(s, map, v);
+ pwqp = isl_pw_qpolynomial_neg(pwqp);
+ } else {
+ isl_stream_error(s, tok, "unexpected isl_token");
+ isl_stream_push_token(s, tok);
+ return NULL;
+ }
+
+ if (isl_stream_eat_if_available(s, '*') ||
+ isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
+ isl_pw_qpolynomial *pwqp2;
+
+ pwqp2 = read_factor(s, map, v);
+ pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2);
+ }
+
+ return pwqp;
+error:
+ isl_pw_qpolynomial_free(pwqp);
+ return NULL;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(struct isl_stream *s,
+ __isl_keep isl_map *map, struct vars *v)
+{
+ struct isl_token *tok;
+ isl_pw_qpolynomial *pwqp;
+
+ pwqp = read_factor(s, map, v);
+
+ for (;;) {
+ tok = next_token(s);
+ if (!tok)
+ return pwqp;
+
+ if (tok->type == '+') {
+ isl_pw_qpolynomial *pwqp2;
+
+ isl_token_free(tok);
+ pwqp2 = read_factor(s, map, v);
+ pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
+ } else if (tok->type == '-') {
+ isl_pw_qpolynomial *pwqp2;
+
+ isl_token_free(tok);
+ pwqp2 = read_factor(s, map, v);
+ pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2);
+ } else if (tok->type == ISL_TOKEN_VALUE &&
+ isl_int_is_neg(tok->u.v)) {
+ isl_pw_qpolynomial *pwqp2;
+
+ isl_stream_push_token(s, tok);
+ pwqp2 = read_factor(s, map, v);
+ pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
+ } else {
+ isl_stream_push_token(s, tok);
+ break;
+ }
+ }
+
+ return pwqp;
+}
+
+static __isl_give isl_map *read_optional_formula(struct isl_stream *s,
+ __isl_take isl_map *map, struct vars *v, int rational)
+{
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok->type == ':' ||
+ (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
+ isl_token_free(tok);
+ map = read_formula(s, v, map, rational);
+ } else
+ isl_stream_push_token(s, tok);
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+static struct isl_obj obj_read_poly(struct isl_stream *s,
+ __isl_take isl_map *map, struct vars *v, int n)
+{
+ struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL };
+ isl_pw_qpolynomial *pwqp;
+ struct isl_set *set;
+
+ pwqp = read_term(s, map, v);
+ map = read_optional_formula(s, map, v, 0);
+ set = isl_map_range(map);
+
+ pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set);
+
+ vars_drop(v, v->n - n);
+
+ obj.v = pwqp;
+ return obj;
+}
+
+static struct isl_obj obj_read_poly_or_fold(struct isl_stream *s,
+ __isl_take isl_set *set, struct vars *v, int n)
+{
+ struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL };
+ isl_pw_qpolynomial *pwqp;
+ isl_pw_qpolynomial_fold *pwf = NULL;
+
+ if (!isl_stream_eat_if_available(s, ISL_TOKEN_MAX))
+ return obj_read_poly(s, set, v, n);
+
+ if (isl_stream_eat(s, '('))
+ goto error;
+
+ pwqp = read_term(s, set, v);
+ pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, pwqp);
+
+ while (isl_stream_eat_if_available(s, ',')) {
+ isl_pw_qpolynomial_fold *pwf_i;
+ pwqp = read_term(s, set, v);
+ pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max,
+ pwqp);
+ pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i);
+ }
+
+ if (isl_stream_eat(s, ')'))
+ goto error;
+
+ set = read_optional_formula(s, set, v, 0);
+ pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set);
+
+ vars_drop(v, v->n - n);
+
+ obj.v = pwf;
+ return obj;
+error:
+ isl_set_free(set);
+ isl_pw_qpolynomial_fold_free(pwf);
+ obj.type = isl_obj_none;
+ return obj;
+}
+
+static int is_rational(struct isl_stream *s)
+{
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return 0;
+ if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
+ isl_token_free(tok);
+ isl_stream_eat(s, ':');
+ return 1;
+ }
+
+ isl_stream_push_token(s, tok);
+
+ return 0;
+}
+
+static struct isl_obj obj_read_body(struct isl_stream *s,
+ __isl_take isl_map *map, struct vars *v)
+{
+ struct isl_token *tok;
+ struct isl_obj obj = { isl_obj_set, NULL };
+ int n = v->n;
+ int rational;
+
+ rational = is_rational(s);
+ if (rational)
+ map = isl_map_set_rational(map);
+
+ if (isl_stream_next_token_is(s, ':')) {
+ obj.type = isl_obj_set;
+ obj.v = read_optional_formula(s, map, v, rational);
+ return obj;
+ }
+
+ if (!next_is_tuple(s))
+ return obj_read_poly_or_fold(s, map, v, n);
+
+ map = read_map_tuple(s, map, isl_dim_in, v, rational, 0);
+ if (!map)
+ goto error;
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ goto error;
+ if (tok->type == ISL_TOKEN_TO) {
+ obj.type = isl_obj_map;
+ isl_token_free(tok);
+ if (!next_is_tuple(s)) {
+ isl_set *set = isl_map_domain(map);
+ return obj_read_poly_or_fold(s, set, v, n);
+ }
+ map = read_map_tuple(s, map, isl_dim_out, v, rational, 0);
+ if (!map)
+ goto error;
+ } else {
+ map = isl_map_domain(map);
+ isl_stream_push_token(s, tok);
+ }
+
+ map = read_optional_formula(s, map, v, rational);
+
+ vars_drop(v, v->n - n);
+
+ obj.v = map;
+ return obj;
+error:
+ isl_map_free(map);
+ obj.type = isl_obj_none;
+ return obj;
+}
+
+static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj)
+{
+ if (obj.type == isl_obj_map) {
+ obj.v = isl_union_map_from_map(obj.v);
+ obj.type = isl_obj_union_map;
+ } else if (obj.type == isl_obj_set) {
+ obj.v = isl_union_set_from_set(obj.v);
+ obj.type = isl_obj_union_set;
+ } else if (obj.type == isl_obj_pw_qpolynomial) {
+ obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+ obj.type = isl_obj_union_pw_qpolynomial;
+ } else if (obj.type == isl_obj_pw_qpolynomial_fold) {
+ obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
+ obj.type = isl_obj_union_pw_qpolynomial_fold;
+ } else
+ isl_assert(ctx, 0, goto error);
+ return obj;
+error:
+ obj.type->free(obj.v);
+ obj.type = isl_obj_none;
+ return obj;
+}
+
+static struct isl_obj obj_add(struct isl_ctx *ctx,
+ struct isl_obj obj1, struct isl_obj obj2)
+{
+ if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set)
+ obj1 = to_union(ctx, obj1);
+ if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set)
+ obj2 = to_union(ctx, obj2);
+ if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map)
+ obj1 = to_union(ctx, obj1);
+ if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map)
+ obj2 = to_union(ctx, obj2);
+ if (obj1.type == isl_obj_pw_qpolynomial &&
+ obj2.type == isl_obj_union_pw_qpolynomial)
+ obj1 = to_union(ctx, obj1);
+ if (obj1.type == isl_obj_union_pw_qpolynomial &&
+ obj2.type == isl_obj_pw_qpolynomial)
+ obj2 = to_union(ctx, obj2);
+ if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+ obj2.type == isl_obj_union_pw_qpolynomial_fold)
+ obj1 = to_union(ctx, obj1);
+ if (obj1.type == isl_obj_union_pw_qpolynomial_fold &&
+ obj2.type == isl_obj_pw_qpolynomial_fold)
+ obj2 = to_union(ctx, obj2);
+ isl_assert(ctx, obj1.type == obj2.type, goto error);
+ if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) {
+ obj1 = to_union(ctx, obj1);
+ obj2 = to_union(ctx, obj2);
+ }
+ if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) {
+ obj1 = to_union(ctx, obj1);
+ obj2 = to_union(ctx, obj2);
+ }
+ if (obj1.type == isl_obj_pw_qpolynomial &&
+ !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) {
+ obj1 = to_union(ctx, obj1);
+ obj2 = to_union(ctx, obj2);
+ }
+ if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+ !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) {
+ obj1 = to_union(ctx, obj1);
+ obj2 = to_union(ctx, obj2);
+ }
+ obj1.v = obj1.type->add(obj1.v, obj2.v);
+ return obj1;
+error:
+ obj1.type->free(obj1.v);
+ obj2.type->free(obj2.v);
+ obj1.type = isl_obj_none;
+ obj1.v = NULL;
+ return obj1;
+}
+
+static struct isl_obj obj_read(struct isl_stream *s)
+{
+ isl_map *map = NULL;
+ struct isl_token *tok;
+ struct vars *v = NULL;
+ struct isl_obj obj = { isl_obj_set, NULL };
+
+ tok = next_token(s);
+ if (!tok) {
+ isl_stream_error(s, NULL, "unexpected EOF");
+ goto error;
+ }
+ if (tok->type == ISL_TOKEN_VALUE) {
+ struct isl_token *tok2;
+ struct isl_map *map;
+
+ tok2 = isl_stream_next_token(s);
+ if (!tok2 || tok2->type != ISL_TOKEN_VALUE ||
+ isl_int_is_neg(tok2->u.v)) {
+ if (tok2)
+ isl_stream_push_token(s, tok2);
+ obj.type = isl_obj_val;
+ obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+ isl_token_free(tok);
+ return obj;
+ }
+ isl_stream_push_token(s, tok2);
+ isl_stream_push_token(s, tok);
+ map = map_read_polylib(s);
+ if (!map)
+ goto error;
+ if (isl_map_may_be_set(map))
+ obj.v = isl_map_range(map);
+ else {
+ obj.type = isl_obj_map;
+ obj.v = map;
+ }
+ return obj;
+ }
+ v = vars_new(s->ctx);
+ if (!v) {
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ map = isl_map_universe(isl_space_params_alloc(s->ctx, 0));
+ if (tok->type == '[') {
+ isl_stream_push_token(s, tok);
+ map = read_map_tuple(s, map, isl_dim_param, v, 0, 0);
+ if (!map)
+ goto error;
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_TO) {
+ isl_stream_error(s, tok, "expecting '->'");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ isl_token_free(tok);
+ tok = isl_stream_next_token(s);
+ }
+ if (!tok || tok->type != '{') {
+ isl_stream_error(s, tok, "expecting '{'");
+ if (tok)
+ isl_stream_push_token(s, tok);
+ goto error;
+ }
+ isl_token_free(tok);
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ ;
+ else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) {
+ isl_token_free(tok);
+ if (isl_stream_eat(s, '='))
+ goto error;
+ map = read_map_tuple(s, map, isl_dim_param, v, 0, 1);
+ if (!map)
+ goto error;
+ } else if (tok->type == '}') {
+ obj.type = isl_obj_union_set;
+ obj.v = isl_union_set_empty(isl_map_get_space(map));
+ isl_token_free(tok);
+ goto done;
+ } else
+ isl_stream_push_token(s, tok);
+
+ for (;;) {
+ struct isl_obj o;
+ tok = NULL;
+ o = obj_read_body(s, isl_map_copy(map), v);
+ if (o.type == isl_obj_none || !o.v)
+ goto error;
+ if (!obj.v)
+ obj = o;
+ else {
+ obj = obj_add(s->ctx, obj, o);
+ if (obj.type == isl_obj_none || !obj.v)
+ goto error;
+ }
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ';')
+ break;
+ isl_token_free(tok);
+ if (isl_stream_next_token_is(s, '}')) {
+ tok = isl_stream_next_token(s);
+ break;
+ }
+ }
+
+ if (tok && tok->type == '}') {
+ isl_token_free(tok);
+ } else {
+ isl_stream_error(s, tok, "unexpected isl_token");
+ if (tok)
+ isl_token_free(tok);
+ goto error;
+ }
+done:
+ vars_free(v);
+ isl_map_free(map);
+
+ return obj;
+error:
+ isl_map_free(map);
+ obj.type->free(obj.v);
+ if (v)
+ vars_free(v);
+ obj.v = NULL;
+ return obj;
+}
+
+struct isl_obj isl_stream_read_obj(struct isl_stream *s)
+{
+ return obj_read(s);
+}
+
+__isl_give isl_map *isl_stream_read_map(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.v)
+ isl_assert(s->ctx, obj.type == isl_obj_map ||
+ obj.type == isl_obj_set, goto error);
+
+ if (obj.type == isl_obj_set)
+ obj.v = isl_map_from_range(obj.v);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_set *isl_stream_read_set(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.v) {
+ if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) {
+ obj.v = isl_map_range(obj.v);
+ obj.type = isl_obj_set;
+ }
+ isl_assert(s->ctx, obj.type == isl_obj_set, goto error);
+ }
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_union_map *isl_stream_read_union_map(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.type == isl_obj_map) {
+ obj.type = isl_obj_union_map;
+ obj.v = isl_union_map_from_map(obj.v);
+ }
+ if (obj.type == isl_obj_set) {
+ obj.type = isl_obj_union_set;
+ obj.v = isl_union_set_from_set(obj.v);
+ }
+ if (obj.v && obj.type == isl_obj_union_set &&
+ isl_union_set_is_empty(obj.v))
+ obj.type = isl_obj_union_map;
+ if (obj.v && obj.type != isl_obj_union_map)
+ isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_union_set *isl_stream_read_union_set(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.type == isl_obj_set) {
+ obj.type = isl_obj_union_set;
+ obj.v = isl_union_set_from_set(obj.v);
+ }
+ if (obj.v)
+ isl_assert(s->ctx, obj.type == isl_obj_union_set, goto error);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read(struct isl_stream *s)
+{
+ struct isl_obj obj;
+ struct isl_map *map;
+ struct isl_basic_map *bmap;
+
+ obj = obj_read(s);
+ if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set))
+ isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map",
+ goto error);
+ map = obj.v;
+ if (!map)
+ return NULL;
+
+ if (map->n > 1)
+ isl_die(s->ctx, isl_error_invalid,
+ "set or map description involves "
+ "more than one disjunct", goto error);
+
+ if (map->n == 0)
+ bmap = isl_basic_map_empty_like_map(map);
+ else
+ bmap = isl_basic_map_copy(map->p[0]);
+
+ isl_map_free(map);
+
+ return bmap;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+static __isl_give isl_basic_set *basic_set_read(struct isl_stream *s)
+{
+ isl_basic_map *bmap;
+ bmap = basic_map_read(s);
+ if (!bmap)
+ return NULL;
+ if (!isl_basic_map_may_be_set(bmap))
+ isl_die(s->ctx, isl_error_invalid,
+ "input is not a set", goto error);
+ return isl_basic_map_range(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ struct isl_basic_map *bmap;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ bmap = basic_map_read(s);
+ isl_stream_free(s);
+ return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ isl_basic_set *bset;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ bset = basic_set_read(s);
+ isl_stream_free(s);
+ return bset;
+}
+
+struct isl_basic_map *isl_basic_map_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ struct isl_basic_map *bmap;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ bmap = basic_map_read(s);
+ isl_stream_free(s);
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ isl_basic_set *bset;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ bset = basic_set_read(s);
+ isl_stream_free(s);
+ return bset;
+}
+
+__isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx,
+ FILE *input)
+{
+ struct isl_map *map;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ map = isl_stream_read_map(s);
+ isl_stream_free(s);
+ return map;
+}
+
+__isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ struct isl_map *map;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ map = isl_stream_read_map(s);
+ isl_stream_free(s);
+ return map;
+}
+
+__isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx,
+ FILE *input)
+{
+ isl_set *set;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ set = isl_stream_read_set(s);
+ isl_stream_free(s);
+ return set;
+}
+
+struct isl_set *isl_set_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ isl_set *set;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ set = isl_stream_read_set(s);
+ isl_stream_free(s);
+ return set;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ isl_union_map *umap;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ umap = isl_stream_read_union_map(s);
+ isl_stream_free(s);
+ return umap;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ isl_union_map *umap;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ umap = isl_stream_read_union_map(s);
+ isl_stream_free(s);
+ return umap;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ isl_union_set *uset;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ uset = isl_stream_read_union_set(s);
+ isl_stream_free(s);
+ return uset;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
+ const char *str)
+{
+ isl_union_set *uset;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ uset = isl_stream_read_union_set(s);
+ isl_stream_free(s);
+ return uset;
+}
+
+static __isl_give isl_vec *isl_vec_read_polylib(struct isl_stream *s)
+{
+ struct isl_vec *vec = NULL;
+ struct isl_token *tok;
+ unsigned size;
+ int j;
+
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting vector length");
+ goto error;
+ }
+
+ size = isl_int_get_si(tok->u.v);
+ isl_token_free(tok);
+
+ vec = isl_vec_alloc(s->ctx, size);
+
+ for (j = 0; j < size; ++j) {
+ tok = isl_stream_next_token(s);
+ if (!tok || tok->type != ISL_TOKEN_VALUE) {
+ isl_stream_error(s, tok, "expecting constant value");
+ goto error;
+ }
+ isl_int_set(vec->el[j], tok->u.v);
+ isl_token_free(tok);
+ }
+
+ return vec;
+error:
+ isl_token_free(tok);
+ isl_vec_free(vec);
+ return NULL;
+}
+
+static __isl_give isl_vec *vec_read(struct isl_stream *s)
+{
+ return isl_vec_read_polylib(s);
+}
+
+__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
+{
+ isl_vec *v;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ v = vec_read(s);
+ isl_stream_free(s);
+ return v;
+}
+
+__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
+ struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.v)
+ isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial,
+ goto error);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_pw_qpolynomial *pwqp;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ pwqp = isl_stream_read_pw_qpolynomial(s);
+ isl_stream_free(s);
+ return pwqp;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
+ FILE *input)
+{
+ isl_pw_qpolynomial *pwqp;
+ struct isl_stream *s = isl_stream_new_file(ctx, input);
+ if (!s)
+ return NULL;
+ pwqp = isl_stream_read_pw_qpolynomial(s);
+ isl_stream_free(s);
+ return pwqp;
+}
+
+/* Is the next token an identifer not in "v"?
+ */
+static int next_is_fresh_ident(struct isl_stream *s, struct vars *v)
+{
+ int n = v->n;
+ int fresh;
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (!tok)
+ return 0;
+ fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
+ isl_stream_push_token(s, tok);
+
+ vars_drop(v, v->n - n);
+
+ return fresh;
+}
+
+/* First read the domain of the affine expression, which may be
+ * a parameter space or a set.
+ * The tricky part is that we don't know if the domain is a set or not,
+ * so when we are trying to read the domain, we may actually be reading
+ * the affine expression itself (defined on a parameter domains)
+ * If the tuple we are reading is named, we assume it's the domain.
+ * Also, if inside the tuple, the first thing we find is a nested tuple
+ * or a new identifier, we again assume it's the domain.
+ * Otherwise, we assume we are reading an affine expression.
+ */
+static __isl_give isl_set *read_aff_domain(struct isl_stream *s,
+ __isl_take isl_set *dom, struct vars *v)
+{
+ struct isl_token *tok;
+
+ tok = isl_stream_next_token(s);
+ if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
+ isl_stream_push_token(s, tok);
+ return read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+ }
+ if (!tok || tok->type != '[') {
+ isl_stream_error(s, tok, "expecting '['");
+ goto error;
+ }
+ if (next_is_tuple(s) || next_is_fresh_ident(s, v)) {
+ isl_stream_push_token(s, tok);
+ dom = read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+ } else
+ isl_stream_push_token(s, tok);
+
+ return dom;
+error:
+ if (tok)
+ isl_stream_push_token(s, tok);
+ isl_set_free(dom);
+ return NULL;
+}
+
+/* Read an affine expression from "s".
+ */
+__isl_give isl_aff *isl_stream_read_aff(struct isl_stream *s)
+{
+ isl_aff *aff;
+ isl_multi_aff *ma;
+
+ ma = isl_stream_read_multi_aff(s);
+ if (!ma)
+ return NULL;
+ if (isl_multi_aff_dim(ma, isl_dim_out) != 1)
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting single affine expression",
+ goto error);
+
+ aff = isl_multi_aff_get_aff(ma, 0);
+ isl_multi_aff_free(ma);
+ return aff;
+error:
+ isl_multi_aff_free(ma);
+ return NULL;
+}
+
+/* Read a piecewise affine expression from "s" with domain (space) "dom".
+ */
+static __isl_give isl_pw_aff *read_pw_aff_with_dom(struct isl_stream *s,
+ __isl_take isl_set *dom, struct vars *v)
+{
+ isl_pw_aff *pwaff = NULL;
+
+ if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+
+ if (isl_stream_eat(s, '['))
+ goto error;
+
+ pwaff = accept_affine(s, isl_set_get_space(dom), v);
+
+ if (isl_stream_eat(s, ']'))
+ goto error;
+
+ dom = read_optional_formula(s, dom, v, 0);
+ pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
+
+ return pwaff;
+error:
+ isl_set_free(dom);
+ isl_pw_aff_free(pwaff);
+ return NULL;
+}
+
+__isl_give isl_pw_aff *isl_stream_read_pw_aff(struct isl_stream *s)
+{
+ struct vars *v;
+ isl_set *dom = NULL;
+ isl_set *aff_dom;
+ isl_pw_aff *pa = NULL;
+ int n;
+
+ v = vars_new(s->ctx);
+ if (!v)
+ return NULL;
+
+ dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+ if (next_is_tuple(s)) {
+ dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ }
+ if (isl_stream_eat(s, '{'))
+ goto error;
+
+ n = v->n;
+ aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+ pa = read_pw_aff_with_dom(s, aff_dom, v);
+ vars_drop(v, v->n - n);
+
+ while (isl_stream_eat_if_available(s, ';')) {
+ isl_pw_aff *pa_i;
+
+ n = v->n;
+ aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+ pa_i = read_pw_aff_with_dom(s, aff_dom, v);
+ vars_drop(v, v->n - n);
+
+ pa = isl_pw_aff_union_add(pa, pa_i);
+ }
+
+ if (isl_stream_eat(s, '}'))
+ goto error;
+
+ vars_free(v);
+ isl_set_free(dom);
+ return pa;
+error:
+ vars_free(v);
+ isl_set_free(dom);
+ isl_pw_aff_free(pa);
+ return NULL;
+}
+
+__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+ isl_aff *aff;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ aff = isl_stream_read_aff(s);
+ isl_stream_free(s);
+ return aff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+ isl_pw_aff *pa;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ pa = isl_stream_read_pw_aff(s);
+ isl_stream_free(s);
+ return pa;
+}
+
+/* Read an isl_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_pw_multi_aff.
+ * It would be more efficient if we were to construct the isl_pw_multi_aff
+ * directly.
+ */
+__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (!obj.v)
+ return NULL;
+
+ if (obj.type == isl_obj_map)
+ return isl_pw_multi_aff_from_map(obj.v);
+ if (obj.type == isl_obj_set)
+ return isl_pw_multi_aff_from_set(obj.v);
+
+ obj.type->free(obj.v);
+ isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+ return NULL);
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_pw_multi_aff *pma;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ pma = isl_stream_read_pw_multi_aff(s);
+ isl_stream_free(s);
+ return pma;
+}
+
+/* Read an isl_union_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_union_pw_multi_aff.
+ * It would be more efficient if we were to construct
+ * the isl_union_pw_multi_aff directly.
+ */
+__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
+ struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (!obj.v)
+ return NULL;
+
+ if (obj.type == isl_obj_map || obj.type == isl_obj_set)
+ obj = to_union(s->ctx, obj);
+ if (obj.type == isl_obj_union_map)
+ return isl_union_pw_multi_aff_from_union_map(obj.v);
+ if (obj.type == isl_obj_union_set)
+ return isl_union_pw_multi_aff_from_union_set(obj.v);
+
+ obj.type->free(obj.v);
+ isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+ return NULL);
+}
+
+/* Read an isl_union_pw_multi_aff from "str".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+ isl_ctx *ctx, const char *str)
+{
+ isl_union_pw_multi_aff *upma;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ upma = isl_stream_read_union_pw_multi_aff(s);
+ isl_stream_free(s);
+ return upma;
+}
+
+/* Assuming "pa" represents a single affine expression defined on a universe
+ * domain, extract this affine expression.
+ */
+static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
+{
+ isl_aff *aff;
+
+ if (!pa)
+ return NULL;
+ if (pa->n != 1)
+ isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+ "expecting single affine expression",
+ goto error);
+ if (!isl_set_plain_is_universe(pa->p[0].set))
+ isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+ "expecting universe domain",
+ goto error);
+
+ aff = isl_aff_copy(pa->p[0].aff);
+ isl_pw_aff_free(pa);
+ return aff;
+error:
+ isl_pw_aff_free(pa);
+ return NULL;
+}
+
+/* Read a multi-affine expression from "s".
+ * If the multi-affine expression has a domain, then the tuple
+ * representing this domain cannot involve any affine expressions.
+ * The tuple representing the actual expressions needs to consist
+ * of only affine expressions. Moreover, these expressions can
+ * only depend on parameters and input dimensions and not on other
+ * output dimensions.
+ */
+__isl_give isl_multi_aff *isl_stream_read_multi_aff(struct isl_stream *s)
+{
+ struct vars *v;
+ isl_set *dom = NULL;
+ isl_multi_pw_aff *tuple = NULL;
+ int dim, i, n;
+ isl_space *space, *dom_space;
+ isl_multi_aff *ma = NULL;
+
+ v = vars_new(s->ctx);
+ if (!v)
+ return NULL;
+
+ dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+ if (next_is_tuple(s)) {
+ dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ }
+ if (!isl_set_plain_is_universe(dom))
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting universe parameter domain", goto error);
+ if (isl_stream_eat(s, '{'))
+ goto error;
+
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+ isl_set *set;
+ isl_space *space;
+ int has_expr;
+
+ has_expr = tuple_has_expr(tuple);
+ if (has_expr < 0)
+ goto error;
+ if (has_expr)
+ isl_die(s->ctx, isl_error_invalid,
+ "expecting universe domain", goto error);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ set = isl_set_universe(space);
+ dom = isl_set_intersect_params(set, dom);
+ isl_multi_pw_aff_free(tuple);
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ }
+
+ if (isl_stream_eat(s, '}'))
+ goto error;
+
+ n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+ dim = isl_set_dim(dom, isl_dim_all);
+ dom_space = isl_set_get_space(dom);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ space = isl_space_align_params(space, isl_space_copy(dom_space));
+ if (!isl_space_is_params(dom_space))
+ space = isl_space_map_from_domain_and_range(
+ isl_space_copy(dom_space), space);
+ isl_space_free(dom_space);
+ ma = isl_multi_aff_alloc(space);
+
+ for (i = 0; i < n; ++i) {
+ isl_pw_aff *pa;
+ isl_aff *aff;
+ pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+ aff = aff_from_pw_aff(pa);
+ if (!aff)
+ goto error;
+ if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) {
+ isl_aff_free(aff);
+ isl_die(s->ctx, isl_error_invalid,
+ "not an affine expression", goto error);
+ }
+ aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n);
+ space = isl_multi_aff_get_domain_space(ma);
+ aff = isl_aff_reset_domain_space(aff, space);
+ ma = isl_multi_aff_set_aff(ma, i, aff);
+ }
+
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ isl_set_free(dom);
+ return ma;
+error:
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ isl_set_free(dom);
+ isl_multi_aff_free(ma);
+ return NULL;
+}
+
+__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_multi_aff *maff;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ maff = isl_stream_read_multi_aff(s);
+ isl_stream_free(s);
+ return maff;
+}
+
+/* Read an isl_multi_pw_aff from "s".
+ *
+ * The input format is similar to that of map, except that any conditions
+ * on the domains should be specified inside the tuple since each
+ * piecewise affine expression may have a different domain.
+ *
+ * Since we do not know in advance if the isl_multi_pw_aff lives
+ * in a set or a map space, we first read the first tuple and check
+ * if it is followed by a "->". If so, we convert the tuple into
+ * the domain of the isl_multi_pw_aff and read in the next tuple.
+ * This tuple (or the first tuple if it was not followed by a "->")
+ * is then converted into the isl_multi_pw_aff.
+ *
+ * Note that the function read_tuple accepts tuples where some output or
+ * set dimensions are defined in terms of other output or set dimensions
+ * since this function is also used to read maps. As a special case,
+ * read_tuple also accept dimensions that are defined in terms of themselves
+ * (i.e., that are not defined).
+ * These cases are not allowed when reading am isl_multi_pw_aff so we check
+ * that the definition of the output/set dimensions does not involve any
+ * output/set dimensions.
+ * We then drop the output dimensions from the domain of the result
+ * of read_tuple (which is of the form [input, output] -> [output],
+ * with anonymous domain) and reset the space.
+ */
+__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(struct isl_stream *s)
+{
+ struct vars *v;
+ isl_set *dom = NULL;
+ isl_multi_pw_aff *tuple = NULL;
+ int dim, i, n;
+ isl_space *space, *dom_space;
+ isl_multi_pw_aff *mpa = NULL;
+
+ v = vars_new(s->ctx);
+ if (!v)
+ return NULL;
+
+ dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+ if (next_is_tuple(s)) {
+ dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+ if (isl_stream_eat(s, ISL_TOKEN_TO))
+ goto error;
+ }
+ if (isl_stream_eat(s, '{'))
+ goto error;
+
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+ isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
+ dom = isl_map_domain(map);
+ tuple = read_tuple(s, v, 0, 0);
+ if (!tuple)
+ goto error;
+ }
+
+ if (isl_stream_eat(s, '}'))
+ goto error;
+
+ n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+ dim = isl_set_dim(dom, isl_dim_all);
+ dom_space = isl_set_get_space(dom);
+ space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+ space = isl_space_align_params(space, isl_space_copy(dom_space));
+ if (!isl_space_is_params(dom_space))
+ space = isl_space_map_from_domain_and_range(
+ isl_space_copy(dom_space), space);
+ isl_space_free(dom_space);
+ mpa = isl_multi_pw_aff_alloc(space);
+
+ for (i = 0; i < n; ++i) {
+ isl_pw_aff *pa;
+ pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+ if (!pa)
+ goto error;
+ if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
+ isl_pw_aff_free(pa);
+ isl_die(s->ctx, isl_error_invalid,
+ "not an affine expression", goto error);
+ }
+ pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n);
+ space = isl_multi_pw_aff_get_domain_space(mpa);
+ pa = isl_pw_aff_reset_domain_space(pa, space);
+ mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
+ }
+
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);
+ return mpa;
+error:
+ isl_multi_pw_aff_free(tuple);
+ vars_free(v);
+ isl_set_free(dom);
+ isl_multi_pw_aff_free(mpa);
+ return NULL;
+}
+
+/* Read an isl_multi_pw_aff from "str".
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
+ const char *str)
+{
+ isl_multi_pw_aff *mpa;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ mpa = isl_stream_read_multi_pw_aff(s);
+ isl_stream_free(s);
+ return mpa;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
+ struct isl_stream *s)
+{
+ struct isl_obj obj;
+
+ obj = obj_read(s);
+ if (obj.type == isl_obj_pw_qpolynomial) {
+ obj.type = isl_obj_union_pw_qpolynomial;
+ obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+ }
+ if (obj.v)
+ isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
+ goto error);
+
+ return obj.v;
+error:
+ obj.type->free(obj.v);
+ return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
+ isl_ctx *ctx, const char *str)
+{
+ isl_union_pw_qpolynomial *upwqp;
+ struct isl_stream *s = isl_stream_new_str(ctx, str);
+ if (!s)
+ return NULL;
+ upwqp = isl_stream_read_union_pw_qpolynomial(s);
+ isl_stream_free(s);
+ return upwqp;
+}
Added: polly/trunk/lib/External/isl/isl_int.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int.h (added)
+++ polly/trunk/lib/External/isl/isl_int.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_INT_H
+#define ISL_INT_H
+#define ISL_DEPRECATED_INT_H
+
+#include <isl/hash.h>
+#include <isl/printer.h>
+#include <string.h>
+#include <isl_config.h>
+
+#ifdef USE_GMP_FOR_MP
+#include <isl_int_gmp.h>
+#endif
+
+#ifdef USE_IMATH_FOR_MP
+#include <isl_int_imath.h>
+#endif
+
+#define isl_int_is_zero(i) (isl_int_sgn(i) == 0)
+#define isl_int_is_one(i) (isl_int_cmp_si(i,1) == 0)
+#define isl_int_is_negone(i) (isl_int_cmp_si(i,-1) == 0)
+#define isl_int_is_pos(i) (isl_int_sgn(i) > 0)
+#define isl_int_is_neg(i) (isl_int_sgn(i) < 0)
+#define isl_int_is_nonpos(i) (isl_int_sgn(i) <= 0)
+#define isl_int_is_nonneg(i) (isl_int_sgn(i) >= 0)
+
+#define isl_int_print(out,i,width) \
+ do { \
+ char *s; \
+ s = isl_int_get_str(i); \
+ fprintf(out, "%*s", width, s); \
+ isl_int_free_str(s); \
+ } while (0)
+
+__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
+ isl_int i);
+
+#endif /* ISL_INT_H */
Added: polly/trunk/lib/External/isl/isl_int_gmp.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int_gmp.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int_gmp.h (added)
+++ polly/trunk/lib/External/isl/isl_int_gmp.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,88 @@
+#ifndef ISL_INT_GMP_H
+#define ISL_INT_GMP_H
+
+#include <gmp.h>
+
+/* isl_int is the basic integer type, implemented with GMP's mpz_t. In the
+ * future, different types such as long long or cln::cl_I will be supported.
+ */
+typedef mpz_t isl_int;
+
+#define isl_int_init(i) mpz_init(i)
+#define isl_int_clear(i) mpz_clear(i)
+
+#define isl_int_set(r,i) mpz_set(r,i)
+#define isl_int_set_si(r,i) mpz_set_si(r,i)
+#define isl_int_set_ui(r,i) mpz_set_ui(r,i)
+#define isl_int_fits_slong(r) mpz_fits_slong_p(r)
+#define isl_int_get_si(r) mpz_get_si(r)
+#define isl_int_fits_ulong(r) mpz_fits_ulong_p(r)
+#define isl_int_get_ui(r) mpz_get_ui(r)
+#define isl_int_get_d(r) mpz_get_d(r)
+#define isl_int_get_str(r) mpz_get_str(0, 10, r)
+#define isl_int_abs(r,i) mpz_abs(r,i)
+#define isl_int_neg(r,i) mpz_neg(r,i)
+#define isl_int_swap(i,j) mpz_swap(i,j)
+#define isl_int_swap_or_set(i,j) mpz_swap(i,j)
+#define isl_int_add_ui(r,i,j) mpz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j) mpz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j) mpz_add(r,i,j)
+#define isl_int_sub(r,i,j) mpz_sub(r,i,j)
+#define isl_int_mul(r,i,j) mpz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j) mpz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j) mpz_mul_si(r,i,j)
+#define isl_int_mul_ui(r,i,j) mpz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j) mpz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j) mpz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j) mpz_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j) mpz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j) mpz_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j) mpz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j) mpz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j) mpz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j) mpz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j) mpz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j) mpz_cdiv_q(r,i,j)
+#define isl_int_fdiv_q(r,i,j) mpz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j) mpz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j) mpz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s) mpz_set_str(r,s,10)
+#define isl_int_sgn(i) mpz_sgn(i)
+#define isl_int_cmp(i,j) mpz_cmp(i,j)
+#define isl_int_cmp_si(i,si) mpz_cmp_si(i,si)
+#define isl_int_eq(i,j) (mpz_cmp(i,j) == 0)
+#define isl_int_ne(i,j) (mpz_cmp(i,j) != 0)
+#define isl_int_lt(i,j) (mpz_cmp(i,j) < 0)
+#define isl_int_le(i,j) (mpz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j) (mpz_cmp(i,j) > 0)
+#define isl_int_ge(i,j) (mpz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j) mpz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j) (mpz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j) (mpz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j) (mpz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j) (mpz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j) (mpz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j) mpz_divisible_p(i,j)
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash);
+#define isl_int_hash(v,h) isl_gmp_hash(v,h)
+
+#ifndef mp_get_memory_functions
+void mp_get_memory_functions(
+ void *(**alloc_func_ptr) (size_t),
+ void *(**realloc_func_ptr) (void *, size_t, size_t),
+ void (**free_func_ptr) (void *, size_t));
+#endif
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s) \
+ do { \
+ isl_int_print_mp_free_t mp_free; \
+ mp_get_memory_functions(NULL, NULL, &mp_free); \
+ (*mp_free)(s, strlen(s) + 1); \
+ } while (0)
+
+#endif /* ISL_INT_GMP_H */
Added: polly/trunk/lib/External/isl/isl_int_imath.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_int_imath.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_int_imath.h (added)
+++ polly/trunk/lib/External/isl/isl_int_imath.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,76 @@
+#ifndef ISL_INT_IMATH_H
+#define ISL_INT_IMATH_H
+
+#include "isl_hide_deprecated.h"
+
+#include <isl_imath.h>
+
+/* isl_int is the basic integer type, implemented with imath's mp_int. */
+typedef mp_int isl_int;
+
+#define isl_int_init(i) i = mp_int_alloc()
+#define isl_int_clear(i) mp_int_free(i)
+
+#define isl_int_set(r,i) impz_set(r,i)
+#define isl_int_set_si(r,i) impz_set_si(r,i)
+#define isl_int_set_ui(r,i) impz_set_ui(r,i)
+#define isl_int_fits_slong(r) isl_imath_fits_slong_p(r)
+#define isl_int_get_si(r) impz_get_si(r)
+#define isl_int_fits_ulong(r) isl_imath_fits_ulong_p(r)
+#define isl_int_get_ui(r) impz_get_ui(r)
+#define isl_int_get_d(r) impz_get_si(r)
+#define isl_int_get_str(r) impz_get_str(0, 10, r)
+#define isl_int_abs(r,i) impz_abs(r,i)
+#define isl_int_neg(r,i) impz_neg(r,i)
+#define isl_int_swap(i,j) impz_swap(i,j)
+#define isl_int_swap_or_set(i,j) impz_swap(i,j)
+#define isl_int_add_ui(r,i,j) impz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j) impz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j) impz_add(r,i,j)
+#define isl_int_sub(r,i,j) impz_sub(r,i,j)
+#define isl_int_mul(r,i,j) impz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j) impz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j) mp_int_mul_value(i,j,r)
+#define isl_int_mul_ui(r,i,j) impz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j) impz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j) impz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j) isl_imath_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j) impz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j) isl_imath_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j) impz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j) impz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j) impz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j) impz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j) impz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j) impz_cdiv_q(r,i,j)
+#define isl_int_fdiv_q(r,i,j) impz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j) impz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j) impz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s) impz_set_str(r,s,10)
+#define isl_int_sgn(i) impz_sgn(i)
+#define isl_int_cmp(i,j) impz_cmp(i,j)
+#define isl_int_cmp_si(i,si) impz_cmp_si(i,si)
+#define isl_int_eq(i,j) (impz_cmp(i,j) == 0)
+#define isl_int_ne(i,j) (impz_cmp(i,j) != 0)
+#define isl_int_lt(i,j) (impz_cmp(i,j) < 0)
+#define isl_int_le(i,j) (impz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j) (impz_cmp(i,j) > 0)
+#define isl_int_ge(i,j) (impz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j) impz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j) (impz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j) (impz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j) (impz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j) (impz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j) (impz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j) impz_divisible_p(i,j)
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+#define isl_int_hash(v,h) isl_imath_hash(v,h)
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s) free(s)
+
+#endif /* ISL_INT_IMATH_H */
Added: polly/trunk/lib/External/isl/isl_list_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_list_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_list_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_list_templ.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2011 INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+#include <isl_sort.h>
+#include <isl_tarjan.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
+
+isl_ctx *FN(LIST(EL),get_ctx)(__isl_keep LIST(EL) *list)
+{
+ return list ? list->ctx : NULL;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),alloc)(isl_ctx *ctx, int n)
+{
+ LIST(EL) *list;
+
+ if (n < 0)
+ isl_die(ctx, isl_error_invalid,
+ "cannot create list of negative length",
+ return NULL);
+ list = isl_alloc(ctx, LIST(EL),
+ sizeof(LIST(EL)) + (n - 1) * sizeof(struct EL *));
+ if (!list)
+ return NULL;
+
+ list->ctx = ctx;
+ isl_ctx_ref(ctx);
+ list->ref = 1;
+ list->size = n;
+ list->n = 0;
+ return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),copy)(__isl_keep LIST(EL) *list)
+{
+ if (!list)
+ return NULL;
+
+ list->ref++;
+ return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list)
+{
+ int i;
+ LIST(EL) *dup;
+
+ if (!list)
+ return NULL;
+
+ dup = FN(LIST(EL),alloc)(FN(LIST(EL),get_ctx)(list), list->n);
+ if (!dup)
+ return NULL;
+ for (i = 0; i < list->n; ++i)
+ dup = FN(LIST(EL),add)(dup, FN(EL,copy)(list->p[i]));
+ return dup;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),cow)(__isl_take LIST(EL) *list)
+{
+ if (!list)
+ return NULL;
+
+ if (list->ref == 1)
+ return list;
+ list->ref--;
+ return FN(LIST(EL),dup)(list);
+}
+
+/* Make sure "list" has room for at least "n" more pieces.
+ * Always return a list with a single reference.
+ *
+ * If there is only one reference to list, we extend it in place.
+ * Otherwise, we create a new LIST(EL) and copy the elements.
+ */
+static __isl_give LIST(EL) *FN(LIST(EL),grow)(__isl_take LIST(EL) *list, int n)
+{
+ isl_ctx *ctx;
+ int i, new_size;
+ LIST(EL) *res;
+
+ if (!list)
+ return NULL;
+ if (list->ref == 1 && list->n + n <= list->size)
+ return list;
+
+ ctx = FN(LIST(EL),get_ctx)(list);
+ new_size = ((list->n + n + 1) * 3) / 2;
+ if (list->ref == 1) {
+ res = isl_realloc(ctx, list, LIST(EL),
+ sizeof(LIST(EL)) + (new_size - 1) * sizeof(EL *));
+ if (!res)
+ return FN(LIST(EL),free)(list);
+ res->size = new_size;
+ return res;
+ }
+
+ if (list->n + n <= list->size && list->size < new_size)
+ new_size = list->size;
+
+ res = FN(LIST(EL),alloc)(ctx, new_size);
+ if (!res)
+ return FN(LIST(EL),free)(list);
+
+ for (i = 0; i < list->n; ++i)
+ res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+
+ FN(LIST(EL),free)(list);
+ return res;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),add)(__isl_take LIST(EL) *list,
+ __isl_take struct EL *el)
+{
+ list = FN(LIST(EL),grow)(list, 1);
+ if (!list || !el)
+ goto error;
+ list->p[list->n] = el;
+ list->n++;
+ return list;
+error:
+ FN(EL,free)(el);
+ FN(LIST(EL),free)(list);
+ return NULL;
+}
+
+/* Remove the "n" elements starting at "first" from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),drop)(__isl_take LIST(EL) *list,
+ unsigned first, unsigned n)
+{
+ int i;
+
+ if (!list)
+ return NULL;
+ if (first + n > list->n || first + n < first)
+ isl_die(list->ctx, isl_error_invalid,
+ "index out of bounds", return FN(LIST(EL),free)(list));
+ if (n == 0)
+ return list;
+ list = FN(LIST(EL),cow)(list);
+ if (!list)
+ return NULL;
+ for (i = 0; i < n; ++i)
+ FN(EL,free)(list->p[first + i]);
+ for (i = first; i + n < list->n; ++i)
+ list->p[i] = list->p[i + n];
+ list->n -= n;
+ return list;
+}
+
+/* Insert "el" at position "pos" in "list".
+ *
+ * If there is only one reference to "list" and if it already has space
+ * for one extra element, we insert it directly into "list".
+ * Otherwise, we create a new list consisting of "el" and copied
+ * elements from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),insert)(__isl_take LIST(EL) *list,
+ unsigned pos, __isl_take struct EL *el)
+{
+ int i;
+ isl_ctx *ctx;
+ LIST(EL) *res;
+
+ if (!list || !el)
+ goto error;
+ ctx = FN(LIST(EL),get_ctx)(list);
+ if (pos > list->n)
+ isl_die(ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+
+ if (list->ref == 1 && list->size > list->n) {
+ for (i = list->n - 1; i >= pos; --i)
+ list->p[i + 1] = list->p[i];
+ list->n++;
+ list->p[pos] = el;
+ return list;
+ }
+
+ res = FN(LIST(EL),alloc)(ctx, list->n + 1);
+ for (i = 0; i < pos; ++i)
+ res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+ res = FN(LIST(EL),add)(res, el);
+ for (i = pos; i < list->n; ++i)
+ res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+ FN(LIST(EL),free)(list);
+
+ return res;
+error:
+ FN(EL,free)(el);
+ FN(LIST(EL),free)(list);
+ return NULL;
+}
+
+__isl_null LIST(EL) *FN(LIST(EL),free)(__isl_take LIST(EL) *list)
+{
+ int i;
+
+ if (!list)
+ return NULL;
+
+ if (--list->ref > 0)
+ return NULL;
+
+ isl_ctx_deref(list->ctx);
+ for (i = 0; i < list->n; ++i)
+ FN(EL,free)(list->p[i]);
+ free(list);
+
+ return NULL;
+}
+
+int FN(FN(LIST(EL),n),BASE)(__isl_keep LIST(EL) *list)
+{
+ return list ? list->n : 0;
+}
+
+__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index)
+{
+ if (!list)
+ return NULL;
+ if (index < 0 || index >= list->n)
+ isl_die(list->ctx, isl_error_invalid,
+ "index out of bounds", return NULL);
+ return FN(EL,copy)(list->p[index]);
+}
+
+/* Replace the element at position "index" in "list" by "el".
+ */
+__isl_give LIST(EL) *FN(FN(LIST(EL),set),BASE)(__isl_take LIST(EL) *list,
+ int index, __isl_take EL *el)
+{
+ if (!list || !el)
+ goto error;
+ if (index < 0 || index >= list->n)
+ isl_die(list->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+ if (list->p[index] == el) {
+ FN(EL,free)(el);
+ return list;
+ }
+ list = FN(LIST(EL),cow)(list);
+ if (!list)
+ goto error;
+ FN(EL,free)(list->p[index]);
+ list->p[index] = el;
+ return list;
+error:
+ FN(EL,free)(el);
+ FN(LIST(EL),free)(list);
+ return NULL;
+}
+
+int FN(LIST(EL),foreach)(__isl_keep LIST(EL) *list,
+ int (*fn)(__isl_take EL *el, void *user), void *user)
+{
+ int i;
+
+ if (!list)
+ return -1;
+
+ for (i = 0; i < list->n; ++i) {
+ EL *el = FN(EL,copy(list->p[i]));
+ if (!el)
+ return -1;
+ if (fn(el, user) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Internal data structure for isl_*_list_sort.
+ *
+ * "cmp" is the original comparison function.
+ * "user" is a user provided pointer that should be passed to "cmp".
+ */
+S(LIST(EL),sort_data) {
+ int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+ void *user;
+};
+
+/* Compare two entries of an isl_*_list based on the user provided
+ * comparison function on pairs of isl_* objects.
+ */
+static int FN(LIST(EL),cmp)(const void *a, const void *b, void *user)
+{
+ S(LIST(EL),sort_data) *data = user;
+ EL * const *el1 = a;
+ EL * const *el2 = b;
+
+ return data->cmp(*el1, *el2, data->user);
+}
+
+/* Sort the elements of "list" in ascending order according to
+ * comparison function "cmp".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),sort)(__isl_take LIST(EL) *list,
+ int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user), void *user)
+{
+ S(LIST(EL),sort_data) data = { cmp, user };
+
+ if (!list)
+ return NULL;
+ if (list->n <= 1)
+ return list;
+ list = FN(LIST(EL),cow)(list);
+ if (!list)
+ return NULL;
+
+ if (isl_sort(list->p, list->n, sizeof(list->p[0]),
+ &FN(LIST(EL),cmp), &data) < 0)
+ return FN(LIST(EL),free)(list);
+
+ return list;
+}
+
+/* Internal data structure for isl_*_list_foreach_scc.
+ *
+ * "list" is the original list.
+ * "follows" is the user provided callback that defines the edges of the graph.
+ */
+S(LIST(EL),foreach_scc_data) {
+ LIST(EL) *list;
+ int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+ void *follows_user;
+};
+
+/* Does element i of data->list follow element j?
+ *
+ * Use the user provided callback to find out.
+ */
+static int FN(LIST(EL),follows)(int i, int j, void *user)
+{
+ S(LIST(EL),foreach_scc_data) *data = user;
+
+ return data->follows(data->list->p[i], data->list->p[j],
+ data->follows_user);
+}
+
+/* Call "fn" on the sublist of "list" that consists of the elements
+ * with indices specified by the "n" elements of "pos".
+ */
+static int FN(LIST(EL),call_on_scc)(__isl_keep LIST(EL) *list, int *pos, int n,
+ int (*fn)(__isl_take LIST(EL) *scc, void *user), void *user)
+{
+ int i;
+ isl_ctx *ctx;
+ LIST(EL) *slice;
+
+ ctx = FN(LIST(EL),get_ctx)(list);
+ slice = FN(LIST(EL),alloc)(ctx, n);
+ for (i = 0; i < n; ++i) {
+ EL *el;
+
+ el = FN(EL,copy)(list->p[pos[i]]);
+ slice = FN(LIST(EL),add)(slice, el);
+ }
+
+ return fn(slice, user);
+}
+
+/* Call "fn" on each of the strongly connected components (SCCs) of
+ * the graph with as vertices the elements of "list" and
+ * a directed edge from node b to node a iff follows(a, b)
+ * returns 1. follows should return -1 on error.
+ *
+ * If SCC a contains a node i that follows a node j in another SCC b
+ * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a
+ * after being called on SCC b.
+ *
+ * We simply call isl_tarjan_graph_init, extract the SCCs from the result and
+ * call fn on each of them.
+ */
+int FN(LIST(EL),foreach_scc)(__isl_keep LIST(EL) *list,
+ int (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user),
+ void *follows_user,
+ int (*fn)(__isl_take LIST(EL) *scc, void *user), void *fn_user)
+{
+ S(LIST(EL),foreach_scc_data) data = { list, follows, follows_user };
+ int i, n;
+ isl_ctx *ctx;
+ struct isl_tarjan_graph *g;
+
+ if (!list)
+ return -1;
+ if (list->n == 0)
+ return 0;
+ if (list->n == 1)
+ return fn(FN(LIST(EL),copy)(list), fn_user);
+
+ ctx = FN(LIST(EL),get_ctx)(list);
+ n = list->n;
+ g = isl_tarjan_graph_init(ctx, n, &FN(LIST(EL),follows), &data);
+ if (!g)
+ return -1;
+
+ i = 0;
+ do {
+ int first;
+
+ if (g->order[i] == -1)
+ isl_die(ctx, isl_error_internal, "cannot happen",
+ break);
+ first = i;
+ while (g->order[i] != -1) {
+ ++i; --n;
+ }
+ if (first == 0 && n == 0) {
+ isl_tarjan_graph_free(g);
+ return fn(FN(LIST(EL),copy)(list), fn_user);
+ }
+ if (FN(LIST(EL),call_on_scc)(list, g->order + first, i - first,
+ fn, fn_user) < 0)
+ break;
+ ++i;
+ } while (n);
+
+ isl_tarjan_graph_free(g);
+
+ return n > 0 ? -1 : 0;
+}
+
+__isl_give LIST(EL) *FN(FN(LIST(EL),from),BASE)(__isl_take EL *el)
+{
+ isl_ctx *ctx;
+ LIST(EL) *list;
+
+ if (!el)
+ return NULL;
+ ctx = FN(EL,get_ctx)(el);
+ list = FN(LIST(EL),alloc)(ctx, 1);
+ if (!list)
+ goto error;
+ list = FN(LIST(EL),add)(list, el);
+ return list;
+error:
+ FN(EL,free)(el);
+ return NULL;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),concat)(__isl_take LIST(EL) *list1,
+ __isl_take LIST(EL) *list2)
+{
+ int i;
+ isl_ctx *ctx;
+ LIST(EL) *res;
+
+ if (!list1 || !list2)
+ goto error;
+
+ ctx = FN(LIST(EL),get_ctx)(list1);
+ res = FN(LIST(EL),alloc)(ctx, list1->n + list2->n);
+ for (i = 0; i < list1->n; ++i)
+ res = FN(LIST(EL),add)(res, FN(EL,copy)(list1->p[i]));
+ for (i = 0; i < list2->n; ++i)
+ res = FN(LIST(EL),add)(res, FN(EL,copy)(list2->p[i]));
+
+ FN(LIST(EL),free)(list1);
+ FN(LIST(EL),free)(list2);
+ return res;
+error:
+ FN(LIST(EL),free)(list1);
+ FN(LIST(EL),free)(list2);
+ return NULL;
+}
+
+__isl_give isl_printer *CAT(isl_printer_print_,LIST(BASE))(
+ __isl_take isl_printer *p, __isl_keep LIST(EL) *list)
+{
+ int i;
+
+ if (!p || !list)
+ goto error;
+ p = isl_printer_print_str(p, "(");
+ for (i = 0; i < list->n; ++i) {
+ if (i)
+ p = isl_printer_print_str(p, ",");
+ p = CAT(isl_printer_print_,BASE)(p, list->p[i]);
+ }
+ p = isl_printer_print_str(p, ")");
+ return p;
+error:
+ isl_printer_free(p);
+ return NULL;
+}
+
+void FN(LIST(EL),dump)(__isl_keep LIST(EL) *list)
+{
+ isl_printer *printer;
+
+ if (!list)
+ return;
+
+ printer = isl_printer_to_file(FN(LIST(EL),get_ctx)(list), stderr);
+ printer = CAT(isl_printer_print_,LIST(BASE))(printer, list);
+ printer = isl_printer_end_line(printer);
+
+ isl_printer_free(printer);
+}
Added: polly/trunk/lib/External/isl/isl_list_templ.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_list_templ.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_list_templ.h (added)
+++ polly/trunk/lib/External/isl/isl_list_templ.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,16 @@
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+
+struct LIST(EL) {
+ int ref;
+ isl_ctx *ctx;
+
+ int n;
+
+ size_t size;
+ struct EL *p[1];
+};
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list);
Added: polly/trunk/lib/External/isl/isl_local_space.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_local_space.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_local_space.c (added)
+++ polly/trunk/lib/External/isl/isl_local_space.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,1363 @@
+/*
+ * Copyright 2011 INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_local_space_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
+{
+ return ls ? ls->dim->ctx : NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+ __isl_take isl_mat *div)
+{
+ isl_ctx *ctx;
+ isl_local_space *ls = NULL;
+
+ if (!dim || !div)
+ goto error;
+
+ ctx = isl_space_get_ctx(dim);
+ ls = isl_calloc_type(ctx, struct isl_local_space);
+ if (!ls)
+ goto error;
+
+ ls->ref = 1;
+ ls->dim = dim;
+ ls->div = div;
+
+ return ls;
+error:
+ isl_mat_free(div);
+ isl_space_free(dim);
+ isl_local_space_free(ls);
+ return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+ unsigned n_div)
+{
+ isl_ctx *ctx;
+ isl_mat *div;
+ unsigned total;
+
+ if (!dim)
+ return NULL;
+
+ total = isl_space_dim(dim, isl_dim_all);
+
+ ctx = isl_space_get_ctx(dim);
+ div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
+ return isl_local_space_alloc_div(dim, div);
+}
+
+__isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
+{
+ return isl_local_space_alloc(dim, 0);
+}
+
+__isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ ls->ref++;
+ return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ return isl_local_space_alloc_div(isl_space_copy(ls->dim),
+ isl_mat_copy(ls->div));
+
+}
+
+__isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ if (ls->ref == 1)
+ return ls;
+ ls->ref--;
+ return isl_local_space_dup(ls);
+}
+
+__isl_null isl_local_space *isl_local_space_free(
+ __isl_take isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ if (--ls->ref > 0)
+ return NULL;
+
+ isl_space_free(ls->dim);
+ isl_mat_free(ls->div);
+
+ free(ls);
+
+ return NULL;
+}
+
+/* Is the local space that of a parameter domain?
+ */
+int isl_local_space_is_params(__isl_keep isl_local_space *ls)
+{
+ if (!ls)
+ return -1;
+ return isl_space_is_params(ls->dim);
+}
+
+/* Is the local space that of a set?
+ */
+int isl_local_space_is_set(__isl_keep isl_local_space *ls)
+{
+ return ls ? isl_space_is_set(ls->dim) : -1;
+}
+
+/* Return true if the two local spaces are identical, with identical
+ * expressions for the integer divisions.
+ */
+int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
+ __isl_keep isl_local_space *ls2)
+{
+ int equal;
+
+ if (!ls1 || !ls2)
+ return -1;
+
+ equal = isl_space_is_equal(ls1->dim, ls2->dim);
+ if (equal < 0 || !equal)
+ return equal;
+
+ if (!isl_local_space_divs_known(ls1))
+ return 0;
+ if (!isl_local_space_divs_known(ls2))
+ return 0;
+
+ return isl_mat_is_equal(ls1->div, ls2->div);
+}
+
+/* Compare two isl_local_spaces.
+ *
+ * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
+ * than "ls2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary. We do "prefer" divs that only involve
+ * earlier dimensions in the sense that we consider local spaces where
+ * the first differing div involves earlier dimensions to be smaller.
+ */
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+ __isl_keep isl_local_space *ls2)
+{
+ int i;
+ int cmp;
+ int known1, known2;
+ int last1, last2;
+ int n_col;
+
+ if (ls1 == ls2)
+ return 0;
+ if (!ls1)
+ return -1;
+ if (!ls2)
+ return 1;
+
+ cmp = isl_space_cmp(ls1->dim, ls2->dim);
+ if (cmp != 0)
+ return cmp;
+
+ if (ls1->div->n_row != ls2->div->n_row)
+ return ls1->div->n_row - ls2->div->n_row;
+
+ n_col = isl_mat_cols(ls1->div);
+ for (i = 0; i < ls1->div->n_row; ++i) {
+ known1 = isl_local_space_div_is_known(ls1, i);
+ known2 = isl_local_space_div_is_known(ls2, i);
+ if (!known1 && !known2)
+ continue;
+ if (!known1)
+ return 1;
+ if (!known2)
+ return -1;
+ last1 = isl_seq_last_non_zero(ls1->div->row[i] + 1, n_col - 1);
+ last2 = isl_seq_last_non_zero(ls2->div->row[i] + 1, n_col - 1);
+ if (last1 != last2)
+ return last1 - last2;
+ cmp = isl_seq_cmp(ls1->div->row[i], ls2->div->row[i], n_col);
+ if (cmp != 0)
+ return cmp;
+ }
+
+ return 0;
+}
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type)
+{
+ if (!ls)
+ return 0;
+ if (type == isl_dim_div)
+ return ls->div->n_row;
+ if (type == isl_dim_all)
+ return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
+ return isl_space_dim(ls->dim, type);
+}
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type)
+{
+ isl_space *dim;
+
+ if (!ls)
+ return 0;
+
+ dim = ls->dim;
+ switch (type) {
+ case isl_dim_cst: return 0;
+ case isl_dim_param: return 1;
+ case isl_dim_in: return 1 + dim->nparam;
+ case isl_dim_out: return 1 + dim->nparam + dim->n_in;
+ case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
+ default: return 0;
+ }
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "ls".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type, const char *name)
+{
+ if (!ls)
+ return -1;
+ if (type == isl_dim_div)
+ return -1;
+ return isl_space_find_dim_by_name(ls->dim, type, name);
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos)
+{
+ return ls ? isl_space_has_dim_name(ls->dim, type, pos) : -1;
+}
+
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos)
+{
+ return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
+}
+
+int isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos)
+{
+ return ls ? isl_space_has_dim_id(ls->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos)
+{
+ return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
+}
+
+__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+ int pos)
+{
+ isl_aff *aff;
+
+ if (!ls)
+ return NULL;
+
+ if (pos < 0 || pos >= ls->div->n_row)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "index out of bounds", return NULL);
+
+ if (isl_int_is_zero(ls->div->row[pos][0]))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "expression of div unknown", return NULL);
+ if (!isl_local_space_is_set(ls))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "cannot represent divs of map spaces", return NULL);
+
+ aff = isl_aff_alloc(isl_local_space_copy(ls));
+ if (!aff)
+ return NULL;
+ isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
+ return aff;
+}
+
+__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ return isl_space_copy(ls->dim);
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_local_space *isl_local_space_set_tuple_id(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, __isl_take isl_id *id)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ goto error;
+ ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ return ls;
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_name(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+ ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_id(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ goto error;
+ ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+
+ return ls;
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+ __isl_take isl_local_space *ls, __isl_take isl_space *dim)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls || !dim)
+ goto error;
+
+ isl_space_free(ls->dim);
+ ls->dim = dim;
+
+ return ls;
+error:
+ isl_local_space_free(ls);
+ isl_space_free(dim);
+ return NULL;
+}
+
+/* Reorder the columns of the given div definitions according to the
+ * given reordering.
+ * The order of the divs themselves is assumed not to change.
+ */
+static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
+ __isl_take isl_reordering *r)
+{
+ int i, j;
+ isl_mat *mat;
+ int extra;
+
+ if (!div || !r)
+ goto error;
+
+ extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
+ mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
+ if (!mat)
+ goto error;
+
+ for (i = 0; i < div->n_row; ++i) {
+ isl_seq_cpy(mat->row[i], div->row[i], 2);
+ isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
+ for (j = 0; j < r->len; ++j)
+ isl_int_set(mat->row[i][2 + r->pos[j]],
+ div->row[i][2 + j]);
+ }
+
+ isl_reordering_free(r);
+ isl_mat_free(div);
+ return mat;
+error:
+ isl_reordering_free(r);
+ isl_mat_free(div);
+ return NULL;
+}
+
+/* Reorder the dimensions of "ls" according to the given reordering.
+ * The reordering r is assumed to have been extended with the local
+ * variables, leaving them in the same order.
+ */
+__isl_give isl_local_space *isl_local_space_realign(
+ __isl_take isl_local_space *ls, __isl_take isl_reordering *r)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls || !r)
+ goto error;
+
+ ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
+ if (!ls->div)
+ goto error;
+
+ ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
+
+ isl_reordering_free(r);
+ return ls;
+error:
+ isl_local_space_free(ls);
+ isl_reordering_free(r);
+ return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_add_div(
+ __isl_take isl_local_space *ls, __isl_take isl_vec *div)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls || !div)
+ goto error;
+
+ if (ls->div->n_col != div->size)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "incompatible dimensions", goto error);
+
+ ls->div = isl_mat_add_zero_cols(ls->div, 1);
+ ls->div = isl_mat_add_rows(ls->div, 1);
+ if (!ls->div)
+ goto error;
+
+ isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
+ isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
+
+ isl_vec_free(div);
+ return ls;
+error:
+ isl_local_space_free(ls);
+ isl_vec_free(div);
+ return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+ __isl_take isl_local_space *ls, __isl_take isl_mat *div)
+{
+ ls = isl_local_space_cow(ls);
+
+ if (!ls || !div)
+ goto error;
+
+ isl_mat_free(ls->div);
+ ls->div = div;
+ return ls;
+error:
+ isl_mat_free(div);
+ isl_local_space_free(ls);
+ return NULL;
+}
+
+/* Copy row "s" of "src" to row "d" of "dst", applying the expansion
+ * defined by "exp".
+ */
+static void expand_row(__isl_keep isl_mat *dst, int d,
+ __isl_keep isl_mat *src, int s, int *exp)
+{
+ int i;
+ unsigned c = src->n_col - src->n_row;
+
+ isl_seq_cpy(dst->row[d], src->row[s], c);
+ isl_seq_clr(dst->row[d] + c, dst->n_col - c);
+
+ for (i = 0; i < s; ++i)
+ isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
+}
+
+/* Compare (known) divs.
+ * Return non-zero if at least one of the two divs is unknown.
+ * In particular, if both divs are unknown, we respect their
+ * current order. Otherwise, we sort the known div after the unknown
+ * div only if the known div depends on the unknown div.
+ */
+static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
+ unsigned n_row, unsigned n_col)
+{
+ int li, lj;
+ int unknown_i, unknown_j;
+
+ unknown_i = isl_int_is_zero(row_i[0]);
+ unknown_j = isl_int_is_zero(row_j[0]);
+
+ if (unknown_i && unknown_j)
+ return i - j;
+
+ if (unknown_i)
+ li = n_col - n_row + i;
+ else
+ li = isl_seq_last_non_zero(row_i, n_col);
+ if (unknown_j)
+ lj = n_col - n_row + j;
+ else
+ lj = isl_seq_last_non_zero(row_j, n_col);
+
+ if (li != lj)
+ return li - lj;
+
+ return isl_seq_cmp(row_i, row_j, n_col);
+}
+
+/* Call cmp_row for divs in a matrix.
+ */
+int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
+{
+ return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
+}
+
+/* Call cmp_row for divs in a basic map.
+ */
+static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
+ unsigned total)
+{
+ return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
+}
+
+/* Sort the divs in "bmap".
+ *
+ * We first make sure divs are placed after divs on which they depend.
+ * Then we perform a simple insertion sort based on the same ordering
+ * that is used in isl_merge_divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+ __isl_take isl_basic_map *bmap)
+{
+ int i, j;
+ unsigned total;
+
+ bmap = isl_basic_map_order_divs(bmap);
+ if (!bmap)
+ return NULL;
+ if (bmap->n_div <= 1)
+ return bmap;
+
+ total = 2 + isl_basic_map_total_dim(bmap);
+ for (i = 1; i < bmap->n_div; ++i) {
+ for (j = i - 1; j >= 0; --j) {
+ if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
+ break;
+ isl_basic_map_swap_div(bmap, j, j + 1);
+ }
+ }
+
+ return bmap;
+}
+
+/* Sort the divs in the basic maps of "map".
+ */
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
+{
+ return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
+}
+
+/* Combine the two lists of divs into a single list.
+ * For each row i in div1, exp1[i] is set to the position of the corresponding
+ * row in the result. Similarly for div2 and exp2.
+ * This function guarantees
+ * exp1[i] >= i
+ * exp1[i+1] > exp1[i]
+ * For optimal merging, the two input list should have been sorted.
+ */
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+ __isl_keep isl_mat *div2, int *exp1, int *exp2)
+{
+ int i, j, k;
+ isl_mat *div = NULL;
+ unsigned d;
+
+ if (!div1 || !div2)
+ return NULL;
+
+ d = div1->n_col - div1->n_row;
+ div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
+ d + div1->n_row + div2->n_row);
+ if (!div)
+ return NULL;
+
+ for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
+ int cmp;
+
+ expand_row(div, k, div1, i, exp1);
+ expand_row(div, k + 1, div2, j, exp2);
+
+ cmp = isl_mat_cmp_div(div, k, k + 1);
+ if (cmp == 0) {
+ exp1[i++] = k;
+ exp2[j++] = k;
+ } else if (cmp < 0) {
+ exp1[i++] = k;
+ } else {
+ exp2[j++] = k;
+ isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
+ }
+ }
+ for (; i < div1->n_row; ++i, ++k) {
+ expand_row(div, k, div1, i, exp1);
+ exp1[i] = k;
+ }
+ for (; j < div2->n_row; ++j, ++k) {
+ expand_row(div, k, div2, j, exp2);
+ exp2[j] = k;
+ }
+
+ div->n_row = k;
+ div->n_col = d + k;
+
+ return div;
+}
+
+/* Swap divs "a" and "b" in "ls".
+ */
+__isl_give isl_local_space *isl_local_space_swap_div(
+ __isl_take isl_local_space *ls, int a, int b)
+{
+ int offset;
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+ if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "index out of bounds", return isl_local_space_free(ls));
+ offset = ls->div->n_col - ls->div->n_row;
+ ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
+ ls->div = isl_mat_swap_rows(ls->div, a, b);
+ if (!ls->div)
+ return isl_local_space_free(ls);
+ return ls;
+}
+
+/* Construct a local space that contains all the divs in either
+ * "ls1" or "ls2".
+ */
+__isl_give isl_local_space *isl_local_space_intersect(
+ __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
+{
+ isl_ctx *ctx;
+ int *exp1 = NULL;
+ int *exp2 = NULL;
+ isl_mat *div;
+ int equal;
+
+ if (!ls1 || !ls2)
+ goto error;
+
+ ctx = isl_local_space_get_ctx(ls1);
+ if (!isl_space_is_equal(ls1->dim, ls2->dim))
+ isl_die(ctx, isl_error_invalid,
+ "spaces should be identical", goto error);
+
+ if (ls2->div->n_row == 0) {
+ isl_local_space_free(ls2);
+ return ls1;
+ }
+
+ if (ls1->div->n_row == 0) {
+ isl_local_space_free(ls1);
+ return ls2;
+ }
+
+ exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
+ exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
+ if (!exp1 || !exp2)
+ goto error;
+
+ div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
+ if (!div)
+ goto error;
+
+ equal = isl_mat_is_equal(ls1->div, div);
+ if (equal < 0)
+ goto error;
+ if (!equal)
+ ls1 = isl_local_space_cow(ls1);
+ if (!ls1)
+ goto error;
+
+ free(exp1);
+ free(exp2);
+ isl_local_space_free(ls2);
+ isl_mat_free(ls1->div);
+ ls1->div = div;
+
+ return ls1;
+error:
+ free(exp1);
+ free(exp2);
+ isl_local_space_free(ls1);
+ isl_local_space_free(ls2);
+ return NULL;
+}
+
+/* Does "ls" have an explicit representation for div "div"?
+ */
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
+{
+ if (!ls)
+ return -1;
+ if (div < 0 || div >= ls->div->n_row)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "position out of bounds", return -1);
+ return !isl_int_is_zero(ls->div->row[div][0]);
+}
+
+int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
+{
+ int i;
+
+ if (!ls)
+ return -1;
+
+ for (i = 0; i < ls->div->n_row; ++i)
+ if (isl_int_is_zero(ls->div->row[i][0]))
+ return 0;
+
+ return 1;
+}
+
+__isl_give isl_local_space *isl_local_space_domain(
+ __isl_take isl_local_space *ls)
+{
+ ls = isl_local_space_drop_dims(ls, isl_dim_out,
+ 0, isl_local_space_dim(ls, isl_dim_out));
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+ ls->dim = isl_space_domain(ls->dim);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_range(
+ __isl_take isl_local_space *ls)
+{
+ ls = isl_local_space_drop_dims(ls, isl_dim_in,
+ 0, isl_local_space_dim(ls, isl_dim_in));
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ ls->dim = isl_space_range(ls->dim);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ return ls;
+}
+
+/* Construct a local space for a map that has the given local
+ * space as domain and that has a zero-dimensional range.
+ */
+__isl_give isl_local_space *isl_local_space_from_domain(
+ __isl_take isl_local_space *ls)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+ ls->dim = isl_space_from_domain(ls->dim);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_add_dims(
+ __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
+{
+ int pos;
+
+ if (!ls)
+ return NULL;
+ pos = isl_local_space_dim(ls, type);
+ return isl_local_space_insert_dims(ls, type, pos, n);
+}
+
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_local_space *ls, int div)
+{
+ isl_ctx *ctx = ls->div->ctx;
+ unsigned total = ls->div->n_col - 2;
+
+ isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
+ isl_int_gcd(ctx->normalize_gcd,
+ ctx->normalize_gcd, ls->div->row[div][0]);
+ if (isl_int_is_one(ctx->normalize_gcd))
+ return;
+
+ isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
+ ctx->normalize_gcd, total);
+ isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
+ ctx->normalize_gcd);
+ isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
+ ctx->normalize_gcd);
+}
+
+/* Exploit the equalities in "eq" to simplify the expressions of
+ * the integer divisions in "ls".
+ * The integer divisions in "ls" are assumed to appear as regular
+ * dimensions in "eq".
+ */
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+ __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
+{
+ int i, j, k;
+ unsigned total;
+ unsigned n_div;
+
+ if (!ls || !eq)
+ goto error;
+
+ total = isl_space_dim(eq->dim, isl_dim_all);
+ if (isl_local_space_dim(ls, isl_dim_all) != total)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "spaces don't match", goto error);
+ total++;
+ n_div = eq->n_div;
+ for (i = 0; i < eq->n_eq; ++i) {
+ j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+ if (j < 0 || j == 0 || j >= total)
+ continue;
+
+ for (k = 0; k < ls->div->n_row; ++k) {
+ if (isl_int_is_zero(ls->div->row[k][1 + j]))
+ continue;
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ goto error;
+ ls->div = isl_mat_cow(ls->div);
+ if (!ls->div)
+ goto error;
+ isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
+ &ls->div->row[k][0]);
+ normalize_div(ls, k);
+ }
+ }
+
+ isl_basic_set_free(eq);
+ return ls;
+error:
+ isl_basic_set_free(eq);
+ isl_local_space_free(ls);
+ return NULL;
+}
+
+/* Plug in the affine expressions "subs" of length "subs_len" (including
+ * the denominator and the constant term) into the variable at position "pos"
+ * of the "n" div expressions starting at "first".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ * f/d
+ *
+ * Any integer division starting at "first" with a non-zero coefficient for i,
+ *
+ * floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ * floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+ int first, int n)
+{
+ int i;
+ isl_int v;
+
+ if (n == 0)
+ return ls;
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+ ls->div = isl_mat_cow(ls->div);
+ if (!ls->div)
+ return isl_local_space_free(ls);
+
+ if (first + n > ls->div->n_row)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "index out of bounds", return isl_local_space_free(ls));
+
+ pos += isl_local_space_offset(ls, type);
+
+ isl_int_init(v);
+ for (i = first; i < ls->div->n_row; ++i) {
+ if (isl_int_is_zero(ls->div->row[i][1 + pos]))
+ continue;
+ isl_seq_substitute(ls->div->row[i], pos, subs,
+ ls->div->n_col, subs_len, v);
+ normalize_div(ls, i);
+ }
+ isl_int_clear(v);
+
+ return ls;
+}
+
+/* Plug in "subs" for dimension "type", "pos" in the integer divisions
+ * of "ls".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ * f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ * floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ * floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls || !subs)
+ return isl_local_space_free(ls);
+
+ if (!isl_space_is_equal(ls->dim, subs->ls->dim))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "spaces don't match", return isl_local_space_free(ls));
+ if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+ "cannot handle divs yet",
+ return isl_local_space_free(ls));
+
+ return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
+ subs->v->size, 0, ls->div->n_row);
+}
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type)
+{
+ if (!ls)
+ return -1;
+ return isl_space_is_named_or_nested(ls->dim, type);
+}
+
+__isl_give isl_local_space *isl_local_space_drop_dims(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ isl_ctx *ctx;
+
+ if (!ls)
+ return NULL;
+ if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+ return ls;
+
+ ctx = isl_local_space_get_ctx(ls);
+ if (first + n > isl_local_space_dim(ls, type))
+ isl_die(ctx, isl_error_invalid, "range out of bounds",
+ return isl_local_space_free(ls));
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ if (type == isl_dim_div) {
+ ls->div = isl_mat_drop_rows(ls->div, first, n);
+ } else {
+ ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ }
+
+ first += 1 + isl_local_space_offset(ls, type);
+ ls->div = isl_mat_drop_cols(ls->div, first, n);
+ if (!ls->div)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_insert_dims(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ isl_ctx *ctx;
+
+ if (!ls)
+ return NULL;
+ if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+ return ls;
+
+ ctx = isl_local_space_get_ctx(ls);
+ if (first > isl_local_space_dim(ls, type))
+ isl_die(ctx, isl_error_invalid, "position out of bounds",
+ return isl_local_space_free(ls));
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ if (type == isl_dim_div) {
+ ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
+ } else {
+ ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+ }
+
+ first += 1 + isl_local_space_offset(ls, type);
+ ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
+ if (!ls->div)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+/* Check if the constraints pointed to by "constraint" is a div
+ * constraint corresponding to div "div" in "ls".
+ *
+ * That is, if div = floor(f/m), then check if the constraint is
+ *
+ * f - m d >= 0
+ * or
+ * -(f-(m-1)) + m d >= 0
+ */
+int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+ isl_int *constraint, unsigned div)
+{
+ unsigned pos;
+
+ if (!ls)
+ return -1;
+
+ if (isl_int_is_zero(ls->div->row[div][0]))
+ return 0;
+
+ pos = isl_local_space_offset(ls, isl_dim_div) + div;
+
+ if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
+ int neg;
+ isl_int_sub(ls->div->row[div][1],
+ ls->div->row[div][1], ls->div->row[div][0]);
+ isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+ neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
+ isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+ isl_int_add(ls->div->row[div][1],
+ ls->div->row[div][1], ls->div->row[div][0]);
+ if (!neg)
+ return 0;
+ if (isl_seq_first_non_zero(constraint+pos+1,
+ ls->div->n_row-div-1) != -1)
+ return 0;
+ } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
+ if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
+ return 0;
+ if (isl_seq_first_non_zero(constraint+pos+1,
+ ls->div->n_row-div-1) != -1)
+ return 0;
+ } else
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Set active[i] to 1 if the dimension at position i is involved
+ * in the linear expression l.
+ */
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
+{
+ int i, j;
+ isl_ctx *ctx;
+ int *active = NULL;
+ unsigned total;
+ unsigned offset;
+
+ ctx = isl_local_space_get_ctx(ls);
+ total = isl_local_space_dim(ls, isl_dim_all);
+ active = isl_calloc_array(ctx, int, total);
+ if (total && !active)
+ return NULL;
+
+ for (i = 0; i < total; ++i)
+ active[i] = !isl_int_is_zero(l[i]);
+
+ offset = isl_local_space_offset(ls, isl_dim_div) - 1;
+ for (i = ls->div->n_row - 1; i >= 0; --i) {
+ if (!active[offset + i])
+ continue;
+ for (j = 0; j < total; ++j)
+ active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
+ }
+
+ return active;
+}
+
+/* Given a local space "ls" of a set, create a local space
+ * for the lift of the set. In particular, the result
+ * is of the form [dim -> local[..]], with ls->div->n_row variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_local_space *isl_local_space_lift(
+ __isl_take isl_local_space *ls)
+{
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
+ ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
+ if (!ls->dim || !ls->div)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+/* Construct a basic map that maps a set living in local space "ls"
+ * to the corresponding lifted local space.
+ */
+__isl_give isl_basic_map *isl_local_space_lifting(
+ __isl_take isl_local_space *ls)
+{
+ isl_basic_map *lifting;
+ isl_basic_set *bset;
+
+ if (!ls)
+ return NULL;
+ if (!isl_local_space_is_set(ls))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "lifting only defined on set spaces", goto error);
+
+ bset = isl_basic_set_from_local_space(ls);
+ lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
+ lifting = isl_basic_map_domain_map(lifting);
+ lifting = isl_basic_map_reverse(lifting);
+
+ return lifting;
+error:
+ isl_local_space_free(ls);
+ return NULL;
+}
+
+/* Compute the preimage of "ls" under the function represented by "ma".
+ * In other words, plug in "ma" in "ls". The result is a local space
+ * that is part of the domain space of "ma".
+ *
+ * If the divs in "ls" are represented as
+ *
+ * floor((a_i(p) + b_i x + c_i(divs))/n_i)
+ *
+ * and ma is represented by
+ *
+ * x = D(p) + F(y) + G(divs')
+ *
+ * then the resulting divs are
+ *
+ * floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
+ *
+ * We first copy over the divs from "ma" and then
+ * we add the modified divs from "ls".
+ */
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+ __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
+{
+ int i;
+ isl_space *space;
+ isl_local_space *res = NULL;
+ int n_div_ls, n_div_ma;
+ isl_int f, c1, c2, g;
+
+ ma = isl_multi_aff_align_divs(ma);
+ if (!ls || !ma)
+ goto error;
+ if (!isl_space_is_range_internal(ls->dim, ma->space))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "spaces don't match", goto error);
+
+ n_div_ls = isl_local_space_dim(ls, isl_dim_div);
+ n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+ space = isl_space_domain(isl_multi_aff_get_space(ma));
+ res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
+ if (!res)
+ goto error;
+
+ if (n_div_ma) {
+ isl_mat_free(res->div);
+ res->div = isl_mat_copy(ma->p[0]->ls->div);
+ res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
+ res->div = isl_mat_add_rows(res->div, n_div_ls);
+ if (!res->div)
+ goto error;
+ }
+
+ isl_int_init(f);
+ isl_int_init(c1);
+ isl_int_init(c2);
+ isl_int_init(g);
+
+ for (i = 0; i < ls->div->n_row; ++i) {
+ if (isl_int_is_zero(ls->div->row[i][0])) {
+ isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
+ continue;
+ }
+ isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
+ ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
+ normalize_div(res, n_div_ma + i);
+ }
+
+ isl_int_clear(f);
+ isl_int_clear(c1);
+ isl_int_clear(c2);
+ isl_int_clear(g);
+
+ isl_local_space_free(ls);
+ isl_multi_aff_free(ma);
+ return res;
+error:
+ isl_local_space_free(ls);
+ isl_multi_aff_free(ma);
+ isl_local_space_free(res);
+ return NULL;
+}
+
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * Moving to/from local dimensions is not allowed.
+ * We currently assume that the dimension type changes.
+ */
+__isl_give isl_local_space *isl_local_space_move_dims(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ unsigned g_dst_pos;
+ unsigned g_src_pos;
+
+ if (!ls)
+ return NULL;
+ if (n == 0 &&
+ !isl_local_space_is_named_or_nested(ls, src_type) &&
+ !isl_local_space_is_named_or_nested(ls, dst_type))
+ return ls;
+
+ if (src_pos + n > isl_local_space_dim(ls, src_type))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "range out of bounds", return isl_local_space_free(ls));
+ if (dst_pos > isl_local_space_dim(ls, dst_type))
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "position out of bounds",
+ return isl_local_space_free(ls));
+ if (src_type == isl_dim_div)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "cannot move divs", return isl_local_space_free(ls));
+ if (dst_type == isl_dim_div)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+ "cannot move to divs", return isl_local_space_free(ls));
+ if (dst_type == src_type && dst_pos == src_pos)
+ return ls;
+ if (dst_type == src_type)
+ isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+ "moving dims within the same type not supported",
+ return isl_local_space_free(ls));
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
+ g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
+ if (dst_type > src_type)
+ g_dst_pos -= n;
+ ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
+ if (!ls->div)
+ return isl_local_space_free(ls);
+ ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+/* Remove any internal structure of the domain of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_domain(
+ __isl_take isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ if (!ls->dim->nested[0])
+ return ls;
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ ls->dim = isl_space_flatten_domain(ls->dim);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
+
+/* Remove any internal structure of the range of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_range(
+ __isl_take isl_local_space *ls)
+{
+ if (!ls)
+ return NULL;
+
+ if (!ls->dim->nested[1])
+ return ls;
+
+ ls = isl_local_space_cow(ls);
+ if (!ls)
+ return NULL;
+
+ ls->dim = isl_space_flatten_range(ls->dim);
+ if (!ls->dim)
+ return isl_local_space_free(ls);
+
+ return ls;
+}
Added: polly/trunk/lib/External/isl/isl_local_space_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_local_space_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_local_space_private.h (added)
+++ polly/trunk/lib/External/isl/isl_local_space_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,75 @@
+#ifndef ISL_LOCAL_SPACE_PRIVATE_H
+#define ISL_LOCAL_SPACE_PRIVATE_H
+
+#include <isl/mat.h>
+#include <isl/set.h>
+#include <isl/local_space.h>
+
+struct isl_local_space {
+ int ref;
+
+ isl_space *dim;
+ isl_mat *div;
+};
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+ unsigned n_div);
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+ __isl_take isl_mat *div);
+
+__isl_give isl_local_space *isl_local_space_swap_div(
+ __isl_take isl_local_space *ls, int a, int b);
+__isl_give isl_local_space *isl_local_space_add_div(
+ __isl_take isl_local_space *ls, __isl_take isl_vec *div);
+
+int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j);
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+ __isl_keep isl_mat *div2, int *exp1, int *exp2);
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+ __isl_take isl_local_space *ls, __isl_take isl_mat *div);
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div);
+int isl_local_space_divs_known(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+ __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq);
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+ enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+ __isl_take isl_local_space *ls, __isl_take isl_space *dim);
+__isl_give isl_local_space *isl_local_space_realign(
+ __isl_take isl_local_space *ls, __isl_take isl_reordering *r);
+
+int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+ isl_int *constraint, unsigned div);
+
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l);
+
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+ int first, int n);
+__isl_give isl_local_space *isl_local_space_substitute(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_local_space *isl_local_space_lift(
+ __isl_take isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+ __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma);
+
+__isl_give isl_local_space *isl_local_space_move_dims(
+ __isl_take isl_local_space *ls,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+ __isl_keep isl_local_space *ls2);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_lp.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_lp.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_lp.c (added)
+++ polly/trunk/lib/External/isl/isl_lp.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/lp.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_options_private.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+
+enum isl_lp_result isl_tab_solve_lp(struct isl_basic_map *bmap, int maximize,
+ isl_int *f, isl_int denom, isl_int *opt,
+ isl_int *opt_denom,
+ struct isl_vec **sol)
+{
+ struct isl_tab *tab;
+ enum isl_lp_result res;
+ unsigned dim = isl_basic_map_total_dim(bmap);
+
+ if (maximize)
+ isl_seq_neg(f, f, 1 + dim);
+
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ tab = isl_tab_from_basic_map(bmap, 0);
+ res = isl_tab_min(tab, f, denom, opt, opt_denom, 0);
+ if (res == isl_lp_ok && sol) {
+ *sol = isl_tab_get_sample_value(tab);
+ if (!*sol)
+ res = isl_lp_error;
+ }
+ isl_tab_free(tab);
+
+ if (maximize)
+ isl_seq_neg(f, f, 1 + dim);
+ if (maximize && opt)
+ isl_int_neg(*opt, *opt);
+
+ return res;
+}
+
+/* Given a basic map "bmap" and an affine combination of the variables "f"
+ * with denominator "denom", set *opt / *opt_denom to the minimal
+ * (or maximal if "maximize" is true) value attained by f/d over "bmap",
+ * assuming the basic map is not empty and the expression cannot attain
+ * arbitrarily small (or large) values.
+ * If opt_denom is NULL, then *opt is rounded up (or down)
+ * to the nearest integer.
+ * The return value reflects the nature of the result (empty, unbounded,
+ * minmimal or maximal value returned in *opt).
+ */
+enum isl_lp_result isl_basic_map_solve_lp(struct isl_basic_map *bmap, int max,
+ isl_int *f, isl_int d, isl_int *opt,
+ isl_int *opt_denom,
+ struct isl_vec **sol)
+{
+ if (sol)
+ *sol = NULL;
+
+ if (!bmap)
+ return isl_lp_error;
+
+ return isl_tab_solve_lp(bmap, max, f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_basic_set_solve_lp(struct isl_basic_set *bset, int max,
+ isl_int *f, isl_int d, isl_int *opt,
+ isl_int *opt_denom,
+ struct isl_vec **sol)
+{
+ return isl_basic_map_solve_lp((struct isl_basic_map *)bset, max,
+ f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+ isl_int *f, isl_int d, isl_int *opt,
+ isl_int *opt_denom,
+ struct isl_vec **sol)
+{
+ int i;
+ isl_int o;
+ isl_int t;
+ isl_int opt_i;
+ isl_int opt_denom_i;
+ enum isl_lp_result res;
+ int max_div;
+ isl_vec *v = NULL;
+
+ if (!map)
+ return isl_lp_error;
+ if (map->n == 0)
+ return isl_lp_empty;
+
+ max_div = 0;
+ for (i = 0; i < map->n; ++i)
+ if (map->p[i]->n_div > max_div)
+ max_div = map->p[i]->n_div;
+ if (max_div > 0) {
+ unsigned total = isl_space_dim(map->dim, isl_dim_all);
+ v = isl_vec_alloc(map->ctx, 1 + total + max_div);
+ if (!v)
+ return isl_lp_error;
+ isl_seq_cpy(v->el, f, 1 + total);
+ isl_seq_clr(v->el + 1 + total, max_div);
+ f = v->el;
+ }
+
+ if (!opt && map->n > 1 && sol) {
+ isl_int_init(o);
+ opt = &o;
+ }
+ if (map->n > 0)
+ isl_int_init(opt_i);
+ if (map->n > 0 && opt_denom) {
+ isl_int_init(opt_denom_i);
+ isl_int_init(t);
+ }
+
+ res = isl_basic_map_solve_lp(map->p[0], max, f, d,
+ opt, opt_denom, sol);
+ if (res == isl_lp_error || res == isl_lp_unbounded)
+ goto done;
+
+ if (sol)
+ *sol = NULL;
+
+ for (i = 1; i < map->n; ++i) {
+ isl_vec *sol_i = NULL;
+ enum isl_lp_result res_i;
+ int better;
+
+ res_i = isl_basic_map_solve_lp(map->p[i], max, f, d,
+ &opt_i,
+ opt_denom ? &opt_denom_i : NULL,
+ sol ? &sol_i : NULL);
+ if (res_i == isl_lp_error || res_i == isl_lp_unbounded) {
+ res = res_i;
+ goto done;
+ }
+ if (res_i == isl_lp_empty)
+ continue;
+ if (res == isl_lp_empty) {
+ better = 1;
+ } else if (!opt_denom) {
+ if (max)
+ better = isl_int_gt(opt_i, *opt);
+ else
+ better = isl_int_lt(opt_i, *opt);
+ } else {
+ isl_int_mul(t, opt_i, *opt_denom);
+ isl_int_submul(t, *opt, opt_denom_i);
+ if (max)
+ better = isl_int_is_pos(t);
+ else
+ better = isl_int_is_neg(t);
+ }
+ if (better) {
+ res = res_i;
+ if (opt)
+ isl_int_set(*opt, opt_i);
+ if (opt_denom)
+ isl_int_set(*opt_denom, opt_denom_i);
+ if (sol) {
+ isl_vec_free(*sol);
+ *sol = sol_i;
+ }
+ } else
+ isl_vec_free(sol_i);
+ }
+
+done:
+ isl_vec_free(v);
+ if (map->n > 0 && opt_denom) {
+ isl_int_clear(opt_denom_i);
+ isl_int_clear(t);
+ }
+ if (map->n > 0)
+ isl_int_clear(opt_i);
+ if (opt == &o)
+ isl_int_clear(o);
+ return res;
+}
+
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+ isl_int *f, isl_int d, isl_int *opt,
+ isl_int *opt_denom,
+ struct isl_vec **sol)
+{
+ return isl_map_solve_lp((struct isl_map *)set, max,
+ f, d, opt, opt_denom, sol);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters and divs.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_solve_lp and translate the results.
+ */
+static __isl_give isl_val *basic_set_opt_lp(
+ __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+ isl_ctx *ctx;
+ isl_val *res;
+ enum isl_lp_result lp_res;
+
+ if (!bset || !obj)
+ return NULL;
+
+ ctx = isl_aff_get_ctx(obj);
+ res = isl_val_alloc(ctx);
+ if (!res)
+ return NULL;
+ lp_res = isl_basic_set_solve_lp(bset, max, obj->v->el + 1,
+ obj->v->el[0], &res->n, &res->d, NULL);
+ if (lp_res == isl_lp_ok)
+ return isl_val_normalize(res);
+ isl_val_free(res);
+ if (lp_res == isl_lp_error)
+ return NULL;
+ if (lp_res == isl_lp_empty)
+ return isl_val_nan(ctx);
+ if (max)
+ return isl_val_infty(ctx);
+ else
+ return isl_val_neginfty(ctx);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Align the divs of "bset" and "obj" and call basic_set_opt_lp.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val_aligned(
+ __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+ int *exp1 = NULL;
+ int *exp2 = NULL;
+ isl_ctx *ctx;
+ isl_mat *bset_div = NULL;
+ isl_mat *div = NULL;
+ isl_val *res;
+ int bset_n_div, obj_n_div;
+
+ if (!bset || !obj)
+ return NULL;
+
+ ctx = isl_aff_get_ctx(obj);
+ if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+ isl_die(ctx, isl_error_invalid,
+ "spaces don't match", return NULL);
+
+ bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+ obj_n_div = isl_aff_dim(obj, isl_dim_div);
+ if (bset_n_div == 0 && obj_n_div == 0)
+ return basic_set_opt_lp(bset, max, obj);
+
+ bset = isl_basic_set_copy(bset);
+ obj = isl_aff_copy(obj);
+
+ bset_div = isl_basic_set_get_divs(bset);
+ exp1 = isl_alloc_array(ctx, int, bset_n_div);
+ exp2 = isl_alloc_array(ctx, int, obj_n_div);
+ if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+ goto error;
+
+ div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+ bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+ obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+ res = basic_set_opt_lp(bset, max, obj);
+
+ isl_mat_free(bset_div);
+ isl_mat_free(div);
+ free(exp1);
+ free(exp2);
+ isl_basic_set_free(bset);
+ isl_aff_free(obj);
+
+ return res;
+error:
+ isl_mat_free(div);
+ isl_mat_free(bset_div);
+ free(exp1);
+ free(exp2);
+ isl_basic_set_free(bset);
+ isl_aff_free(obj);
+ return NULL;
+}
+
+/* Return the optimal (rational) value of "obj" over "bset".
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val(
+ __isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+ isl_val *res;
+
+ if (!bset || !obj)
+ return NULL;
+
+ if (isl_space_match(bset->dim, isl_dim_param,
+ obj->ls->dim, isl_dim_param))
+ return isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+ bset = isl_basic_set_copy(bset);
+ obj = isl_aff_copy(obj);
+ bset = isl_basic_set_align_params(bset, isl_aff_get_domain_space(obj));
+ obj = isl_aff_align_params(obj, isl_basic_set_get_space(bset));
+
+ res = isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+ isl_basic_set_free(bset);
+ isl_aff_free(obj);
+
+ return res;
+}
+
+/* Return the minimal (rational) value of "obj" over "bset".
+ *
+ * Return negative infinity if the minimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset,
+ __isl_keep isl_aff *obj)
+{
+ return isl_basic_set_opt_lp_val(bset, 0, obj);
+}
+
+/* Return the maximal (rational) value of "obj" over "bset".
+ *
+ * Return infinity if the maximal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset,
+ __isl_keep isl_aff *obj)
+{
+ return isl_basic_set_opt_lp_val(bset, 1, obj);
+}
Added: polly/trunk/lib/External/isl/isl_lp_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_lp_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_lp_private.h (added)
+++ polly/trunk/lib/External/isl/isl_lp_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,21 @@
+#ifndef ISL_LP_PRIVATE_H
+#define ISL_LP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/vec.h>
+
+enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap,
+ int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+ __isl_give isl_vec **sol);
+enum isl_lp_result isl_basic_set_solve_lp(__isl_keep isl_basic_set *bset,
+ int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+ __isl_give isl_vec **sol);
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+ isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+ __isl_give isl_vec **sol);
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+ isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+ __isl_give isl_vec **sol);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_map.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map.c (added)
+++ polly/trunk/lib/External/isl/isl_map.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,12888 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010 INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014 INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_blk.h>
+#include "isl_space_private.h"
+#include "isl_equalities.h"
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include "isl_sample.h"
+#include <isl_sort.h>
+#include "isl_tab.h"
+#include <isl/vec.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_dim_map.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_options_private.h>
+#include <isl_morph.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/map_int.h>
+#include <isl/deprecated/set_int.h>
+
+static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+ switch (type) {
+ case isl_dim_param: return dim->nparam;
+ case isl_dim_in: return dim->n_in;
+ case isl_dim_out: return dim->n_out;
+ case isl_dim_all: return dim->nparam + dim->n_in + dim->n_out;
+ default: return 0;
+ }
+}
+
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+ switch (type) {
+ case isl_dim_param: return 1;
+ case isl_dim_in: return 1 + dim->nparam;
+ case isl_dim_out: return 1 + dim->nparam + dim->n_in;
+ default: return 0;
+ }
+}
+
+unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type)
+{
+ if (!bmap)
+ return 0;
+ switch (type) {
+ case isl_dim_cst: return 1;
+ case isl_dim_param:
+ case isl_dim_in:
+ case isl_dim_out: return isl_space_dim(bmap->dim, type);
+ case isl_dim_div: return bmap->n_div;
+ case isl_dim_all: return isl_basic_map_total_dim(bmap);
+ default: return 0;
+ }
+}
+
+unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+ return map ? n(map->dim, type) : 0;
+}
+
+unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type)
+{
+ return set ? n(set->dim, type) : 0;
+}
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+ enum isl_dim_type type)
+{
+ isl_space *dim = bmap->dim;
+ switch (type) {
+ case isl_dim_cst: return 0;
+ case isl_dim_param: return 1;
+ case isl_dim_in: return 1 + dim->nparam;
+ case isl_dim_out: return 1 + dim->nparam + dim->n_in;
+ case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
+ default: return 0;
+ }
+}
+
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+ enum isl_dim_type type)
+{
+ return isl_basic_map_offset(bset, type);
+}
+
+static unsigned map_offset(struct isl_map *map, enum isl_dim_type type)
+{
+ return pos(map->dim, type);
+}
+
+unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type)
+{
+ return isl_basic_map_dim(bset, type);
+}
+
+unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_set_dim(bset, isl_dim_set);
+}
+
+unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_set_dim(bset, isl_dim_param);
+}
+
+unsigned isl_basic_set_total_dim(const struct isl_basic_set *bset)
+{
+ if (!bset)
+ return 0;
+ return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div;
+}
+
+unsigned isl_set_n_dim(__isl_keep isl_set *set)
+{
+ return isl_set_dim(set, isl_dim_set);
+}
+
+unsigned isl_set_n_param(__isl_keep isl_set *set)
+{
+ return isl_set_dim(set, isl_dim_param);
+}
+
+unsigned isl_basic_map_n_in(const struct isl_basic_map *bmap)
+{
+ return bmap ? bmap->dim->n_in : 0;
+}
+
+unsigned isl_basic_map_n_out(const struct isl_basic_map *bmap)
+{
+ return bmap ? bmap->dim->n_out : 0;
+}
+
+unsigned isl_basic_map_n_param(const struct isl_basic_map *bmap)
+{
+ return bmap ? bmap->dim->nparam : 0;
+}
+
+unsigned isl_basic_map_n_div(const struct isl_basic_map *bmap)
+{
+ return bmap ? bmap->n_div : 0;
+}
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap)
+{
+ return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0;
+}
+
+unsigned isl_map_n_in(const struct isl_map *map)
+{
+ return map ? map->dim->n_in : 0;
+}
+
+unsigned isl_map_n_out(const struct isl_map *map)
+{
+ return map ? map->dim->n_out : 0;
+}
+
+unsigned isl_map_n_param(const struct isl_map *map)
+{
+ return map ? map->dim->nparam : 0;
+}
+
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set)
+{
+ int m;
+ if (!map || !set)
+ return -1;
+ m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+ if (m < 0 || !m)
+ return m;
+ return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+ set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+ struct isl_basic_set *bset)
+{
+ int m;
+ if (!bmap || !bset)
+ return -1;
+ m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+ if (m < 0 || !m)
+ return m;
+ return isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+ bset->dim, isl_dim_set);
+}
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
+{
+ int m;
+ if (!map || !set)
+ return -1;
+ m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+ if (m < 0 || !m)
+ return m;
+ return isl_space_tuple_is_equal(map->dim, isl_dim_out,
+ set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+ struct isl_basic_set *bset)
+{
+ int m;
+ if (!bmap || !bset)
+ return -1;
+ m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+ if (m < 0 || !m)
+ return m;
+ return isl_space_tuple_is_equal(bmap->dim, isl_dim_out,
+ bset->dim, isl_dim_set);
+}
+
+isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap)
+{
+ return bmap ? bmap->ctx : NULL;
+}
+
+isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset)
+{
+ return bset ? bset->ctx : NULL;
+}
+
+isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map)
+{
+ return map ? map->ctx : NULL;
+}
+
+isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set)
+{
+ return set ? set->ctx : NULL;
+}
+
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+ return isl_space_copy(bmap->dim);
+}
+
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset)
+{
+ if (!bset)
+ return NULL;
+ return isl_space_copy(bset->dim);
+}
+
+/* Extract the divs in "bmap" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap)
+{
+ int i;
+ isl_ctx *ctx;
+ isl_mat *div;
+ unsigned total;
+ unsigned cols;
+
+ if (!bmap)
+ return NULL;
+
+ ctx = isl_basic_map_get_ctx(bmap);
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+ cols = 1 + 1 + total + bmap->n_div;
+ div = isl_mat_alloc(ctx, bmap->n_div, cols);
+ if (!div)
+ return NULL;
+
+ for (i = 0; i < bmap->n_div; ++i)
+ isl_seq_cpy(div->row[i], bmap->div[i], cols);
+
+ return div;
+}
+
+/* Extract the divs in "bset" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_get_divs(bset);
+}
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+ __isl_keep isl_basic_map *bmap)
+{
+ isl_mat *div;
+
+ if (!bmap)
+ return NULL;
+
+ div = isl_basic_map_get_divs(bmap);
+ return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div);
+}
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+ __isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_get_local_space(bset);
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+ __isl_take isl_local_space *ls)
+{
+ int i;
+ int n_div;
+ isl_basic_map *bmap;
+
+ if (!ls)
+ return NULL;
+
+ n_div = isl_local_space_dim(ls, isl_dim_div);
+ bmap = isl_basic_map_alloc_space(isl_local_space_get_space(ls),
+ n_div, 0, 2 * n_div);
+
+ for (i = 0; i < n_div; ++i)
+ if (isl_basic_map_alloc_div(bmap) < 0)
+ goto error;
+
+ for (i = 0; i < n_div; ++i) {
+ isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+ if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+ goto error;
+ }
+
+ isl_local_space_free(ls);
+ return bmap;
+error:
+ isl_local_space_free(ls);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+ __isl_take isl_local_space *ls)
+{
+ return isl_basic_map_from_local_space(ls);
+}
+
+__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map)
+{
+ if (!map)
+ return NULL;
+ return isl_space_copy(map->dim);
+}
+
+__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set)
+{
+ if (!set)
+ return NULL;
+ return isl_space_copy(set->dim);
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_tuple_name(
+ __isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s)
+{
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ bmap->dim = isl_space_set_tuple_name(bmap->dim, type, s);
+ if (!bmap->dim)
+ goto error;
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_tuple_name(
+ __isl_take isl_basic_set *bset, const char *s)
+{
+ return isl_basic_map_set_tuple_name(bset, isl_dim_set, s);
+}
+
+const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type)
+{
+ return bmap ? isl_space_get_tuple_name(bmap->dim, type) : NULL;
+}
+
+__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
+ enum isl_dim_type type, const char *s)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_set_tuple_name(map->dim, type, s);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_set_tuple_name(map->p[i], type, s);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_basic_map *isl_basic_map_set_tuple_id(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, __isl_take isl_id *id)
+{
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ goto error;
+ bmap->dim = isl_space_set_tuple_id(bmap->dim, type, id);
+ if (!bmap->dim)
+ return isl_basic_map_free(bmap);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+/* Replace the identifier of the tuple by "id".
+ */
+__isl_give isl_basic_set *isl_basic_set_set_tuple_id(
+ __isl_take isl_basic_set *bset, __isl_take isl_id *id)
+{
+ return isl_basic_map_set_tuple_id(bset, isl_dim_set, id);
+}
+
+/* Does the input or output tuple have a name?
+ */
+int isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+ return map ? isl_space_has_tuple_name(map->dim, type) : -1;
+}
+
+const char *isl_map_get_tuple_name(__isl_keep isl_map *map,
+ enum isl_dim_type type)
+{
+ return map ? isl_space_get_tuple_name(map->dim, type) : NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
+ const char *s)
+{
+ return (isl_set *)isl_map_set_tuple_name((isl_map *)set, isl_dim_set, s);
+}
+
+__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map,
+ enum isl_dim_type type, __isl_take isl_id *id)
+{
+ map = isl_map_cow(map);
+ if (!map)
+ goto error;
+
+ map->dim = isl_space_set_tuple_id(map->dim, type, id);
+
+ return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
+ __isl_take isl_id *id)
+{
+ return isl_map_set_tuple_id(set, isl_dim_set, id);
+}
+
+__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map,
+ enum isl_dim_type type)
+{
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_reset_tuple_id(map->dim, type);
+
+ return isl_map_reset_space(map, isl_space_copy(map->dim));
+}
+
+__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set)
+{
+ return isl_map_reset_tuple_id(set, isl_dim_set);
+}
+
+int isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+ return map ? isl_space_has_tuple_id(map->dim, type) : -1;
+}
+
+__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map,
+ enum isl_dim_type type)
+{
+ return map ? isl_space_get_tuple_id(map->dim, type) : NULL;
+}
+
+int isl_set_has_tuple_id(__isl_keep isl_set *set)
+{
+ return isl_map_has_tuple_id(set, isl_dim_set);
+}
+
+__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set)
+{
+ return isl_map_get_tuple_id(set, isl_dim_set);
+}
+
+/* Does the set tuple have a name?
+ */
+int isl_set_has_tuple_name(__isl_keep isl_set *set)
+{
+ return set ? isl_space_has_tuple_name(set->dim, isl_dim_set) : -1;
+}
+
+
+const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset)
+{
+ return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_set_get_tuple_name(__isl_keep isl_set *set)
+{
+ return set ? isl_space_get_tuple_name(set->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ return bmap ? isl_space_get_dim_name(bmap->dim, type, pos) : NULL;
+}
+
+const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos)
+{
+ return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_map_has_dim_name(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ return map ? isl_space_has_dim_name(map->dim, type, pos) : -1;
+}
+
+const char *isl_map_get_dim_name(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ return map ? isl_space_get_dim_name(map->dim, type, pos) : NULL;
+}
+
+const char *isl_set_get_dim_name(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_set_has_dim_name(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return set ? isl_space_has_dim_name(set->dim, type, pos) : -1;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_dim_name(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s);
+ if (!bmap->dim)
+ goto error;
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_set_dim_name(map->dim, type, pos, s);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_set_dim_name(map->p[i], type, pos, s);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_dim_name(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ return (isl_basic_set *)isl_basic_map_set_dim_name(
+ (isl_basic_map *)bset, type, pos, s);
+}
+
+__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, const char *s)
+{
+ return (isl_set *)isl_map_set_dim_name((isl_map *)set, type, pos, s);
+}
+
+int isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ return bmap ? isl_space_has_dim_id(bmap->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos)
+{
+ return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL;
+}
+
+int isl_map_has_dim_id(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ return map ? isl_space_has_dim_id(map->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ return map ? isl_space_get_dim_id(map->dim, type, pos) : NULL;
+}
+
+int isl_set_has_dim_id(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_map_has_dim_id(set, type, pos);
+}
+
+__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_map_get_dim_id(set, type, pos);
+}
+
+__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+ map = isl_map_cow(map);
+ if (!map)
+ goto error;
+
+ map->dim = isl_space_set_dim_id(map->dim, type, pos, id);
+
+ return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+ isl_id_free(id);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+ return isl_map_set_dim_id(set, type, pos, id);
+}
+
+int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type,
+ __isl_keep isl_id *id)
+{
+ if (!map)
+ return -1;
+ return isl_space_find_dim_by_id(map->dim, type, id);
+}
+
+int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
+ __isl_keep isl_id *id)
+{
+ return isl_map_find_dim_by_id(set, type, id);
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "bmap".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, const char *name)
+{
+ if (!bmap)
+ return -1;
+ return isl_space_find_dim_by_name(bmap->dim, type, name);
+}
+
+int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type,
+ const char *name)
+{
+ if (!map)
+ return -1;
+ return isl_space_find_dim_by_name(map->dim, type, name);
+}
+
+int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type,
+ const char *name)
+{
+ return isl_map_find_dim_by_name(set, type, name);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "map".
+ */
+__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map)
+{
+ isl_space *space;
+
+ space = isl_map_get_space(map);
+ space = isl_space_reset_user(space);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "set".
+ */
+__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set)
+{
+ return isl_map_reset_user(set);
+}
+
+int isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+}
+
+int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_is_rational(bset);
+}
+
+/* Does "bmap" contain any rational points?
+ *
+ * If "bmap" has an equality for each dimension, equating the dimension
+ * to an integer constant, then it has no rational points, even if it
+ * is marked as rational.
+ */
+int isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap)
+{
+ int has_rational = 1;
+ unsigned total;
+
+ if (!bmap)
+ return -1;
+ if (isl_basic_map_plain_is_empty(bmap))
+ return 0;
+ if (!isl_basic_map_is_rational(bmap))
+ return 0;
+ bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_implicit_equalities(bmap);
+ if (!bmap)
+ return -1;
+ total = isl_basic_map_total_dim(bmap);
+ if (bmap->n_eq == total) {
+ int i, j;
+ for (i = 0; i < bmap->n_eq; ++i) {
+ j = isl_seq_first_non_zero(bmap->eq[i] + 1, total);
+ if (j < 0)
+ break;
+ if (!isl_int_is_one(bmap->eq[i][1 + j]) &&
+ !isl_int_is_negone(bmap->eq[i][1 + j]))
+ break;
+ j = isl_seq_first_non_zero(bmap->eq[i] + 1 + j + 1,
+ total - j - 1);
+ if (j >= 0)
+ break;
+ }
+ if (i == bmap->n_eq)
+ has_rational = 0;
+ }
+ isl_basic_map_free(bmap);
+
+ return has_rational;
+}
+
+/* Does "map" contain any rational points?
+ */
+int isl_map_has_rational(__isl_keep isl_map *map)
+{
+ int i;
+ int has_rational;
+
+ if (!map)
+ return -1;
+ for (i = 0; i < map->n; ++i) {
+ has_rational = isl_basic_map_has_rational(map->p[i]);
+ if (has_rational < 0)
+ return -1;
+ if (has_rational)
+ return 1;
+ }
+ return 0;
+}
+
+/* Does "set" contain any rational points?
+ */
+int isl_set_has_rational(__isl_keep isl_set *set)
+{
+ return isl_map_has_rational(set);
+}
+
+/* Is this basic set a parameter domain?
+ */
+int isl_basic_set_is_params(__isl_keep isl_basic_set *bset)
+{
+ if (!bset)
+ return -1;
+ return isl_space_is_params(bset->dim);
+}
+
+/* Is this set a parameter domain?
+ */
+int isl_set_is_params(__isl_keep isl_set *set)
+{
+ if (!set)
+ return -1;
+ return isl_space_is_params(set->dim);
+}
+
+/* Is this map actually a parameter domain?
+ * Users should never call this function. Outside of isl,
+ * a map can never be a parameter domain.
+ */
+int isl_map_is_params(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+ return isl_space_is_params(map->dim);
+}
+
+static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx,
+ struct isl_basic_map *bmap, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ int i;
+ size_t row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + extra;
+
+ bmap->ctx = ctx;
+ isl_ctx_ref(ctx);
+
+ bmap->block = isl_blk_alloc(ctx, (n_ineq + n_eq) * row_size);
+ if (isl_blk_is_error(bmap->block))
+ goto error;
+
+ bmap->ineq = isl_alloc_array(ctx, isl_int *, n_ineq + n_eq);
+ if ((n_ineq + n_eq) && !bmap->ineq)
+ goto error;
+
+ if (extra == 0) {
+ bmap->block2 = isl_blk_empty();
+ bmap->div = NULL;
+ } else {
+ bmap->block2 = isl_blk_alloc(ctx, extra * (1 + row_size));
+ if (isl_blk_is_error(bmap->block2))
+ goto error;
+
+ bmap->div = isl_alloc_array(ctx, isl_int *, extra);
+ if (!bmap->div)
+ goto error;
+ }
+
+ for (i = 0; i < n_ineq + n_eq; ++i)
+ bmap->ineq[i] = bmap->block.data + i * row_size;
+
+ for (i = 0; i < extra; ++i)
+ bmap->div[i] = bmap->block2.data + i * (1 + row_size);
+
+ bmap->ref = 1;
+ bmap->flags = 0;
+ bmap->c_size = n_eq + n_ineq;
+ bmap->eq = bmap->ineq + n_ineq;
+ bmap->extra = extra;
+ bmap->n_eq = 0;
+ bmap->n_ineq = 0;
+ bmap->n_div = 0;
+ bmap->sample = NULL;
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_alloc(struct isl_ctx *ctx,
+ unsigned nparam, unsigned dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *bmap;
+ isl_space *space;
+
+ space = isl_space_set_alloc(ctx, nparam, dim);
+ if (!space)
+ return NULL;
+
+ bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq);
+ return (struct isl_basic_set *)bmap;
+}
+
+struct isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+ unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *bmap;
+ if (!dim)
+ return NULL;
+ isl_assert(dim->ctx, dim->n_in == 0, goto error);
+ bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+ return (struct isl_basic_set *)bmap;
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+ unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *bmap;
+
+ if (!dim)
+ return NULL;
+ bmap = isl_calloc_type(dim->ctx, struct isl_basic_map);
+ if (!bmap)
+ goto error;
+ bmap->dim = dim;
+
+ return basic_map_init(dim->ctx, bmap, extra, n_eq, n_ineq);
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc(struct isl_ctx *ctx,
+ unsigned nparam, unsigned in, unsigned out, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *bmap;
+ isl_space *dim;
+
+ dim = isl_space_alloc(ctx, nparam, in, out);
+ if (!dim)
+ return NULL;
+
+ bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+ return bmap;
+}
+
+static void dup_constraints(
+ struct isl_basic_map *dst, struct isl_basic_map *src)
+{
+ int i;
+ unsigned total = isl_basic_map_total_dim(src);
+
+ for (i = 0; i < src->n_eq; ++i) {
+ int j = isl_basic_map_alloc_equality(dst);
+ isl_seq_cpy(dst->eq[j], src->eq[i], 1+total);
+ }
+
+ for (i = 0; i < src->n_ineq; ++i) {
+ int j = isl_basic_map_alloc_inequality(dst);
+ isl_seq_cpy(dst->ineq[j], src->ineq[i], 1+total);
+ }
+
+ for (i = 0; i < src->n_div; ++i) {
+ int j = isl_basic_map_alloc_div(dst);
+ isl_seq_cpy(dst->div[j], src->div[i], 1+1+total);
+ }
+ ISL_F_SET(dst, ISL_BASIC_SET_FINAL);
+}
+
+struct isl_basic_map *isl_basic_map_dup(struct isl_basic_map *bmap)
+{
+ struct isl_basic_map *dup;
+
+ if (!bmap)
+ return NULL;
+ dup = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+ bmap->n_div, bmap->n_eq, bmap->n_ineq);
+ if (!dup)
+ return NULL;
+ dup_constraints(dup, bmap);
+ dup->flags = bmap->flags;
+ dup->sample = isl_vec_copy(bmap->sample);
+ return dup;
+}
+
+struct isl_basic_set *isl_basic_set_dup(struct isl_basic_set *bset)
+{
+ struct isl_basic_map *dup;
+
+ dup = isl_basic_map_dup((struct isl_basic_map *)bset);
+ return (struct isl_basic_set *)dup;
+}
+
+struct isl_basic_set *isl_basic_set_copy(struct isl_basic_set *bset)
+{
+ if (!bset)
+ return NULL;
+
+ if (ISL_F_ISSET(bset, ISL_BASIC_SET_FINAL)) {
+ bset->ref++;
+ return bset;
+ }
+ return isl_basic_set_dup(bset);
+}
+
+struct isl_set *isl_set_copy(struct isl_set *set)
+{
+ if (!set)
+ return NULL;
+
+ set->ref++;
+ return set;
+}
+
+struct isl_basic_map *isl_basic_map_copy(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL)) {
+ bmap->ref++;
+ return bmap;
+ }
+ bmap = isl_basic_map_dup(bmap);
+ if (bmap)
+ ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+ return bmap;
+}
+
+struct isl_map *isl_map_copy(struct isl_map *map)
+{
+ if (!map)
+ return NULL;
+
+ map->ref++;
+ return map;
+}
+
+__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (--bmap->ref > 0)
+ return NULL;
+
+ isl_ctx_deref(bmap->ctx);
+ free(bmap->div);
+ isl_blk_free(bmap->ctx, bmap->block2);
+ free(bmap->ineq);
+ isl_blk_free(bmap->ctx, bmap->block);
+ isl_vec_free(bmap->sample);
+ isl_space_free(bmap->dim);
+ free(bmap);
+
+ return NULL;
+}
+
+__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_free((struct isl_basic_map *)bset);
+}
+
+static int room_for_con(struct isl_basic_map *bmap, unsigned n)
+{
+ return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size;
+}
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+ __isl_take isl_map *map1, __isl_take isl_map *map2,
+ __isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+ __isl_take isl_map *map2))
+{
+ if (!map1 || !map2)
+ goto error;
+ if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+ return fn(map1, map2);
+ if (!isl_space_has_named_params(map1->dim) ||
+ !isl_space_has_named_params(map2->dim))
+ isl_die(map1->ctx, isl_error_invalid,
+ "unaligned unnamed parameters", goto error);
+ map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+ map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+ return fn(map1, map2);
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+ __isl_keep isl_map *map2,
+ int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2))
+{
+ int r;
+
+ if (!map1 || !map2)
+ return -1;
+ if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+ return fn(map1, map2);
+ if (!isl_space_has_named_params(map1->dim) ||
+ !isl_space_has_named_params(map2->dim))
+ isl_die(map1->ctx, isl_error_invalid,
+ "unaligned unnamed parameters", return -1);
+ map1 = isl_map_copy(map1);
+ map2 = isl_map_copy(map2);
+ map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+ map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+ r = fn(map1, map2);
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return r;
+}
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap)
+{
+ struct isl_ctx *ctx;
+ if (!bmap)
+ return -1;
+ ctx = bmap->ctx;
+ isl_assert(ctx, room_for_con(bmap, 1), return -1);
+ isl_assert(ctx, (bmap->eq - bmap->ineq) + bmap->n_eq <= bmap->c_size,
+ return -1);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+ if ((bmap->eq - bmap->ineq) + bmap->n_eq == bmap->c_size) {
+ isl_int *t;
+ int j = isl_basic_map_alloc_inequality(bmap);
+ if (j < 0)
+ return -1;
+ t = bmap->ineq[j];
+ bmap->ineq[j] = bmap->ineq[bmap->n_ineq - 1];
+ bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+ bmap->eq[-1] = t;
+ bmap->n_eq++;
+ bmap->n_ineq--;
+ bmap->eq--;
+ return 0;
+ }
+ isl_seq_clr(bmap->eq[bmap->n_eq] + 1 + isl_basic_map_total_dim(bmap),
+ bmap->extra - bmap->n_div);
+ return bmap->n_eq++;
+}
+
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset)
+{
+ return isl_basic_map_alloc_equality((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n)
+{
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, n <= bmap->n_eq, return -1);
+ bmap->n_eq -= n;
+ return 0;
+}
+
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n)
+{
+ return isl_basic_map_free_equality((struct isl_basic_map *)bset, n);
+}
+
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos)
+{
+ isl_int *t;
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, pos < bmap->n_eq, return -1);
+
+ if (pos != bmap->n_eq - 1) {
+ t = bmap->eq[pos];
+ bmap->eq[pos] = bmap->eq[bmap->n_eq - 1];
+ bmap->eq[bmap->n_eq - 1] = t;
+ }
+ bmap->n_eq--;
+ return 0;
+}
+
+int isl_basic_set_drop_equality(struct isl_basic_set *bset, unsigned pos)
+{
+ return isl_basic_map_drop_equality((struct isl_basic_map *)bset, pos);
+}
+
+/* Turn inequality "pos" of "bmap" into an equality.
+ *
+ * In particular, we move the inequality in front of the equalities
+ * and move the last inequality in the position of the moved inequality.
+ * Note that isl_tab_make_equalities_explicit depends on this particular
+ * change in the ordering of the constraints.
+ */
+void isl_basic_map_inequality_to_equality(
+ struct isl_basic_map *bmap, unsigned pos)
+{
+ isl_int *t;
+
+ t = bmap->ineq[pos];
+ bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+ bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+ bmap->eq[-1] = t;
+ bmap->n_eq++;
+ bmap->n_ineq--;
+ bmap->eq--;
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+}
+
+static int room_for_ineq(struct isl_basic_map *bmap, unsigned n)
+{
+ return bmap->n_ineq + n <= bmap->eq - bmap->ineq;
+}
+
+int isl_basic_map_alloc_inequality(struct isl_basic_map *bmap)
+{
+ struct isl_ctx *ctx;
+ if (!bmap)
+ return -1;
+ ctx = bmap->ctx;
+ isl_assert(ctx, room_for_ineq(bmap, 1), return -1);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+ isl_seq_clr(bmap->ineq[bmap->n_ineq] +
+ 1 + isl_basic_map_total_dim(bmap),
+ bmap->extra - bmap->n_div);
+ return bmap->n_ineq++;
+}
+
+int isl_basic_set_alloc_inequality(struct isl_basic_set *bset)
+{
+ return isl_basic_map_alloc_inequality((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n)
+{
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, n <= bmap->n_ineq, return -1);
+ bmap->n_ineq -= n;
+ return 0;
+}
+
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n)
+{
+ return isl_basic_map_free_inequality((struct isl_basic_map *)bset, n);
+}
+
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos)
+{
+ isl_int *t;
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+
+ if (pos != bmap->n_ineq - 1) {
+ t = bmap->ineq[pos];
+ bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+ bmap->ineq[bmap->n_ineq - 1] = t;
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ }
+ bmap->n_ineq--;
+ return 0;
+}
+
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos)
+{
+ return isl_basic_map_drop_inequality((struct isl_basic_map *)bset, pos);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+ isl_int *eq)
+{
+ int k;
+
+ bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+ if (!bmap)
+ return NULL;
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bmap->eq[k], eq, 1 + isl_basic_map_total_dim(bmap));
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+ isl_int *eq)
+{
+ return (isl_basic_set *)
+ isl_basic_map_add_eq((isl_basic_map *)bset, eq);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+ isl_int *ineq)
+{
+ int k;
+
+ bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+ if (!bmap)
+ return NULL;
+ k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bmap->ineq[k], ineq, 1 + isl_basic_map_total_dim(bmap));
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+ isl_int *ineq)
+{
+ return (isl_basic_set *)
+ isl_basic_map_add_ineq((isl_basic_map *)bset, ineq);
+}
+
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, bmap->n_div < bmap->extra, return -1);
+ isl_seq_clr(bmap->div[bmap->n_div] +
+ 1 + 1 + isl_basic_map_total_dim(bmap),
+ bmap->extra - bmap->n_div);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+ return bmap->n_div++;
+}
+
+int isl_basic_set_alloc_div(struct isl_basic_set *bset)
+{
+ return isl_basic_map_alloc_div((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n)
+{
+ if (!bmap)
+ return -1;
+ isl_assert(bmap->ctx, n <= bmap->n_div, return -1);
+ bmap->n_div -= n;
+ return 0;
+}
+
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n)
+{
+ return isl_basic_map_free_div((struct isl_basic_map *)bset, n);
+}
+
+/* Copy constraint from src to dst, putting the vars of src at offset
+ * dim_off in dst and the divs of src at offset div_off in dst.
+ * If both sets are actually map, then dim_off applies to the input
+ * variables.
+ */
+static void copy_constraint(struct isl_basic_map *dst_map, isl_int *dst,
+ struct isl_basic_map *src_map, isl_int *src,
+ unsigned in_off, unsigned out_off, unsigned div_off)
+{
+ unsigned src_nparam = isl_basic_map_n_param(src_map);
+ unsigned dst_nparam = isl_basic_map_n_param(dst_map);
+ unsigned src_in = isl_basic_map_n_in(src_map);
+ unsigned dst_in = isl_basic_map_n_in(dst_map);
+ unsigned src_out = isl_basic_map_n_out(src_map);
+ unsigned dst_out = isl_basic_map_n_out(dst_map);
+ isl_int_set(dst[0], src[0]);
+ isl_seq_cpy(dst+1, src+1, isl_min(dst_nparam, src_nparam));
+ if (dst_nparam > src_nparam)
+ isl_seq_clr(dst+1+src_nparam,
+ dst_nparam - src_nparam);
+ isl_seq_clr(dst+1+dst_nparam, in_off);
+ isl_seq_cpy(dst+1+dst_nparam+in_off,
+ src+1+src_nparam,
+ isl_min(dst_in-in_off, src_in));
+ if (dst_in-in_off > src_in)
+ isl_seq_clr(dst+1+dst_nparam+in_off+src_in,
+ dst_in - in_off - src_in);
+ isl_seq_clr(dst+1+dst_nparam+dst_in, out_off);
+ isl_seq_cpy(dst+1+dst_nparam+dst_in+out_off,
+ src+1+src_nparam+src_in,
+ isl_min(dst_out-out_off, src_out));
+ if (dst_out-out_off > src_out)
+ isl_seq_clr(dst+1+dst_nparam+dst_in+out_off+src_out,
+ dst_out - out_off - src_out);
+ isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out, div_off);
+ isl_seq_cpy(dst+1+dst_nparam+dst_in+dst_out+div_off,
+ src+1+src_nparam+src_in+src_out,
+ isl_min(dst_map->extra-div_off, src_map->n_div));
+ if (dst_map->n_div-div_off > src_map->n_div)
+ isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out+
+ div_off+src_map->n_div,
+ dst_map->n_div - div_off - src_map->n_div);
+}
+
+static void copy_div(struct isl_basic_map *dst_map, isl_int *dst,
+ struct isl_basic_map *src_map, isl_int *src,
+ unsigned in_off, unsigned out_off, unsigned div_off)
+{
+ isl_int_set(dst[0], src[0]);
+ copy_constraint(dst_map, dst+1, src_map, src+1, in_off, out_off, div_off);
+}
+
+static struct isl_basic_map *add_constraints(struct isl_basic_map *bmap1,
+ struct isl_basic_map *bmap2, unsigned i_pos, unsigned o_pos)
+{
+ int i;
+ unsigned div_off;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ div_off = bmap1->n_div;
+
+ for (i = 0; i < bmap2->n_eq; ++i) {
+ int i1 = isl_basic_map_alloc_equality(bmap1);
+ if (i1 < 0)
+ goto error;
+ copy_constraint(bmap1, bmap1->eq[i1], bmap2, bmap2->eq[i],
+ i_pos, o_pos, div_off);
+ }
+
+ for (i = 0; i < bmap2->n_ineq; ++i) {
+ int i1 = isl_basic_map_alloc_inequality(bmap1);
+ if (i1 < 0)
+ goto error;
+ copy_constraint(bmap1, bmap1->ineq[i1], bmap2, bmap2->ineq[i],
+ i_pos, o_pos, div_off);
+ }
+
+ for (i = 0; i < bmap2->n_div; ++i) {
+ int i1 = isl_basic_map_alloc_div(bmap1);
+ if (i1 < 0)
+ goto error;
+ copy_div(bmap1, bmap1->div[i1], bmap2, bmap2->div[i],
+ i_pos, o_pos, div_off);
+ }
+
+ isl_basic_map_free(bmap2);
+
+ return bmap1;
+
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+ struct isl_basic_set *bset2, unsigned pos)
+{
+ return (struct isl_basic_set *)
+ add_constraints((struct isl_basic_map *)bset1,
+ (struct isl_basic_map *)bset2, 0, pos);
+}
+
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+ __isl_take isl_space *dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *ext;
+ unsigned flags;
+ int dims_ok;
+
+ if (!dim)
+ goto error;
+
+ if (!base)
+ goto error;
+
+ dims_ok = isl_space_is_equal(base->dim, dim) &&
+ base->extra >= base->n_div + extra;
+
+ if (dims_ok && room_for_con(base, n_eq + n_ineq) &&
+ room_for_ineq(base, n_ineq)) {
+ isl_space_free(dim);
+ return base;
+ }
+
+ isl_assert(base->ctx, base->dim->nparam <= dim->nparam, goto error);
+ isl_assert(base->ctx, base->dim->n_in <= dim->n_in, goto error);
+ isl_assert(base->ctx, base->dim->n_out <= dim->n_out, goto error);
+ extra += base->extra;
+ n_eq += base->n_eq;
+ n_ineq += base->n_ineq;
+
+ ext = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+ dim = NULL;
+ if (!ext)
+ goto error;
+
+ if (dims_ok)
+ ext->sample = isl_vec_copy(base->sample);
+ flags = base->flags;
+ ext = add_constraints(ext, base, 0, 0);
+ if (ext) {
+ ext->flags = flags;
+ ISL_F_CLR(ext, ISL_BASIC_SET_FINAL);
+ }
+
+ return ext;
+
+error:
+ isl_space_free(dim);
+ isl_basic_map_free(base);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+ __isl_take isl_space *dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_extend_space((struct isl_basic_map *)base, dim,
+ extra, n_eq, n_ineq);
+}
+
+struct isl_basic_map *isl_basic_map_extend_constraints(
+ struct isl_basic_map *base, unsigned n_eq, unsigned n_ineq)
+{
+ if (!base)
+ return NULL;
+ return isl_basic_map_extend_space(base, isl_space_copy(base->dim),
+ 0, n_eq, n_ineq);
+}
+
+struct isl_basic_map *isl_basic_map_extend(struct isl_basic_map *base,
+ unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ struct isl_basic_map *bmap;
+ isl_space *dim;
+
+ if (!base)
+ return NULL;
+ dim = isl_space_alloc(base->ctx, nparam, n_in, n_out);
+ if (!dim)
+ goto error;
+
+ bmap = isl_basic_map_extend_space(base, dim, extra, n_eq, n_ineq);
+ return bmap;
+error:
+ isl_basic_map_free(base);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_extend(struct isl_basic_set *base,
+ unsigned nparam, unsigned dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_extend((struct isl_basic_map *)base,
+ nparam, 0, dim, extra, n_eq, n_ineq);
+}
+
+struct isl_basic_set *isl_basic_set_extend_constraints(
+ struct isl_basic_set *base, unsigned n_eq, unsigned n_ineq)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_extend_constraints((struct isl_basic_map *)base,
+ n_eq, n_ineq);
+}
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_cow((struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (bmap->ref > 1) {
+ bmap->ref--;
+ bmap = isl_basic_map_dup(bmap);
+ }
+ if (bmap)
+ ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL);
+ return bmap;
+}
+
+struct isl_set *isl_set_cow(struct isl_set *set)
+{
+ if (!set)
+ return NULL;
+
+ if (set->ref == 1)
+ return set;
+ set->ref--;
+ return isl_set_dup(set);
+}
+
+struct isl_map *isl_map_cow(struct isl_map *map)
+{
+ if (!map)
+ return NULL;
+
+ if (map->ref == 1)
+ return map;
+ map->ref--;
+ return isl_map_dup(map);
+}
+
+static void swap_vars(struct isl_blk blk, isl_int *a,
+ unsigned a_len, unsigned b_len)
+{
+ isl_seq_cpy(blk.data, a+a_len, b_len);
+ isl_seq_cpy(blk.data+b_len, a, a_len);
+ isl_seq_cpy(a, blk.data, b_len+a_len);
+}
+
+static __isl_give isl_basic_map *isl_basic_map_swap_vars(
+ __isl_take isl_basic_map *bmap, unsigned pos, unsigned n1, unsigned n2)
+{
+ int i;
+ struct isl_blk blk;
+
+ if (!bmap)
+ goto error;
+
+ isl_assert(bmap->ctx,
+ pos + n1 + n2 <= 1 + isl_basic_map_total_dim(bmap), goto error);
+
+ if (n1 == 0 || n2 == 0)
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ blk = isl_blk_alloc(bmap->ctx, n1 + n2);
+ if (isl_blk_is_error(blk))
+ goto error;
+
+ for (i = 0; i < bmap->n_eq; ++i)
+ swap_vars(blk,
+ bmap->eq[i] + pos, n1, n2);
+
+ for (i = 0; i < bmap->n_ineq; ++i)
+ swap_vars(blk,
+ bmap->ineq[i] + pos, n1, n2);
+
+ for (i = 0; i < bmap->n_div; ++i)
+ swap_vars(blk,
+ bmap->div[i]+1 + pos, n1, n2);
+
+ isl_blk_free(bmap->ctx, blk);
+
+ ISL_F_CLR(bmap, ISL_BASIC_SET_NORMALIZED);
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static __isl_give isl_basic_set *isl_basic_set_swap_vars(
+ __isl_take isl_basic_set *bset, unsigned n)
+{
+ unsigned dim;
+ unsigned nparam;
+
+ if (!bset)
+ return NULL;
+
+ nparam = isl_basic_set_n_param(bset);
+ dim = isl_basic_set_n_dim(bset);
+ isl_assert(bset->ctx, n <= dim, goto error);
+
+ return isl_basic_map_swap_vars(bset, 1 + nparam, n, dim - n);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap)
+{
+ int i = 0;
+ unsigned total;
+ if (!bmap)
+ goto error;
+ total = isl_basic_map_total_dim(bmap);
+ isl_basic_map_free_div(bmap, bmap->n_div);
+ isl_basic_map_free_inequality(bmap, bmap->n_ineq);
+ if (bmap->n_eq > 0)
+ isl_basic_map_free_equality(bmap, bmap->n_eq-1);
+ else {
+ i = isl_basic_map_alloc_equality(bmap);
+ if (i < 0)
+ goto error;
+ }
+ isl_int_set_si(bmap->eq[i][0], 1);
+ isl_seq_clr(bmap->eq[i]+1, total);
+ ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+ isl_vec_free(bmap->sample);
+ bmap->sample = NULL;
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_set_to_empty((struct isl_basic_map *)bset);
+}
+
+/* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints
+ * of "bmap").
+ */
+static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b)
+{
+ isl_int *t = bmap->div[a];
+ bmap->div[a] = bmap->div[b];
+ bmap->div[b] = t;
+}
+
+/* Swap divs "a" and "b" in "bmap" and adjust the constraints and
+ * div definitions accordingly.
+ */
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
+{
+ int i;
+ unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
+
+ swap_div(bmap, a, b);
+
+ for (i = 0; i < bmap->n_eq; ++i)
+ isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]);
+
+ for (i = 0; i < bmap->n_ineq; ++i)
+ isl_int_swap(bmap->ineq[i][1+off+a], bmap->ineq[i][1+off+b]);
+
+ for (i = 0; i < bmap->n_div; ++i)
+ isl_int_swap(bmap->div[i][1+1+off+a], bmap->div[i][1+1+off+b]);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (n == 0)
+ return map;
+
+ if (first + n > isl_map_dim(map, type) || first + n < first)
+ isl_die(map->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n);
+ if (!map->p[i])
+ goto error;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_set *)isl_map_eliminate((isl_map *)set, type, first, n);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set,
+ unsigned first, unsigned n)
+{
+ return isl_set_eliminate(set, isl_dim_set, first, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_divs(
+ __isl_take isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+ bmap = isl_basic_map_eliminate_vars(bmap,
+ isl_space_dim(bmap->dim, isl_dim_all), bmap->n_div);
+ if (!bmap)
+ return NULL;
+ bmap->n_div = 0;
+ return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs(
+ __isl_take isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)isl_basic_map_remove_divs(
+ (struct isl_basic_map *)bset);
+}
+
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0)
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_remove_divs(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set)
+{
+ return isl_map_remove_divs(set);
+}
+
+struct isl_basic_map *isl_basic_map_remove_dims(struct isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ if (!bmap)
+ return NULL;
+ isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+ goto error);
+ if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+ return bmap;
+ bmap = isl_basic_map_eliminate_vars(bmap,
+ isl_basic_map_offset(bmap, type) - 1 + first, n);
+ if (!bmap)
+ return bmap;
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY) && type == isl_dim_div)
+ return bmap;
+ bmap = isl_basic_map_drop(bmap, type, first, n);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Return true if the definition of the given div (recursively) involves
+ * any of the given variables.
+ */
+static int div_involves_vars(__isl_keep isl_basic_map *bmap, int div,
+ unsigned first, unsigned n)
+{
+ int i;
+ unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return 0;
+ if (isl_seq_first_non_zero(bmap->div[div] + 1 + first, n) >= 0)
+ return 1;
+
+ for (i = bmap->n_div - 1; i >= 0; --i) {
+ if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+ continue;
+ if (div_involves_vars(bmap, i, first, n))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Try and add a lower and/or upper bound on "div" to "bmap"
+ * based on inequality "i".
+ * "total" is the total number of variables (excluding the divs).
+ * "v" is a temporary object that can be used during the calculations.
+ * If "lb" is set, then a lower bound should be constructed.
+ * If "ub" is set, then an upper bound should be constructed.
+ *
+ * The calling function has already checked that the inequality does not
+ * reference "div", but we still need to check that the inequality is
+ * of the right form. We'll consider the case where we want to construct
+ * a lower bound. The construction of upper bounds is similar.
+ *
+ * Let "div" be of the form
+ *
+ * q = floor((a + f(x))/d)
+ *
+ * We essentially check if constraint "i" is of the form
+ *
+ * b + f(x) >= 0
+ *
+ * so that we can use it to derive a lower bound on "div".
+ * However, we allow a slightly more general form
+ *
+ * b + g(x) >= 0
+ *
+ * with the condition that the coefficients of g(x) - f(x) are all
+ * divisible by d.
+ * Rewriting this constraint as
+ *
+ * 0 >= -b - g(x)
+ *
+ * adding a + f(x) to both sides and dividing by d, we obtain
+ *
+ * (a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d
+ *
+ * Taking the floor on both sides, we obtain
+ *
+ * q >= floor((a-b)/d) + (f(x)-g(x))/d
+ *
+ * or
+ *
+ * (g(x)-f(x))/d + ceil((b-a)/d) + q >= 0
+ *
+ * In the case of an upper bound, we construct the constraint
+ *
+ * (g(x)+f(x))/d + floor((b+a)/d) - q >= 0
+ *
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq(
+ __isl_take isl_basic_map *bmap, int div, int i,
+ unsigned total, isl_int v, int lb, int ub)
+{
+ int j;
+
+ for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) {
+ if (lb) {
+ isl_int_sub(v, bmap->ineq[i][1 + j],
+ bmap->div[div][1 + 1 + j]);
+ lb = isl_int_is_divisible_by(v, bmap->div[div][0]);
+ }
+ if (ub) {
+ isl_int_add(v, bmap->ineq[i][1 + j],
+ bmap->div[div][1 + 1 + j]);
+ ub = isl_int_is_divisible_by(v, bmap->div[div][0]);
+ }
+ }
+ if (!lb && !ub)
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub);
+ if (lb) {
+ int k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+ isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j],
+ bmap->div[div][1 + j]);
+ isl_int_cdiv_q(bmap->ineq[k][j],
+ bmap->ineq[k][j], bmap->div[div][0]);
+ }
+ isl_int_set_si(bmap->ineq[k][1 + total + div], 1);
+ }
+ if (ub) {
+ int k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+ isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j],
+ bmap->div[div][1 + j]);
+ isl_int_fdiv_q(bmap->ineq[k][j],
+ bmap->ineq[k][j], bmap->div[div][0]);
+ }
+ isl_int_set_si(bmap->ineq[k][1 + total + div], -1);
+ }
+
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* This function is called right before "div" is eliminated from "bmap"
+ * using Fourier-Motzkin.
+ * Look through the constraints of "bmap" for constraints on the argument
+ * of the integer division and use them to construct constraints on the
+ * integer division itself. These constraints can then be combined
+ * during the Fourier-Motzkin elimination.
+ * Note that it is only useful to introduce lower bounds on "div"
+ * if "bmap" already contains upper bounds on "div" as the newly
+ * introduce lower bounds can then be combined with the pre-existing
+ * upper bounds. Similarly for upper bounds.
+ * We therefore first check if "bmap" contains any lower and/or upper bounds
+ * on "div".
+ *
+ * It is interesting to note that the introduction of these constraints
+ * can indeed lead to more accurate results, even when compared to
+ * deriving constraints on the argument of "div" from constraints on "div".
+ * Consider, for example, the set
+ *
+ * { [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }
+ *
+ * The second constraint can be rewritten as
+ *
+ * 2 * [(-i-2j+3)/4] + k >= 0
+ *
+ * from which we can derive
+ *
+ * -i - 2j + 3 >= -2k
+ *
+ * or
+ *
+ * i + 2j <= 3 + 2k
+ *
+ * Combined with the first constraint, we obtain
+ *
+ * -3 <= 3 + 2k or k >= -3
+ *
+ * If, on the other hand we derive a constraint on [(i+2j)/4] from
+ * the first constraint, we obtain
+ *
+ * [(i + 2j)/4] >= [-3/4] = -1
+ *
+ * Combining this constraint with the second constraint, we obtain
+ *
+ * k >= -2
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div(
+ __isl_take isl_basic_map *bmap, int div)
+{
+ int i;
+ int check_lb, check_ub;
+ isl_int v;
+ unsigned total;
+
+ if (!bmap)
+ return NULL;
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return bmap;
+
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+
+ check_lb = 0;
+ check_ub = 0;
+ for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) {
+ int s = isl_int_sgn(bmap->ineq[i][1 + total + div]);
+ if (s > 0)
+ check_ub = 1;
+ if (s < 0)
+ check_lb = 1;
+ }
+
+ if (!check_lb && !check_ub)
+ return bmap;
+
+ isl_int_init(v);
+
+ for (i = 0; bmap && i < bmap->n_ineq; ++i) {
+ if (!isl_int_is_zero(bmap->ineq[i][1 + total + div]))
+ continue;
+
+ bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v,
+ check_lb, check_ub);
+ }
+
+ isl_int_clear(v);
+
+ return bmap;
+}
+
+/* Remove all divs (recursively) involving any of the given dimensions
+ * in their definitions.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+ isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+ goto error);
+ first += isl_basic_map_offset(bmap, type);
+
+ for (i = bmap->n_div - 1; i >= 0; --i) {
+ if (!div_involves_vars(bmap, i, first, n))
+ continue;
+ bmap = insert_bounds_on_div(bmap, i);
+ bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+ if (!bmap)
+ return NULL;
+ i = bmap->n_div;
+ }
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_basic_map_remove_divs_involving_dims(bset, type, first, n);
+}
+
+__isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0)
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_remove_divs_involving_dims(map->p[i],
+ type, first, n);
+ if (!map->p[i])
+ goto error;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_set *)isl_map_remove_divs_involving_dims((isl_map *)set,
+ type, first, n);
+}
+
+/* Does the desciption of "bmap" depend on the specified dimensions?
+ * We also check whether the dimensions appear in any of the div definitions.
+ * In principle there is no need for this check. If the dimensions appear
+ * in a div definition, they also appear in the defining constraints of that
+ * div.
+ */
+int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!bmap)
+ return -1;
+
+ if (first + n > isl_basic_map_dim(bmap, type))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "index out of bounds", return -1);
+
+ first += isl_basic_map_offset(bmap, type);
+ for (i = 0; i < bmap->n_eq; ++i)
+ if (isl_seq_first_non_zero(bmap->eq[i] + first, n) >= 0)
+ return 1;
+ for (i = 0; i < bmap->n_ineq; ++i)
+ if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0)
+ return 1;
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+int isl_map_involves_dims(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ if (first + n > isl_map_dim(map, type))
+ isl_die(map->ctx, isl_error_invalid,
+ "index out of bounds", return -1);
+
+ for (i = 0; i < map->n; ++i) {
+ int involves = isl_basic_map_involves_dims(map->p[i],
+ type, first, n);
+ if (involves < 0 || involves)
+ return involves;
+ }
+
+ return 0;
+}
+
+int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_basic_map_involves_dims(bset, type, first, n);
+}
+
+int isl_set_involves_dims(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_map_involves_dims(set, type, first, n);
+}
+
+/* Return true if the definition of the given div is unknown or depends
+ * on unknown divs.
+ */
+static int div_is_unknown(__isl_keep isl_basic_map *bmap, int div)
+{
+ int i;
+ unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return 1;
+
+ for (i = bmap->n_div - 1; i >= 0; --i) {
+ if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+ continue;
+ if (div_is_unknown(bmap, i))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_unknown_divs(
+ __isl_take isl_basic_map *bmap)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+
+ for (i = bmap->n_div - 1; i >= 0; --i) {
+ if (!div_is_unknown(bmap, i))
+ continue;
+ bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+ if (!bmap)
+ return NULL;
+ i = bmap->n_div;
+ }
+
+ return bmap;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs(
+ __isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_remove_unknown_divs(bset);
+}
+
+__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0)
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_remove_unknown_divs(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set)
+{
+ return (isl_set *)isl_map_remove_unknown_divs((isl_map *)set);
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_dims(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_basic_set *)
+ isl_basic_map_remove_dims((isl_basic_map *)bset, type, first, n);
+}
+
+struct isl_map *isl_map_remove_dims(struct isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (n == 0)
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+ isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_eliminate_vars(map->p[i],
+ isl_basic_map_offset(map->p[i], type) - 1 + first, n);
+ if (!map->p[i])
+ goto error;
+ }
+ map = isl_map_drop(map, type, first, n);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_set *)isl_map_remove_dims((isl_map *)bset, type, first, n);
+}
+
+/* Project out n inputs starting at first using Fourier-Motzkin */
+struct isl_map *isl_map_remove_inputs(struct isl_map *map,
+ unsigned first, unsigned n)
+{
+ return isl_map_remove_dims(map, isl_dim_in, first, n);
+}
+
+static void dump_term(struct isl_basic_map *bmap,
+ isl_int c, int pos, FILE *out)
+{
+ const char *name;
+ unsigned in = isl_basic_map_n_in(bmap);
+ unsigned dim = in + isl_basic_map_n_out(bmap);
+ unsigned nparam = isl_basic_map_n_param(bmap);
+ if (!pos)
+ isl_int_print(out, c, 0);
+ else {
+ if (!isl_int_is_one(c))
+ isl_int_print(out, c, 0);
+ if (pos < 1 + nparam) {
+ name = isl_space_get_dim_name(bmap->dim,
+ isl_dim_param, pos - 1);
+ if (name)
+ fprintf(out, "%s", name);
+ else
+ fprintf(out, "p%d", pos - 1);
+ } else if (pos < 1 + nparam + in)
+ fprintf(out, "i%d", pos - 1 - nparam);
+ else if (pos < 1 + nparam + dim)
+ fprintf(out, "o%d", pos - 1 - nparam - in);
+ else
+ fprintf(out, "e%d", pos - 1 - nparam - dim);
+ }
+}
+
+static void dump_constraint_sign(struct isl_basic_map *bmap, isl_int *c,
+ int sign, FILE *out)
+{
+ int i;
+ int first;
+ unsigned len = 1 + isl_basic_map_total_dim(bmap);
+ isl_int v;
+
+ isl_int_init(v);
+ for (i = 0, first = 1; i < len; ++i) {
+ if (isl_int_sgn(c[i]) * sign <= 0)
+ continue;
+ if (!first)
+ fprintf(out, " + ");
+ first = 0;
+ isl_int_abs(v, c[i]);
+ dump_term(bmap, v, i, out);
+ }
+ isl_int_clear(v);
+ if (first)
+ fprintf(out, "0");
+}
+
+static void dump_constraint(struct isl_basic_map *bmap, isl_int *c,
+ const char *op, FILE *out, int indent)
+{
+ int i;
+
+ fprintf(out, "%*s", indent, "");
+
+ dump_constraint_sign(bmap, c, 1, out);
+ fprintf(out, " %s ", op);
+ dump_constraint_sign(bmap, c, -1, out);
+
+ fprintf(out, "\n");
+
+ for (i = bmap->n_div; i < bmap->extra; ++i) {
+ if (isl_int_is_zero(c[1+isl_space_dim(bmap->dim, isl_dim_all)+i]))
+ continue;
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "ERROR: unused div coefficient not zero\n");
+ abort();
+ }
+}
+
+static void dump_constraints(struct isl_basic_map *bmap,
+ isl_int **c, unsigned n,
+ const char *op, FILE *out, int indent)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ dump_constraint(bmap, c[i], op, out, indent);
+}
+
+static void dump_affine(struct isl_basic_map *bmap, isl_int *exp, FILE *out)
+{
+ int j;
+ int first = 1;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ for (j = 0; j < 1 + total; ++j) {
+ if (isl_int_is_zero(exp[j]))
+ continue;
+ if (!first && isl_int_is_pos(exp[j]))
+ fprintf(out, "+");
+ dump_term(bmap, exp[j], j, out);
+ first = 0;
+ }
+}
+
+static void dump(struct isl_basic_map *bmap, FILE *out, int indent)
+{
+ int i;
+
+ dump_constraints(bmap, bmap->eq, bmap->n_eq, "=", out, indent);
+ dump_constraints(bmap, bmap->ineq, bmap->n_ineq, ">=", out, indent);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "e%d = [(", i);
+ dump_affine(bmap, bmap->div[i]+1, out);
+ fprintf(out, ")/");
+ isl_int_print(out, bmap->div[i][0], 0);
+ fprintf(out, "]\n");
+ }
+}
+
+void isl_basic_set_print_internal(struct isl_basic_set *bset,
+ FILE *out, int indent)
+{
+ if (!bset) {
+ fprintf(out, "null basic set\n");
+ return;
+ }
+
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "ref: %d, nparam: %d, dim: %d, extra: %d, flags: %x\n",
+ bset->ref, bset->dim->nparam, bset->dim->n_out,
+ bset->extra, bset->flags);
+ dump((struct isl_basic_map *)bset, out, indent);
+}
+
+void isl_basic_map_print_internal(struct isl_basic_map *bmap,
+ FILE *out, int indent)
+{
+ if (!bmap) {
+ fprintf(out, "null basic map\n");
+ return;
+ }
+
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "ref: %d, nparam: %d, in: %d, out: %d, extra: %d, "
+ "flags: %x, n_name: %d\n",
+ bmap->ref,
+ bmap->dim->nparam, bmap->dim->n_in, bmap->dim->n_out,
+ bmap->extra, bmap->flags, bmap->dim->n_id);
+ dump(bmap, out, indent);
+}
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos)
+{
+ unsigned total;
+ if (!bmap)
+ return -1;
+ total = isl_basic_map_total_dim(bmap);
+ isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+ isl_seq_neg(bmap->ineq[pos], bmap->ineq[pos], 1 + total);
+ isl_int_sub_ui(bmap->ineq[pos][0], bmap->ineq[pos][0], 1);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ return 0;
+}
+
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+ unsigned flags)
+{
+ struct isl_set *set;
+
+ if (!dim)
+ return NULL;
+ isl_assert(dim->ctx, dim->n_in == 0, goto error);
+ isl_assert(dim->ctx, n >= 0, goto error);
+ set = isl_alloc(dim->ctx, struct isl_set,
+ sizeof(struct isl_set) +
+ (n - 1) * sizeof(struct isl_basic_set *));
+ if (!set)
+ goto error;
+
+ set->ctx = dim->ctx;
+ isl_ctx_ref(set->ctx);
+ set->ref = 1;
+ set->size = n;
+ set->n = 0;
+ set->dim = dim;
+ set->flags = flags;
+ return set;
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_set *isl_set_alloc(struct isl_ctx *ctx,
+ unsigned nparam, unsigned dim, int n, unsigned flags)
+{
+ struct isl_set *set;
+ isl_space *dims;
+
+ dims = isl_space_alloc(ctx, nparam, 0, dim);
+ if (!dims)
+ return NULL;
+
+ set = isl_set_alloc_space(dims, n, flags);
+ return set;
+}
+
+/* Make sure "map" has room for at least "n" more basic maps.
+ */
+struct isl_map *isl_map_grow(struct isl_map *map, int n)
+{
+ int i;
+ struct isl_map *grown = NULL;
+
+ if (!map)
+ return NULL;
+ isl_assert(map->ctx, n >= 0, goto error);
+ if (map->n + n <= map->size)
+ return map;
+ grown = isl_map_alloc_space(isl_map_get_space(map), map->n + n, map->flags);
+ if (!grown)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ grown->p[i] = isl_basic_map_copy(map->p[i]);
+ if (!grown->p[i])
+ goto error;
+ grown->n++;
+ }
+ isl_map_free(map);
+ return grown;
+error:
+ isl_map_free(grown);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Make sure "set" has room for at least "n" more basic sets.
+ */
+struct isl_set *isl_set_grow(struct isl_set *set, int n)
+{
+ return (struct isl_set *)isl_map_grow((struct isl_map *)set, n);
+}
+
+struct isl_set *isl_set_dup(struct isl_set *set)
+{
+ int i;
+ struct isl_set *dup;
+
+ if (!set)
+ return NULL;
+
+ dup = isl_set_alloc_space(isl_space_copy(set->dim), set->n, set->flags);
+ if (!dup)
+ return NULL;
+ for (i = 0; i < set->n; ++i)
+ dup = isl_set_add_basic_set(dup, isl_basic_set_copy(set->p[i]));
+ return dup;
+}
+
+struct isl_set *isl_set_from_basic_set(struct isl_basic_set *bset)
+{
+ return isl_map_from_basic_map(bset);
+}
+
+struct isl_map *isl_map_from_basic_map(struct isl_basic_map *bmap)
+{
+ struct isl_map *map;
+
+ if (!bmap)
+ return NULL;
+
+ map = isl_map_alloc_space(isl_space_copy(bmap->dim), 1, ISL_MAP_DISJOINT);
+ return isl_map_add_basic_map(map, bmap);
+}
+
+__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set,
+ __isl_take isl_basic_set *bset)
+{
+ return (struct isl_set *)isl_map_add_basic_map((struct isl_map *)set,
+ (struct isl_basic_map *)bset);
+}
+
+__isl_null isl_set *isl_set_free(__isl_take isl_set *set)
+{
+ int i;
+
+ if (!set)
+ return NULL;
+
+ if (--set->ref > 0)
+ return NULL;
+
+ isl_ctx_deref(set->ctx);
+ for (i = 0; i < set->n; ++i)
+ isl_basic_set_free(set->p[i]);
+ isl_space_free(set->dim);
+ free(set);
+
+ return NULL;
+}
+
+void isl_set_print_internal(struct isl_set *set, FILE *out, int indent)
+{
+ int i;
+
+ if (!set) {
+ fprintf(out, "null set\n");
+ return;
+ }
+
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "ref: %d, n: %d, nparam: %d, dim: %d, flags: %x\n",
+ set->ref, set->n, set->dim->nparam, set->dim->n_out,
+ set->flags);
+ for (i = 0; i < set->n; ++i) {
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "basic set %d:\n", i);
+ isl_basic_set_print_internal(set->p[i], out, indent+4);
+ }
+}
+
+void isl_map_print_internal(struct isl_map *map, FILE *out, int indent)
+{
+ int i;
+
+ if (!map) {
+ fprintf(out, "null map\n");
+ return;
+ }
+
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "ref: %d, n: %d, nparam: %d, in: %d, out: %d, "
+ "flags: %x, n_name: %d\n",
+ map->ref, map->n, map->dim->nparam, map->dim->n_in,
+ map->dim->n_out, map->flags, map->dim->n_id);
+ for (i = 0; i < map->n; ++i) {
+ fprintf(out, "%*s", indent, "");
+ fprintf(out, "basic map %d:\n", i);
+ isl_basic_map_print_internal(map->p[i], out, indent+4);
+ }
+}
+
+struct isl_basic_map *isl_basic_map_intersect_domain(
+ struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+ struct isl_basic_map *bmap_domain;
+
+ if (!bmap || !bset)
+ goto error;
+
+ isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+ bset->dim, isl_dim_param), goto error);
+
+ if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+ isl_assert(bset->ctx,
+ isl_basic_map_compatible_domain(bmap, bset), goto error);
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ goto error;
+ bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+ bset->n_div, bset->n_eq, bset->n_ineq);
+ bmap_domain = isl_basic_map_from_domain(bset);
+ bmap = add_constraints(bmap, bmap_domain, 0, 0);
+
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_intersect_range(
+ struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+ struct isl_basic_map *bmap_range;
+
+ if (!bmap || !bset)
+ goto error;
+
+ isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+ bset->dim, isl_dim_param), goto error);
+
+ if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+ isl_assert(bset->ctx,
+ isl_basic_map_compatible_range(bmap, bset), goto error);
+
+ if (isl_basic_set_is_universe(bset)) {
+ isl_basic_set_free(bset);
+ return bmap;
+ }
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ goto error;
+ bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+ bset->n_div, bset->n_eq, bset->n_ineq);
+ bmap_range = isl_basic_map_from_basic_set(bset, isl_space_copy(bset->dim));
+ bmap = add_constraints(bmap, bmap_range, 0, 0);
+
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+int isl_basic_map_contains(struct isl_basic_map *bmap, struct isl_vec *vec)
+{
+ int i;
+ unsigned total;
+ isl_int s;
+
+ if (!bmap || !vec)
+ return -1;
+
+ total = 1 + isl_basic_map_total_dim(bmap);
+ if (total != vec->size)
+ return -1;
+
+ isl_int_init(s);
+
+ for (i = 0; i < bmap->n_eq; ++i) {
+ isl_seq_inner_product(vec->el, bmap->eq[i], total, &s);
+ if (!isl_int_is_zero(s)) {
+ isl_int_clear(s);
+ return 0;
+ }
+ }
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ isl_seq_inner_product(vec->el, bmap->ineq[i], total, &s);
+ if (isl_int_is_neg(s)) {
+ isl_int_clear(s);
+ return 0;
+ }
+ }
+
+ isl_int_clear(s);
+
+ return 1;
+}
+
+int isl_basic_set_contains(struct isl_basic_set *bset, struct isl_vec *vec)
+{
+ return isl_basic_map_contains((struct isl_basic_map *)bset, vec);
+}
+
+struct isl_basic_map *isl_basic_map_intersect(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ struct isl_vec *sample = NULL;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+ bmap2->dim, isl_dim_param), goto error);
+ if (isl_space_dim(bmap1->dim, isl_dim_all) ==
+ isl_space_dim(bmap1->dim, isl_dim_param) &&
+ isl_space_dim(bmap2->dim, isl_dim_all) !=
+ isl_space_dim(bmap2->dim, isl_dim_param))
+ return isl_basic_map_intersect(bmap2, bmap1);
+
+ if (isl_space_dim(bmap2->dim, isl_dim_all) !=
+ isl_space_dim(bmap2->dim, isl_dim_param))
+ isl_assert(bmap1->ctx,
+ isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+ if (bmap1->sample &&
+ isl_basic_map_contains(bmap1, bmap1->sample) > 0 &&
+ isl_basic_map_contains(bmap2, bmap1->sample) > 0)
+ sample = isl_vec_copy(bmap1->sample);
+ else if (bmap2->sample &&
+ isl_basic_map_contains(bmap1, bmap2->sample) > 0 &&
+ isl_basic_map_contains(bmap2, bmap2->sample) > 0)
+ sample = isl_vec_copy(bmap2->sample);
+
+ bmap1 = isl_basic_map_cow(bmap1);
+ if (!bmap1)
+ goto error;
+ bmap1 = isl_basic_map_extend_space(bmap1, isl_space_copy(bmap1->dim),
+ bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+ bmap1 = add_constraints(bmap1, bmap2, 0, 0);
+
+ if (!bmap1)
+ isl_vec_free(sample);
+ else if (sample) {
+ isl_vec_free(bmap1->sample);
+ bmap1->sample = sample;
+ }
+
+ bmap1 = isl_basic_map_simplify(bmap1);
+ return isl_basic_map_finalize(bmap1);
+error:
+ if (sample)
+ isl_vec_free(sample);
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_intersect(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_intersect(
+ (struct isl_basic_map *)bset1,
+ (struct isl_basic_map *)bset2);
+}
+
+__isl_give isl_basic_set *isl_basic_set_intersect_params(
+ __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+ return isl_basic_set_intersect(bset1, bset2);
+}
+
+/* Special case of isl_map_intersect, where both map1 and map2
+ * are convex, without any divs and such that either map1 or map2
+ * contains a single constraint. This constraint is then simply
+ * added to the other map.
+ */
+static __isl_give isl_map *map_intersect_add_constraint(
+ __isl_take isl_map *map1, __isl_take isl_map *map2)
+{
+ isl_assert(map1->ctx, map1->n == 1, goto error);
+ isl_assert(map2->ctx, map1->n == 1, goto error);
+ isl_assert(map1->ctx, map1->p[0]->n_div == 0, goto error);
+ isl_assert(map2->ctx, map1->p[0]->n_div == 0, goto error);
+
+ if (map2->p[0]->n_eq + map2->p[0]->n_ineq != 1)
+ return isl_map_intersect(map2, map1);
+
+ isl_assert(map2->ctx,
+ map2->p[0]->n_eq + map2->p[0]->n_ineq == 1, goto error);
+
+ map1 = isl_map_cow(map1);
+ if (!map1)
+ goto error;
+ if (isl_map_plain_is_empty(map1)) {
+ isl_map_free(map2);
+ return map1;
+ }
+ map1->p[0] = isl_basic_map_cow(map1->p[0]);
+ if (map2->p[0]->n_eq == 1)
+ map1->p[0] = isl_basic_map_add_eq(map1->p[0], map2->p[0]->eq[0]);
+ else
+ map1->p[0] = isl_basic_map_add_ineq(map1->p[0],
+ map2->p[0]->ineq[0]);
+
+ map1->p[0] = isl_basic_map_simplify(map1->p[0]);
+ map1->p[0] = isl_basic_map_finalize(map1->p[0]);
+ if (!map1->p[0])
+ goto error;
+
+ if (isl_basic_map_plain_is_empty(map1->p[0])) {
+ isl_basic_map_free(map1->p[0]);
+ map1->n = 0;
+ }
+
+ isl_map_free(map2);
+
+ return map1;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+/* map2 may be either a parameter domain or a map living in the same
+ * space as map1.
+ */
+static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ unsigned flags = 0;
+ isl_map *result;
+ int i, j;
+
+ if (!map1 || !map2)
+ goto error;
+
+ if ((isl_map_plain_is_empty(map1) ||
+ isl_map_plain_is_universe(map2)) &&
+ isl_space_is_equal(map1->dim, map2->dim)) {
+ isl_map_free(map2);
+ return map1;
+ }
+ if ((isl_map_plain_is_empty(map2) ||
+ isl_map_plain_is_universe(map1)) &&
+ isl_space_is_equal(map1->dim, map2->dim)) {
+ isl_map_free(map1);
+ return map2;
+ }
+
+ if (map1->n == 1 && map2->n == 1 &&
+ map1->p[0]->n_div == 0 && map2->p[0]->n_div == 0 &&
+ isl_space_is_equal(map1->dim, map2->dim) &&
+ (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 ||
+ map2->p[0]->n_eq + map2->p[0]->n_ineq == 1))
+ return map_intersect_add_constraint(map1, map2);
+
+ if (isl_space_dim(map2->dim, isl_dim_all) !=
+ isl_space_dim(map2->dim, isl_dim_param))
+ isl_assert(map1->ctx,
+ isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+ if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+ ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+ ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+ result = isl_map_alloc_space(isl_space_copy(map1->dim),
+ map1->n * map2->n, flags);
+ if (!result)
+ goto error;
+ for (i = 0; i < map1->n; ++i)
+ for (j = 0; j < map2->n; ++j) {
+ struct isl_basic_map *part;
+ part = isl_basic_map_intersect(
+ isl_basic_map_copy(map1->p[i]),
+ isl_basic_map_copy(map2->p[j]));
+ if (isl_basic_map_is_empty(part) < 0)
+ part = isl_basic_map_free(part);
+ result = isl_map_add_basic_map(result, part);
+ if (!result)
+ goto error;
+ }
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return result;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ if (!map1 || !map2)
+ goto error;
+ if (!isl_space_is_equal(map1->dim, map2->dim))
+ isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+ "spaces don't match", goto error);
+ return map_intersect_internal(map1, map2);
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_intersect);
+}
+
+struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2)
+{
+ return (struct isl_set *)
+ isl_map_intersect((struct isl_map *)set1,
+ (struct isl_map *)set2);
+}
+
+/* map_intersect_internal accepts intersections
+ * with parameter domains, so we can just call that function.
+ */
+static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map,
+ __isl_take isl_set *params)
+{
+ return map_intersect_internal(map, params);
+}
+
+__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_intersect_params);
+}
+
+__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set,
+ __isl_take isl_set *params)
+{
+ return isl_map_intersect_params(set, params);
+}
+
+struct isl_basic_map *isl_basic_map_reverse(struct isl_basic_map *bmap)
+{
+ isl_space *dim;
+ struct isl_basic_set *bset;
+ unsigned in;
+
+ if (!bmap)
+ return NULL;
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ dim = isl_space_reverse(isl_space_copy(bmap->dim));
+ in = isl_basic_map_n_in(bmap);
+ bset = isl_basic_set_from_basic_map(bmap);
+ bset = isl_basic_set_swap_vars(bset, in);
+ return isl_basic_map_from_basic_set(bset, dim);
+}
+
+static __isl_give isl_basic_map *basic_map_space_reset(
+ __isl_take isl_basic_map *bmap, enum isl_dim_type type)
+{
+ isl_space *space;
+
+ if (!bmap)
+ return NULL;
+ if (!isl_space_is_named_or_nested(bmap->dim, type))
+ return bmap;
+
+ space = isl_basic_map_get_space(bmap);
+ space = isl_space_reset(space, type);
+ bmap = isl_basic_map_reset_space(bmap, space);
+ return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_insert_dims(
+ __isl_take isl_basic_map *bmap, enum isl_dim_type type,
+ unsigned pos, unsigned n)
+{
+ isl_space *res_dim;
+ struct isl_basic_map *res;
+ struct isl_dim_map *dim_map;
+ unsigned total, off;
+ enum isl_dim_type t;
+
+ if (n == 0)
+ return basic_map_space_reset(bmap, type);
+
+ if (!bmap)
+ return NULL;
+
+ res_dim = isl_space_insert_dims(isl_basic_map_get_space(bmap), type, pos, n);
+
+ total = isl_basic_map_total_dim(bmap) + n;
+ dim_map = isl_dim_map_alloc(bmap->ctx, total);
+ off = 0;
+ for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+ if (t != type) {
+ isl_dim_map_dim(dim_map, bmap->dim, t, off);
+ } else {
+ unsigned size = isl_basic_map_dim(bmap, t);
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ 0, pos, off);
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ pos, size - pos, off + pos + n);
+ }
+ off += isl_space_dim(res_dim, t);
+ }
+ isl_dim_map_div(dim_map, bmap, off);
+
+ res = isl_basic_map_alloc_space(res_dim,
+ bmap->n_div, bmap->n_eq, bmap->n_ineq);
+ if (isl_basic_map_is_rational(bmap))
+ res = isl_basic_map_set_rational(res);
+ if (isl_basic_map_plain_is_empty(bmap)) {
+ isl_basic_map_free(bmap);
+ free(dim_map);
+ return isl_basic_map_set_to_empty(res);
+ }
+ res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+ return isl_basic_map_finalize(res);
+}
+
+__isl_give isl_basic_set *isl_basic_set_insert_dims(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, unsigned n)
+{
+ return isl_basic_map_insert_dims(bset, type, pos, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned n)
+{
+ if (!bmap)
+ return NULL;
+ return isl_basic_map_insert_dims(bmap, type,
+ isl_basic_map_dim(bmap, type), n);
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned n)
+{
+ if (!bset)
+ return NULL;
+ isl_assert(bset->ctx, type != isl_dim_in, goto error);
+ return (isl_basic_set *)isl_basic_map_add((isl_basic_map *)bset, type, n);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+static __isl_give isl_map *map_space_reset(__isl_take isl_map *map,
+ enum isl_dim_type type)
+{
+ isl_space *space;
+
+ if (!map || !isl_space_is_named_or_nested(map->dim, type))
+ return map;
+
+ space = isl_map_get_space(map);
+ space = isl_space_reset(space, type);
+ map = isl_map_reset_space(map, space);
+ return map;
+}
+
+__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, unsigned n)
+{
+ int i;
+
+ if (n == 0)
+ return map_space_reset(map, type);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_insert_dims(map->dim, type, pos, n);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_insert_dims(map->p[i], type, pos, n);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, unsigned n)
+{
+ return isl_map_insert_dims(set, type, pos, n);
+}
+
+__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned n)
+{
+ if (!map)
+ return NULL;
+ return isl_map_insert_dims(map, type, isl_map_dim(map, type), n);
+}
+
+__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned n)
+{
+ if (!set)
+ return NULL;
+ isl_assert(set->ctx, type != isl_dim_in, goto error);
+ return (isl_set *)isl_map_add_dims((isl_map *)set, type, n);
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_move_dims(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ struct isl_dim_map *dim_map;
+ struct isl_basic_map *res;
+ enum isl_dim_type t;
+ unsigned total, off;
+
+ if (!bmap)
+ return NULL;
+ if (n == 0)
+ return bmap;
+
+ isl_assert(bmap->ctx, src_pos + n <= isl_basic_map_dim(bmap, src_type),
+ goto error);
+
+ if (dst_type == src_type && dst_pos == src_pos)
+ return bmap;
+
+ isl_assert(bmap->ctx, dst_type != src_type, goto error);
+
+ if (pos(bmap->dim, dst_type) + dst_pos ==
+ pos(bmap->dim, src_type) + src_pos +
+ ((src_type < dst_type) ? n : 0)) {
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+ }
+
+ total = isl_basic_map_total_dim(bmap);
+ dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+ off = 0;
+ for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+ unsigned size = isl_space_dim(bmap->dim, t);
+ if (t == dst_type) {
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ 0, dst_pos, off);
+ off += dst_pos;
+ isl_dim_map_dim_range(dim_map, bmap->dim, src_type,
+ src_pos, n, off);
+ off += n;
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ dst_pos, size - dst_pos, off);
+ off += size - dst_pos;
+ } else if (t == src_type) {
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ 0, src_pos, off);
+ off += src_pos;
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ src_pos + n, size - src_pos - n, off);
+ off += size - src_pos - n;
+ } else {
+ isl_dim_map_dim(dim_map, bmap->dim, t, off);
+ off += size;
+ }
+ }
+ isl_dim_map_div(dim_map, bmap, off);
+
+ res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+ bmap->n_div, bmap->n_eq, bmap->n_ineq);
+ bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+ if (!bmap)
+ goto error;
+
+ bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!bmap->dim)
+ goto error;
+
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ return (isl_basic_set *)isl_basic_map_move_dims(
+ (isl_basic_map *)bset, dst_type, dst_pos, src_type, src_pos, n);
+}
+
+__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ if (!set)
+ return NULL;
+ isl_assert(set->ctx, dst_type != isl_dim_in, goto error);
+ return (isl_set *)isl_map_move_dims((isl_map *)set, dst_type, dst_pos,
+ src_type, src_pos, n);
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map,
+ enum isl_dim_type dst_type, unsigned dst_pos,
+ enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (n == 0)
+ return map;
+
+ isl_assert(map->ctx, src_pos + n <= isl_map_dim(map, src_type),
+ goto error);
+
+ if (dst_type == src_type && dst_pos == src_pos)
+ return map;
+
+ isl_assert(map->ctx, dst_type != src_type, goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_move_dims(map->dim, dst_type, dst_pos, src_type, src_pos, n);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_move_dims(map->p[i],
+ dst_type, dst_pos,
+ src_type, src_pos, n);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Move the specified dimensions to the last columns right before
+ * the divs. Don't change the dimension specification of bmap.
+ * That's the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ struct isl_dim_map *dim_map;
+ struct isl_basic_map *res;
+ enum isl_dim_type t;
+ unsigned total, off;
+
+ if (!bmap)
+ return NULL;
+ if (pos(bmap->dim, type) + first + n ==
+ 1 + isl_space_dim(bmap->dim, isl_dim_all))
+ return bmap;
+
+ total = isl_basic_map_total_dim(bmap);
+ dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+ off = 0;
+ for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+ unsigned size = isl_space_dim(bmap->dim, t);
+ if (t == type) {
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ 0, first, off);
+ off += first;
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ first, n, total - bmap->n_div - n);
+ isl_dim_map_dim_range(dim_map, bmap->dim, t,
+ first + n, size - (first + n), off);
+ off += size - (first + n);
+ } else {
+ isl_dim_map_dim(dim_map, bmap->dim, t, off);
+ off += size;
+ }
+ }
+ isl_dim_map_div(dim_map, bmap, off + n);
+
+ res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+ bmap->n_div, bmap->n_eq, bmap->n_ineq);
+ res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+ return res;
+}
+
+/* Insert "n" rows in the divs of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the new divs.
+ * The space of "bmap" is not adjusted, however, which means
+ * that "bmap" is left in an inconsistent state. Removing "n" dimensions
+ * from the space of "bmap" is the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap,
+ int n)
+{
+ int i;
+ size_t row_size;
+ isl_int **new_div;
+ isl_int *old;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + bmap->extra;
+ old = bmap->block2.data;
+ bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2,
+ (bmap->extra + n) * (1 + row_size));
+ if (!bmap->block2.data)
+ return isl_basic_map_free(bmap);
+ new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n);
+ if (!new_div)
+ return isl_basic_map_free(bmap);
+ for (i = 0; i < n; ++i) {
+ new_div[i] = bmap->block2.data +
+ (bmap->extra + i) * (1 + row_size);
+ isl_seq_clr(new_div[i], 1 + row_size);
+ }
+ for (i = 0; i < bmap->extra; ++i)
+ new_div[n + i] = bmap->block2.data + (bmap->div[i] - old);
+ free(bmap->div);
+ bmap->div = new_div;
+ bmap->n_div += n;
+ bmap->extra += n;
+
+ return bmap;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_basic_map *isl_basic_map_project_out(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ if (n == 0)
+ return basic_map_space_reset(bmap, type);
+
+ if (!bmap)
+ return NULL;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+ return isl_basic_map_remove_dims(bmap, type, first, n);
+
+ isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+ goto error);
+
+ bmap = move_last(bmap, type, first, n);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = insert_div_rows(bmap, n);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+ if (!bmap->dim)
+ goto error;
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_drop_redundant_divs(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+struct isl_basic_set *isl_basic_set_project_out(struct isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_basic_set *)isl_basic_map_project_out(
+ (isl_basic_map *)bset, type, first, n);
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (n == 0)
+ return map_space_reset(map, type);
+
+ isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_drop_dims(map->dim, type, first, n);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_project_out(map->p[i], type, first, n);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_set *)isl_map_project_out((isl_map *)set, type, first, n);
+}
+
+static struct isl_basic_map *add_divs(struct isl_basic_map *bmap, unsigned n)
+{
+ int i, j;
+
+ for (i = 0; i < n; ++i) {
+ j = isl_basic_map_alloc_div(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->div[j], 1+1+isl_basic_map_total_dim(bmap));
+ }
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_range(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ isl_space *dim_result = NULL;
+ struct isl_basic_map *bmap;
+ unsigned n_in, n_out, n, nparam, total, pos;
+ struct isl_dim_map *dim_map1, *dim_map2;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+ if (!isl_space_match(bmap1->dim, isl_dim_param,
+ bmap2->dim, isl_dim_param))
+ isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+ "parameters don't match", goto error);
+ if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_out,
+ bmap2->dim, isl_dim_in))
+ isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+ "spaces don't match", goto error);
+
+ dim_result = isl_space_join(isl_space_copy(bmap1->dim),
+ isl_space_copy(bmap2->dim));
+
+ n_in = isl_basic_map_n_in(bmap1);
+ n_out = isl_basic_map_n_out(bmap2);
+ n = isl_basic_map_n_out(bmap1);
+ nparam = isl_basic_map_n_param(bmap1);
+
+ total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + n;
+ dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+ dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_in);
+ isl_dim_map_div(dim_map1, bmap1, pos += n_out);
+ isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+
+ bmap = isl_basic_map_alloc_space(dim_result,
+ bmap1->n_div + bmap2->n_div + n,
+ bmap1->n_eq + bmap2->n_eq,
+ bmap1->n_ineq + bmap2->n_ineq);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+ bmap = add_divs(bmap, n);
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_drop_redundant_divs(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_apply(
+ struct isl_basic_set *bset, struct isl_basic_map *bmap)
+{
+ if (!bset || !bmap)
+ goto error;
+
+ isl_assert(bset->ctx, isl_basic_map_compatible_domain(bmap, bset),
+ goto error);
+
+ return (struct isl_basic_set *)
+ isl_basic_map_apply_range((struct isl_basic_map *)bset, bmap);
+error:
+ isl_basic_set_free(bset);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_domain(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_assert(bmap1->ctx,
+ isl_basic_map_n_in(bmap1) == isl_basic_map_n_in(bmap2), goto error);
+ isl_assert(bmap1->ctx,
+ isl_basic_map_n_param(bmap1) == isl_basic_map_n_param(bmap2),
+ goto error);
+
+ bmap1 = isl_basic_map_reverse(bmap1);
+ bmap1 = isl_basic_map_apply_range(bmap1, bmap2);
+ return isl_basic_map_reverse(bmap1);
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+/* Given two basic maps A -> f(A) and B -> g(B), construct a basic map
+ * A \cap B -> f(A) + f(B)
+ */
+struct isl_basic_map *isl_basic_map_sum(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ unsigned n_in, n_out, nparam, total, pos;
+ struct isl_basic_map *bmap = NULL;
+ struct isl_dim_map *dim_map1, *dim_map2;
+ int i;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+ goto error);
+
+ nparam = isl_basic_map_n_param(bmap1);
+ n_in = isl_basic_map_n_in(bmap1);
+ n_out = isl_basic_map_n_out(bmap1);
+
+ total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + 2 * n_out;
+ dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+ dim_map2 = isl_dim_map_alloc(bmap2->ctx, total);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+ isl_dim_map_div(dim_map1, bmap1, pos += n_in + n_out);
+ isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_out);
+
+ bmap = isl_basic_map_alloc_space(isl_space_copy(bmap1->dim),
+ bmap1->n_div + bmap2->n_div + 2 * n_out,
+ bmap1->n_eq + bmap2->n_eq + n_out,
+ bmap1->n_ineq + bmap2->n_ineq);
+ for (i = 0; i < n_out; ++i) {
+ int j = isl_basic_map_alloc_equality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[j], 1+total);
+ isl_int_set_si(bmap->eq[j][1+nparam+n_in+i], -1);
+ isl_int_set_si(bmap->eq[j][1+pos+i], 1);
+ isl_int_set_si(bmap->eq[j][1+pos-n_out+i], 1);
+ }
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+ bmap = add_divs(bmap, 2 * n_out);
+
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+/* Given two maps A -> f(A) and B -> g(B), construct a map
+ * A \cap B -> f(A) + f(B)
+ */
+struct isl_map *isl_map_sum(struct isl_map *map1, struct isl_map *map2)
+{
+ struct isl_map *result;
+ int i, j;
+
+ if (!map1 || !map2)
+ goto error;
+
+ isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+ result = isl_map_alloc_space(isl_space_copy(map1->dim),
+ map1->n * map2->n, 0);
+ if (!result)
+ goto error;
+ for (i = 0; i < map1->n; ++i)
+ for (j = 0; j < map2->n; ++j) {
+ struct isl_basic_map *part;
+ part = isl_basic_map_sum(
+ isl_basic_map_copy(map1->p[i]),
+ isl_basic_map_copy(map2->p[j]));
+ if (isl_basic_map_is_empty(part))
+ isl_basic_map_free(part);
+ else
+ result = isl_map_add_basic_map(result, part);
+ if (!result)
+ goto error;
+ }
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return result;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ return (isl_set *)isl_map_sum((isl_map *)set1, (isl_map *)set2);
+}
+
+/* Given a basic map A -> f(A), construct A -> -f(A).
+ */
+struct isl_basic_map *isl_basic_map_neg(struct isl_basic_map *bmap)
+{
+ int i, j;
+ unsigned off, n;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ n = isl_basic_map_dim(bmap, isl_dim_out);
+ off = isl_basic_map_offset(bmap, isl_dim_out);
+ for (i = 0; i < bmap->n_eq; ++i)
+ for (j = 0; j < n; ++j)
+ isl_int_neg(bmap->eq[i][off+j], bmap->eq[i][off+j]);
+ for (i = 0; i < bmap->n_ineq; ++i)
+ for (j = 0; j < n; ++j)
+ isl_int_neg(bmap->ineq[i][off+j], bmap->ineq[i][off+j]);
+ for (i = 0; i < bmap->n_div; ++i)
+ for (j = 0; j < n; ++j)
+ isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]);
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_neg(bset);
+}
+
+/* Given a map A -> f(A), construct A -> -f(A).
+ */
+struct isl_map *isl_map_neg(struct isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_neg(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_neg(__isl_take isl_set *set)
+{
+ return (isl_set *)isl_map_neg((isl_map *)set);
+}
+
+/* Given a basic map A -> f(A) and an integer d, construct a basic map
+ * A -> floor(f(A)/d).
+ */
+struct isl_basic_map *isl_basic_map_floordiv(struct isl_basic_map *bmap,
+ isl_int d)
+{
+ unsigned n_in, n_out, nparam, total, pos;
+ struct isl_basic_map *result = NULL;
+ struct isl_dim_map *dim_map;
+ int i;
+
+ if (!bmap)
+ return NULL;
+
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ n_out = isl_basic_map_n_out(bmap);
+
+ total = nparam + n_in + n_out + bmap->n_div + n_out;
+ dim_map = isl_dim_map_alloc(bmap->ctx, total);
+ isl_dim_map_dim(dim_map, bmap->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map, bmap->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_div(dim_map, bmap, pos += n_in + n_out);
+ isl_dim_map_dim(dim_map, bmap->dim, isl_dim_out, pos += bmap->n_div);
+
+ result = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+ bmap->n_div + n_out,
+ bmap->n_eq, bmap->n_ineq + 2 * n_out);
+ result = isl_basic_map_add_constraints_dim_map(result, bmap, dim_map);
+ result = add_divs(result, n_out);
+ for (i = 0; i < n_out; ++i) {
+ int j;
+ j = isl_basic_map_alloc_inequality(result);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(result->ineq[j], 1+total);
+ isl_int_neg(result->ineq[j][1+nparam+n_in+i], d);
+ isl_int_set_si(result->ineq[j][1+pos+i], 1);
+ j = isl_basic_map_alloc_inequality(result);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(result->ineq[j], 1+total);
+ isl_int_set(result->ineq[j][1+nparam+n_in+i], d);
+ isl_int_set_si(result->ineq[j][1+pos+i], -1);
+ isl_int_sub_ui(result->ineq[j][0], d, 1);
+ }
+
+ result = isl_basic_map_simplify(result);
+ return isl_basic_map_finalize(result);
+error:
+ isl_basic_map_free(result);
+ return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+struct isl_map *isl_map_floordiv(struct isl_map *map, isl_int d)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ ISL_F_CLR(map, ISL_MAP_DISJOINT);
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_floordiv(map->p[i], d);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map,
+ __isl_take isl_val *d)
+{
+ if (!map || !d)
+ goto error;
+ if (!isl_val_is_int(d))
+ isl_die(isl_val_get_ctx(d), isl_error_invalid,
+ "expecting integer denominator", goto error);
+ map = isl_map_floordiv(map, d->n);
+ isl_val_free(d);
+ return map;
+error:
+ isl_map_free(map);
+ isl_val_free(d);
+ return NULL;
+}
+
+static struct isl_basic_map *var_equal(struct isl_basic_map *bmap, unsigned pos)
+{
+ int i;
+ unsigned nparam;
+ unsigned n_in;
+
+ i = isl_basic_map_alloc_equality(bmap);
+ if (i < 0)
+ goto error;
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->eq[i][1+nparam+pos], -1);
+ isl_int_set_si(bmap->eq[i][1+nparam+n_in+pos], 1);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraints to "bmap" expressing i_pos < o_pos
+ */
+static struct isl_basic_map *var_less(struct isl_basic_map *bmap, unsigned pos)
+{
+ int i;
+ unsigned nparam;
+ unsigned n_in;
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ goto error;
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->ineq[i][0], -1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos <= o_pos
+ */
+static __isl_give isl_basic_map *var_less_or_equal(
+ __isl_take isl_basic_map *bmap, unsigned pos)
+{
+ int i;
+ unsigned nparam;
+ unsigned n_in;
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ goto error;
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraints to "bmap" expressing i_pos > o_pos
+ */
+static struct isl_basic_map *var_more(struct isl_basic_map *bmap, unsigned pos)
+{
+ int i;
+ unsigned nparam;
+ unsigned n_in;
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ goto error;
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->ineq[i][0], -1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos >= o_pos
+ */
+static __isl_give isl_basic_map *var_more_or_equal(
+ __isl_take isl_basic_map *bmap, unsigned pos)
+{
+ int i;
+ unsigned nparam;
+ unsigned n_in;
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ goto error;
+ nparam = isl_basic_map_n_param(bmap);
+ n_in = isl_basic_map_n_in(bmap);
+ isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+ isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_equal(
+ __isl_take isl_space *dim, unsigned n_equal)
+{
+ int i;
+ struct isl_basic_map *bmap;
+ bmap = isl_basic_map_alloc_space(dim, 0, n_equal, 0);
+ if (!bmap)
+ return NULL;
+ for (i = 0; i < n_equal && bmap; ++i)
+ bmap = var_equal(bmap, i);
+ return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] << o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim,
+ unsigned pos)
+{
+ int i;
+ struct isl_basic_map *bmap;
+ bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+ if (!bmap)
+ return NULL;
+ for (i = 0; i < pos && bmap; ++i)
+ bmap = var_equal(bmap, i);
+ if (bmap)
+ bmap = var_less(bmap, pos);
+ return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] <<= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_or_equal_at(
+ __isl_take isl_space *dim, unsigned pos)
+{
+ int i;
+ isl_basic_map *bmap;
+
+ bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+ for (i = 0; i < pos; ++i)
+ bmap = var_equal(bmap, i);
+ bmap = var_less_or_equal(bmap, pos);
+ return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on pairs of sets of dimension "dim" expressing i_pos > o_pos
+ */
+__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim,
+ unsigned pos)
+{
+ int i;
+ struct isl_basic_map *bmap;
+ bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+ if (!bmap)
+ return NULL;
+ for (i = 0; i < pos && bmap; ++i)
+ bmap = var_equal(bmap, i);
+ if (bmap)
+ bmap = var_more(bmap, pos);
+ return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] >>= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_more_or_equal_at(
+ __isl_take isl_space *dim, unsigned pos)
+{
+ int i;
+ isl_basic_map *bmap;
+
+ bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+ for (i = 0; i < pos; ++i)
+ bmap = var_equal(bmap, i);
+ bmap = var_more_or_equal(bmap, pos);
+ return isl_basic_map_finalize(bmap);
+}
+
+static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *dims,
+ unsigned n, int equal)
+{
+ struct isl_map *map;
+ int i;
+
+ if (n == 0 && equal)
+ return isl_map_universe(dims);
+
+ map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+ for (i = 0; i + 1 < n; ++i)
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_less_at(isl_space_copy(dims), i));
+ if (n > 0) {
+ if (equal)
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_less_or_equal_at(dims, n - 1));
+ else
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_less_at(dims, n - 1));
+ } else
+ isl_space_free(dims);
+
+ return map;
+}
+
+static __isl_give isl_map *map_lex_lte(__isl_take isl_space *dims, int equal)
+{
+ if (!dims)
+ return NULL;
+ return map_lex_lte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n)
+{
+ return map_lex_lte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n)
+{
+ return map_lex_lte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim)
+{
+ return map_lex_lte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim)
+{
+ return map_lex_lte(isl_space_map_from_set(set_dim), 1);
+}
+
+static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *dims,
+ unsigned n, int equal)
+{
+ struct isl_map *map;
+ int i;
+
+ if (n == 0 && equal)
+ return isl_map_universe(dims);
+
+ map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+ for (i = 0; i + 1 < n; ++i)
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_more_at(isl_space_copy(dims), i));
+ if (n > 0) {
+ if (equal)
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_more_or_equal_at(dims, n - 1));
+ else
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_more_at(dims, n - 1));
+ } else
+ isl_space_free(dims);
+
+ return map;
+}
+
+static __isl_give isl_map *map_lex_gte(__isl_take isl_space *dims, int equal)
+{
+ if (!dims)
+ return NULL;
+ return map_lex_gte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n)
+{
+ return map_lex_gte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n)
+{
+ return map_lex_gte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim)
+{
+ return map_lex_gte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim)
+{
+ return map_lex_gte(isl_space_map_from_set(set_dim), 1);
+}
+
+__isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ isl_map *map;
+ map = isl_map_lex_le(isl_set_get_space(set1));
+ map = isl_map_intersect_domain(map, set1);
+ map = isl_map_intersect_range(map, set2);
+ return map;
+}
+
+__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ isl_map *map;
+ map = isl_map_lex_lt(isl_set_get_space(set1));
+ map = isl_map_intersect_domain(map, set1);
+ map = isl_map_intersect_range(map, set2);
+ return map;
+}
+
+__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ isl_map *map;
+ map = isl_map_lex_ge(isl_set_get_space(set1));
+ map = isl_map_intersect_domain(map, set1);
+ map = isl_map_intersect_range(map, set2);
+ return map;
+}
+
+__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ isl_map *map;
+ map = isl_map_lex_gt(isl_set_get_space(set1));
+ map = isl_map_intersect_domain(map, set1);
+ map = isl_map_intersect_range(map, set2);
+ return map;
+}
+
+__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *map;
+ map = isl_map_lex_le(isl_space_range(isl_map_get_space(map1)));
+ map = isl_map_apply_domain(map, isl_map_reverse(map1));
+ map = isl_map_apply_range(map, isl_map_reverse(map2));
+ return map;
+}
+
+__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *map;
+ map = isl_map_lex_lt(isl_space_range(isl_map_get_space(map1)));
+ map = isl_map_apply_domain(map, isl_map_reverse(map1));
+ map = isl_map_apply_range(map, isl_map_reverse(map2));
+ return map;
+}
+
+__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *map;
+ map = isl_map_lex_ge(isl_space_range(isl_map_get_space(map1)));
+ map = isl_map_apply_domain(map, isl_map_reverse(map1));
+ map = isl_map_apply_range(map, isl_map_reverse(map2));
+ return map;
+}
+
+__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *map;
+ map = isl_map_lex_gt(isl_space_range(isl_map_get_space(map1)));
+ map = isl_map_apply_domain(map, isl_map_reverse(map1));
+ map = isl_map_apply_range(map, isl_map_reverse(map2));
+ return map;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_basic_set(
+ __isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+ struct isl_basic_map *bmap;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset || !dim)
+ goto error;
+
+ isl_assert(bset->ctx, isl_space_compatible(bset->dim, dim), goto error);
+ isl_space_free(bset->dim);
+ bmap = (struct isl_basic_map *) bset;
+ bmap->dim = dim;
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_set_free(bset);
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_basic_map(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ goto error;
+ if (bmap->dim->n_in == 0)
+ return (struct isl_basic_set *)bmap;
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ goto error;
+ bmap->dim = isl_space_as_set_space(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+ bmap = isl_basic_map_finalize(bmap);
+ return (struct isl_basic_set *)bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ * f - m d >= 0
+ */
+static int add_upper_div_constraint(__isl_keep isl_basic_map *bmap,
+ unsigned pos, isl_int *div)
+{
+ int i;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ return -1;
+ isl_seq_cpy(bmap->ineq[i], div + 1, 1 + total);
+ isl_int_neg(bmap->ineq[i][1 + pos], div[0]);
+
+ return 0;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ * -(f-(n-1)) + m d >= 0
+ */
+static int add_lower_div_constraint(__isl_keep isl_basic_map *bmap,
+ unsigned pos, isl_int *div)
+{
+ int i;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ return -1;
+ isl_seq_neg(bmap->ineq[i], div + 1, 1 + total);
+ isl_int_set(bmap->ineq[i][1 + pos], div[0]);
+ isl_int_add(bmap->ineq[i][0], bmap->ineq[i][0], bmap->ineq[i][1 + pos]);
+ isl_int_sub_ui(bmap->ineq[i][0], bmap->ineq[i][0], 1);
+
+ return 0;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ * f - m d >= 0
+ * -(f-(n-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ * f - m d >= n
+ */
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+ unsigned pos, isl_int *div)
+{
+ if (add_upper_div_constraint(bmap, pos, div) < 0)
+ return -1;
+ if (add_lower_div_constraint(bmap, pos, div) < 0)
+ return -1;
+ return 0;
+}
+
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+ unsigned pos, isl_int *div)
+{
+ return isl_basic_map_add_div_constraints_var((isl_basic_map *)bset,
+ pos, div);
+}
+
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div)
+{
+ unsigned total = isl_basic_map_total_dim(bmap);
+ unsigned div_pos = total - bmap->n_div + div;
+
+ return isl_basic_map_add_div_constraints_var(bmap, div_pos,
+ bmap->div[div]);
+}
+
+/* For each known div d = floor(f/m), add the constraints
+ *
+ * f - m d >= 0
+ * -(f-(n-1)) + m d >= 0
+ */
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+ __isl_take isl_basic_map *bmap)
+{
+ int i;
+ unsigned n_div;
+
+ if (!bmap)
+ return NULL;
+ n_div = isl_basic_map_dim(bmap, isl_dim_div);
+ if (n_div == 0)
+ return bmap;
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 0, 2 * n_div);
+ if (!bmap)
+ return NULL;
+ for (i = 0; i < n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+ return isl_basic_map_free(bmap);
+ }
+
+ bmap = isl_basic_map_remove_duplicate_constraints(bmap, NULL, 0);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+}
+
+/* Add the div constraint of sign "sign" for div "div" of "bmap".
+ *
+ * In particular, if this div is of the form d = floor(f/m),
+ * then add the constraint
+ *
+ * f - m d >= 0
+ *
+ * if sign < 0 or the constraint
+ *
+ * -(f-(n-1)) + m d >= 0
+ *
+ * if sign > 0.
+ */
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+ unsigned div, int sign)
+{
+ unsigned total;
+ unsigned div_pos;
+
+ if (!bmap)
+ return -1;
+
+ total = isl_basic_map_total_dim(bmap);
+ div_pos = total - bmap->n_div + div;
+
+ if (sign < 0)
+ return add_upper_div_constraint(bmap, div_pos, bmap->div[div]);
+ else
+ return add_lower_div_constraint(bmap, div_pos, bmap->div[div]);
+}
+
+int isl_basic_set_add_div_constraints(struct isl_basic_set *bset, unsigned div)
+{
+ return isl_basic_map_add_div_constraints(bset, div);
+}
+
+struct isl_basic_set *isl_basic_map_underlying_set(
+ struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ goto error;
+ if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 &&
+ bmap->n_div == 0 &&
+ !isl_space_is_named_or_nested(bmap->dim, isl_dim_in) &&
+ !isl_space_is_named_or_nested(bmap->dim, isl_dim_out))
+ return (struct isl_basic_set *)bmap;
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ goto error;
+ bmap->dim = isl_space_underlying(bmap->dim, bmap->n_div);
+ if (!bmap->dim)
+ goto error;
+ bmap->extra -= bmap->n_div;
+ bmap->n_div = 0;
+ bmap = isl_basic_map_finalize(bmap);
+ return (struct isl_basic_set *)bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+ __isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_underlying_set((isl_basic_map *)bset);
+}
+
+/* Replace each element in "list" by the result of applying
+ * isl_basic_set_underlying_set to the element.
+ */
+__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set(
+ __isl_take isl_basic_set_list *list)
+{
+ int i, n;
+
+ if (!list)
+ return NULL;
+
+ n = isl_basic_set_list_n_basic_set(list);
+ for (i = 0; i < n; ++i) {
+ isl_basic_set *bset;
+
+ bset = isl_basic_set_list_get_basic_set(list, i);
+ bset = isl_basic_set_underlying_set(bset);
+ list = isl_basic_set_list_set_basic_set(list, i, bset);
+ }
+
+ return list;
+}
+
+struct isl_basic_map *isl_basic_map_overlying_set(
+ struct isl_basic_set *bset, struct isl_basic_map *like)
+{
+ struct isl_basic_map *bmap;
+ struct isl_ctx *ctx;
+ unsigned total;
+ int i;
+
+ if (!bset || !like)
+ goto error;
+ ctx = bset->ctx;
+ isl_assert(ctx, bset->n_div == 0, goto error);
+ isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
+ isl_assert(ctx, bset->dim->n_out == isl_basic_map_total_dim(like),
+ goto error);
+ if (isl_space_is_equal(bset->dim, like->dim) && like->n_div == 0) {
+ isl_basic_map_free(like);
+ return (struct isl_basic_map *)bset;
+ }
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ goto error;
+ total = bset->dim->n_out + bset->extra;
+ bmap = (struct isl_basic_map *)bset;
+ isl_space_free(bmap->dim);
+ bmap->dim = isl_space_copy(like->dim);
+ if (!bmap->dim)
+ goto error;
+ bmap->n_div = like->n_div;
+ bmap->extra += like->n_div;
+ if (bmap->extra) {
+ unsigned ltotal;
+ isl_int **div;
+ ltotal = total - bmap->extra + like->extra;
+ if (ltotal > total)
+ ltotal = total;
+ bmap->block2 = isl_blk_extend(ctx, bmap->block2,
+ bmap->extra * (1 + 1 + total));
+ if (isl_blk_is_error(bmap->block2))
+ goto error;
+ div = isl_realloc_array(ctx, bmap->div, isl_int *, bmap->extra);
+ if (!div)
+ goto error;
+ bmap->div = div;
+ for (i = 0; i < bmap->extra; ++i)
+ bmap->div[i] = bmap->block2.data + i * (1 + 1 + total);
+ for (i = 0; i < like->n_div; ++i) {
+ isl_seq_cpy(bmap->div[i], like->div[i], 1 + 1 + ltotal);
+ isl_seq_clr(bmap->div[i]+1+1+ltotal, total - ltotal);
+ }
+ bmap = isl_basic_map_add_known_div_constraints(bmap);
+ }
+ isl_basic_map_free(like);
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_basic_map_free(like);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_underlying_set(
+ struct isl_basic_set *bset, struct isl_basic_set *like)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_overlying_set(bset, (struct isl_basic_map *)like);
+}
+
+struct isl_set *isl_set_from_underlying_set(
+ struct isl_set *set, struct isl_basic_set *like)
+{
+ int i;
+
+ if (!set || !like)
+ goto error;
+ isl_assert(set->ctx, set->dim->n_out == isl_basic_set_total_dim(like),
+ goto error);
+ if (isl_space_is_equal(set->dim, like->dim) && like->n_div == 0) {
+ isl_basic_set_free(like);
+ return set;
+ }
+ set = isl_set_cow(set);
+ if (!set)
+ goto error;
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_from_underlying_set(set->p[i],
+ isl_basic_set_copy(like));
+ if (!set->p[i])
+ goto error;
+ }
+ isl_space_free(set->dim);
+ set->dim = isl_space_copy(like->dim);
+ if (!set->dim)
+ goto error;
+ isl_basic_set_free(like);
+ return set;
+error:
+ isl_basic_set_free(like);
+ isl_set_free(set);
+ return NULL;
+}
+
+struct isl_set *isl_map_underlying_set(struct isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+ map->dim = isl_space_cow(map->dim);
+ if (!map->dim)
+ goto error;
+
+ for (i = 1; i < map->n; ++i)
+ isl_assert(map->ctx, map->p[0]->n_div == map->p[i]->n_div,
+ goto error);
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = (struct isl_basic_map *)
+ isl_basic_map_underlying_set(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ if (map->n == 0)
+ map->dim = isl_space_underlying(map->dim, 0);
+ else {
+ isl_space_free(map->dim);
+ map->dim = isl_space_copy(map->p[0]->dim);
+ }
+ if (!map->dim)
+ goto error;
+ return (struct isl_set *)map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_set *isl_set_to_underlying_set(struct isl_set *set)
+{
+ return (struct isl_set *)isl_map_underlying_set((struct isl_map *)set);
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+ __isl_take isl_basic_map *bmap, __isl_take isl_space *dim)
+{
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap || !dim)
+ goto error;
+
+ isl_space_free(bmap->dim);
+ bmap->dim = dim;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_space_free(dim);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+ __isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+ return (isl_basic_set *)isl_basic_map_reset_space((isl_basic_map *)bset,
+ dim);
+}
+
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+ __isl_take isl_space *dim)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map || !dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_reset_space(map->p[i],
+ isl_space_copy(dim));
+ if (!map->p[i])
+ goto error;
+ }
+ isl_space_free(map->dim);
+ map->dim = dim;
+
+ return map;
+error:
+ isl_map_free(map);
+ isl_space_free(dim);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set,
+ __isl_take isl_space *dim)
+{
+ return (struct isl_set *) isl_map_reset_space((struct isl_map *)set, dim);
+}
+
+/* Compute the parameter domain of the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset)
+{
+ isl_space *space;
+ unsigned n;
+
+ if (isl_basic_set_is_params(bset))
+ return bset;
+
+ n = isl_basic_set_dim(bset, isl_dim_set);
+ bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+ space = isl_basic_set_get_space(bset);
+ space = isl_space_params(space);
+ bset = isl_basic_set_reset_space(bset, space);
+ return bset;
+}
+
+/* Construct a zero-dimensional basic set with the given parameter domain.
+ */
+__isl_give isl_basic_set *isl_basic_set_from_params(
+ __isl_take isl_basic_set *bset)
+{
+ isl_space *space;
+ space = isl_basic_set_get_space(bset);
+ space = isl_space_set_from_params(space);
+ bset = isl_basic_set_reset_space(bset, space);
+ return bset;
+}
+
+/* Compute the parameter domain of the given set.
+ */
+__isl_give isl_set *isl_set_params(__isl_take isl_set *set)
+{
+ isl_space *space;
+ unsigned n;
+
+ if (isl_set_is_params(set))
+ return set;
+
+ n = isl_set_dim(set, isl_dim_set);
+ set = isl_set_project_out(set, isl_dim_set, 0, n);
+ space = isl_set_get_space(set);
+ space = isl_space_params(space);
+ set = isl_set_reset_space(set, space);
+ return set;
+}
+
+/* Construct a zero-dimensional set with the given parameter domain.
+ */
+__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set)
+{
+ isl_space *space;
+ space = isl_set_get_space(set);
+ space = isl_space_set_from_params(space);
+ set = isl_set_reset_space(set, space);
+ return set;
+}
+
+/* Compute the parameter domain of the given map.
+ */
+__isl_give isl_set *isl_map_params(__isl_take isl_map *map)
+{
+ isl_space *space;
+ unsigned n;
+
+ n = isl_map_dim(map, isl_dim_in);
+ map = isl_map_project_out(map, isl_dim_in, 0, n);
+ n = isl_map_dim(map, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_out, 0, n);
+ space = isl_map_get_space(map);
+ space = isl_space_params(space);
+ map = isl_map_reset_space(map, space);
+ return map;
+}
+
+struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap)
+{
+ isl_space *dim;
+ struct isl_basic_set *domain;
+ unsigned n_in;
+ unsigned n_out;
+
+ if (!bmap)
+ return NULL;
+ dim = isl_space_domain(isl_basic_map_get_space(bmap));
+
+ n_in = isl_basic_map_n_in(bmap);
+ n_out = isl_basic_map_n_out(bmap);
+ domain = isl_basic_set_from_basic_map(bmap);
+ domain = isl_basic_set_project_out(domain, isl_dim_set, n_in, n_out);
+
+ domain = isl_basic_set_reset_space(domain, dim);
+
+ return domain;
+}
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ return isl_space_may_be_set(bmap->dim);
+}
+
+/* Is this basic map actually a set?
+ * Users should never call this function. Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_basic_map_is_set(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ return isl_space_is_set(bmap->dim);
+}
+
+struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+ if (isl_basic_map_is_set(bmap))
+ return bmap;
+ return isl_basic_map_domain(isl_basic_map_reverse(bmap));
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_map(
+ __isl_take isl_basic_map *bmap)
+{
+ int i, k;
+ isl_space *dim;
+ isl_basic_map *domain;
+ int nparam, n_in, n_out;
+ unsigned total;
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ n_in = isl_basic_map_dim(bmap, isl_dim_in);
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+ dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+ domain = isl_basic_map_universe(dim);
+
+ bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+ bmap = isl_basic_map_apply_range(bmap, domain);
+ bmap = isl_basic_map_extend_constraints(bmap, n_in, 0);
+
+ total = isl_basic_map_total_dim(bmap);
+
+ for (i = 0; i < n_in; ++i) {
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[k], 1 + total);
+ isl_int_set_si(bmap->eq[k][1 + nparam + i], -1);
+ isl_int_set_si(bmap->eq[k][1 + nparam + n_in + n_out + i], 1);
+ }
+
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_map(
+ __isl_take isl_basic_map *bmap)
+{
+ int i, k;
+ isl_space *dim;
+ isl_basic_map *range;
+ int nparam, n_in, n_out;
+ unsigned total;
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ n_in = isl_basic_map_dim(bmap, isl_dim_in);
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+ dim = isl_space_from_range(isl_space_range(isl_basic_map_get_space(bmap)));
+ range = isl_basic_map_universe(dim);
+
+ bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+ bmap = isl_basic_map_apply_range(bmap, range);
+ bmap = isl_basic_map_extend_constraints(bmap, n_out, 0);
+
+ total = isl_basic_map_total_dim(bmap);
+
+ for (i = 0; i < n_out; ++i) {
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[k], 1 + total);
+ isl_int_set_si(bmap->eq[k][1 + nparam + n_in + i], -1);
+ isl_int_set_si(bmap->eq[k][1 + nparam + n_in + n_out + i], 1);
+ }
+
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+int isl_map_may_be_set(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+ return isl_space_may_be_set(map->dim);
+}
+
+/* Is this map actually a set?
+ * Users should never call this function. Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_map_is_set(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+ return isl_space_is_set(map->dim);
+}
+
+struct isl_set *isl_map_range(struct isl_map *map)
+{
+ int i;
+ struct isl_set *set;
+
+ if (!map)
+ goto error;
+ if (isl_map_is_set(map))
+ return (isl_set *)map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ goto error;
+
+ set = (struct isl_set *) map;
+ set->dim = isl_space_range(set->dim);
+ if (!set->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ set->p[i] = isl_basic_map_range(map->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+ ISL_F_CLR(set, ISL_MAP_DISJOINT);
+ ISL_F_CLR(set, ISL_SET_NORMALIZED);
+ return set;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_domain_map(map->dim);
+ if (!map->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_domain_map(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_DISJOINT);
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map)
+{
+ int i;
+ isl_space *range_dim;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ range_dim = isl_space_range(isl_map_get_space(map));
+ range_dim = isl_space_from_range(range_dim);
+ map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+ map->dim = isl_space_join(map->dim, range_dim);
+ if (!map->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_range_map(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_DISJOINT);
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Given a wrapped map of the form A[B -> C],
+ * return the map A[B -> C] -> B.
+ */
+__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set)
+{
+ isl_id *id;
+ isl_map *map;
+
+ if (!set)
+ return NULL;
+ if (!isl_set_has_tuple_id(set))
+ return isl_map_domain_map(isl_set_unwrap(set));
+
+ id = isl_set_get_tuple_id(set);
+ map = isl_map_domain_map(isl_set_unwrap(set));
+ map = isl_map_set_tuple_id(map, isl_dim_in, id);
+
+ return map;
+}
+
+__isl_give isl_map *isl_map_from_set(__isl_take isl_set *set,
+ __isl_take isl_space *dim)
+{
+ int i;
+ struct isl_map *map = NULL;
+
+ set = isl_set_cow(set);
+ if (!set || !dim)
+ goto error;
+ isl_assert(set->ctx, isl_space_compatible(set->dim, dim), goto error);
+ map = (struct isl_map *)set;
+ for (i = 0; i < set->n; ++i) {
+ map->p[i] = isl_basic_map_from_basic_set(
+ set->p[i], isl_space_copy(dim));
+ if (!map->p[i])
+ goto error;
+ }
+ isl_space_free(map->dim);
+ map->dim = dim;
+ return map;
+error:
+ isl_space_free(dim);
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain(
+ __isl_take isl_basic_set *bset)
+{
+ return isl_basic_map_reverse(isl_basic_map_from_range(bset));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_range(
+ __isl_take isl_basic_set *bset)
+{
+ isl_space *space;
+ space = isl_basic_set_get_space(bset);
+ space = isl_space_from_range(space);
+ bset = isl_basic_set_reset_space(bset, space);
+ return (isl_basic_map *)bset;
+}
+
+/* Create a relation with the given set as range.
+ * The domain of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set)
+{
+ isl_space *space;
+ space = isl_set_get_space(set);
+ space = isl_space_from_range(space);
+ set = isl_set_reset_space(set, space);
+ return (struct isl_map *)set;
+}
+
+/* Create a relation with the given set as domain.
+ * The range of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set)
+{
+ return isl_map_reverse(isl_map_from_range(set));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain_and_range(
+ __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range)
+{
+ return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range);
+}
+
+__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain,
+ __isl_take isl_set *range)
+{
+ return isl_map_apply_range(isl_map_reverse(domain), range);
+}
+
+struct isl_set *isl_set_from_map(struct isl_map *map)
+{
+ int i;
+ struct isl_set *set = NULL;
+
+ if (!map)
+ return NULL;
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+ map->dim = isl_space_as_set_space(map->dim);
+ if (!map->dim)
+ goto error;
+ set = (struct isl_set *)map;
+ for (i = 0; i < map->n; ++i) {
+ set->p[i] = isl_basic_set_from_basic_map(map->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+ return set;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+ unsigned flags)
+{
+ struct isl_map *map;
+
+ if (!dim)
+ return NULL;
+ if (n < 0)
+ isl_die(dim->ctx, isl_error_internal,
+ "negative number of basic maps", goto error);
+ map = isl_alloc(dim->ctx, struct isl_map,
+ sizeof(struct isl_map) +
+ (n - 1) * sizeof(struct isl_basic_map *));
+ if (!map)
+ goto error;
+
+ map->ctx = dim->ctx;
+ isl_ctx_ref(map->ctx);
+ map->ref = 1;
+ map->size = n;
+ map->n = 0;
+ map->dim = dim;
+ map->flags = flags;
+ return map;
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_map *isl_map_alloc(struct isl_ctx *ctx,
+ unsigned nparam, unsigned in, unsigned out, int n,
+ unsigned flags)
+{
+ struct isl_map *map;
+ isl_space *dims;
+
+ dims = isl_space_alloc(ctx, nparam, in, out);
+ if (!dims)
+ return NULL;
+
+ map = isl_map_alloc_space(dims, n, flags);
+ return map;
+}
+
+__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *dim)
+{
+ struct isl_basic_map *bmap;
+ bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
+ bmap = isl_basic_map_set_to_empty(bmap);
+ return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *dim)
+{
+ struct isl_basic_set *bset;
+ bset = isl_basic_set_alloc_space(dim, 0, 1, 0);
+ bset = isl_basic_set_set_to_empty(bset);
+ return bset;
+}
+
+struct isl_basic_map *isl_basic_map_empty_like(struct isl_basic_map *model)
+{
+ struct isl_basic_map *bmap;
+ if (!model)
+ return NULL;
+ bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+ bmap = isl_basic_map_set_to_empty(bmap);
+ return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_empty_like_map(struct isl_map *model)
+{
+ struct isl_basic_map *bmap;
+ if (!model)
+ return NULL;
+ bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+ bmap = isl_basic_map_set_to_empty(bmap);
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_empty_like(struct isl_basic_set *model)
+{
+ struct isl_basic_set *bset;
+ if (!model)
+ return NULL;
+ bset = isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
+ bset = isl_basic_set_set_to_empty(bset);
+ return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *dim)
+{
+ struct isl_basic_map *bmap;
+ bmap = isl_basic_map_alloc_space(dim, 0, 0, 0);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *dim)
+{
+ struct isl_basic_set *bset;
+ bset = isl_basic_set_alloc_space(dim, 0, 0, 0);
+ bset = isl_basic_set_finalize(bset);
+ return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim)
+{
+ int i;
+ unsigned total = isl_space_dim(dim, isl_dim_all);
+ isl_basic_map *bmap;
+
+ bmap= isl_basic_map_alloc_space(dim, 0, 0, total);
+ for (i = 0; i < total; ++i) {
+ int k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bmap->ineq[k], 1 + total);
+ isl_int_set_si(bmap->ineq[k][1 + i], 1);
+ }
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim)
+{
+ return isl_basic_map_nat_universe(dim);
+}
+
+__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim)
+{
+ return isl_map_from_basic_map(isl_basic_map_nat_universe(dim));
+}
+
+__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim)
+{
+ return isl_map_nat_universe(dim);
+}
+
+__isl_give isl_basic_map *isl_basic_map_universe_like(
+ __isl_keep isl_basic_map *model)
+{
+ if (!model)
+ return NULL;
+ return isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+struct isl_basic_set *isl_basic_set_universe_like(struct isl_basic_set *model)
+{
+ if (!model)
+ return NULL;
+ return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+__isl_give isl_basic_set *isl_basic_set_universe_like_set(
+ __isl_keep isl_set *model)
+{
+ if (!model)
+ return NULL;
+ return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
+}
+
+__isl_give isl_map *isl_map_empty(__isl_take isl_space *dim)
+{
+ return isl_map_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_map *isl_map_empty_like(struct isl_map *model)
+{
+ if (!model)
+ return NULL;
+ return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_map *isl_map_empty_like_basic_map(struct isl_basic_map *model)
+{
+ if (!model)
+ return NULL;
+ return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
+}
+
+__isl_give isl_set *isl_set_empty(__isl_take isl_space *dim)
+{
+ return isl_set_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+struct isl_set *isl_set_empty_like(struct isl_set *model)
+{
+ if (!model)
+ return NULL;
+ return isl_set_empty(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_map_universe(__isl_take isl_space *dim)
+{
+ struct isl_map *map;
+ if (!dim)
+ return NULL;
+ map = isl_map_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+ map = isl_map_add_basic_map(map, isl_basic_map_universe(dim));
+ return map;
+}
+
+__isl_give isl_set *isl_set_universe(__isl_take isl_space *dim)
+{
+ struct isl_set *set;
+ if (!dim)
+ return NULL;
+ set = isl_set_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+ set = isl_set_add_basic_set(set, isl_basic_set_universe(dim));
+ return set;
+}
+
+__isl_give isl_set *isl_set_universe_like(__isl_keep isl_set *model)
+{
+ if (!model)
+ return NULL;
+ return isl_set_universe(isl_space_copy(model->dim));
+}
+
+struct isl_map *isl_map_dup(struct isl_map *map)
+{
+ int i;
+ struct isl_map *dup;
+
+ if (!map)
+ return NULL;
+ dup = isl_map_alloc_space(isl_space_copy(map->dim), map->n, map->flags);
+ for (i = 0; i < map->n; ++i)
+ dup = isl_map_add_basic_map(dup, isl_basic_map_copy(map->p[i]));
+ return dup;
+}
+
+__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
+ __isl_take isl_basic_map *bmap)
+{
+ if (!bmap || !map)
+ goto error;
+ if (isl_basic_map_plain_is_empty(bmap)) {
+ isl_basic_map_free(bmap);
+ return map;
+ }
+ isl_assert(map->ctx, isl_space_is_equal(map->dim, bmap->dim), goto error);
+ isl_assert(map->ctx, map->n < map->size, goto error);
+ map->p[map->n] = bmap;
+ map->n++;
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ if (map)
+ isl_map_free(map);
+ if (bmap)
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_null isl_map *isl_map_free(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (--map->ref > 0)
+ return NULL;
+
+ isl_ctx_deref(map->ctx);
+ for (i = 0; i < map->n; ++i)
+ isl_basic_map_free(map->p[i]);
+ isl_space_free(map->dim);
+ free(map);
+
+ return NULL;
+}
+
+struct isl_map *isl_map_extend(struct isl_map *base,
+ unsigned nparam, unsigned n_in, unsigned n_out)
+{
+ int i;
+
+ base = isl_map_cow(base);
+ if (!base)
+ return NULL;
+
+ base->dim = isl_space_extend(base->dim, nparam, n_in, n_out);
+ if (!base->dim)
+ goto error;
+ for (i = 0; i < base->n; ++i) {
+ base->p[i] = isl_basic_map_extend_space(base->p[i],
+ isl_space_copy(base->dim), 0, 0, 0);
+ if (!base->p[i])
+ goto error;
+ }
+ return base;
+error:
+ isl_map_free(base);
+ return NULL;
+}
+
+struct isl_set *isl_set_extend(struct isl_set *base,
+ unsigned nparam, unsigned dim)
+{
+ return (struct isl_set *)isl_map_extend((struct isl_map *)base,
+ nparam, 0, dim);
+}
+
+static struct isl_basic_map *isl_basic_map_fix_pos_si(
+ struct isl_basic_map *bmap, unsigned pos, int value)
+{
+ int j;
+
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+ j = isl_basic_map_alloc_equality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->eq[j][pos], -1);
+ isl_int_set_si(bmap->eq[j][0], value);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static __isl_give isl_basic_map *isl_basic_map_fix_pos(
+ __isl_take isl_basic_map *bmap, unsigned pos, isl_int value)
+{
+ int j;
+
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+ j = isl_basic_map_alloc_equality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->eq[j][pos], -1);
+ isl_int_set(bmap->eq[j][0], value);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_fix_si(struct isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ if (!bmap)
+ return NULL;
+ isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+ return isl_basic_map_fix_pos_si(bmap,
+ isl_basic_map_offset(bmap, type) + pos, value);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ if (!bmap)
+ return NULL;
+ isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+ return isl_basic_map_fix_pos(bmap,
+ isl_basic_map_offset(bmap, type) + pos, value);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bmap"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+ if (!bmap || !v)
+ goto error;
+ if (!isl_val_is_int(v))
+ isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+ "expecting integer value", goto error);
+ if (pos >= isl_basic_map_dim(bmap, type))
+ isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+ "index out of bounds", goto error);
+ pos += isl_basic_map_offset(bmap, type);
+ bmap = isl_basic_map_fix_pos(bmap, pos, v->n);
+ isl_val_free(v);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_val_free(v);
+ return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bset"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+ return isl_basic_map_fix_val(bset, type, pos, v);
+}
+
+struct isl_basic_set *isl_basic_set_fix_si(struct isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_fix_si((struct isl_basic_map *)bset,
+ type, pos, value);
+}
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_fix((struct isl_basic_map *)bset,
+ type, pos, value);
+}
+
+struct isl_basic_map *isl_basic_map_fix_input_si(struct isl_basic_map *bmap,
+ unsigned input, int value)
+{
+ return isl_basic_map_fix_si(bmap, isl_dim_in, input, value);
+}
+
+struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset,
+ unsigned dim, int value)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_fix_si((struct isl_basic_map *)bset,
+ isl_dim_set, dim, value);
+}
+
+static int remove_if_empty(__isl_keep isl_map *map, int i)
+{
+ int empty = isl_basic_map_plain_is_empty(map->p[i]);
+
+ if (empty < 0)
+ return -1;
+ if (!empty)
+ return 0;
+
+ isl_basic_map_free(map->p[i]);
+ if (i != map->n - 1) {
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ map->p[i] = map->p[map->n - 1];
+ }
+ map->n--;
+
+ return 0;
+}
+
+/* Perform "fn" on each basic map of "map", where we may not be holding
+ * the only reference to "map".
+ * In particular, "fn" should be a semantics preserving operation
+ * that we want to apply to all copies of "map". We therefore need
+ * to be careful not to modify "map" in a way that breaks "map"
+ * in case anything goes wrong.
+ */
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+ __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap))
+{
+ struct isl_basic_map *bmap;
+ int i;
+
+ if (!map)
+ return NULL;
+
+ for (i = map->n - 1; i >= 0; --i) {
+ bmap = isl_basic_map_copy(map->p[i]);
+ bmap = fn(bmap);
+ if (!bmap)
+ goto error;
+ isl_basic_map_free(map->p[i]);
+ map->p[i] = bmap;
+ if (remove_if_empty(map, i) < 0)
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_map *isl_map_fix_si(struct isl_map *map,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+ for (i = map->n - 1; i >= 0; --i) {
+ map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value);
+ if (remove_if_empty(map, i) < 0)
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return (struct isl_set *)
+ isl_map_fix_si((struct isl_map *)set, type, pos, value);
+}
+
+__isl_give isl_map *isl_map_fix(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_fix(map->p[i], type, pos, value);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return (struct isl_set *)isl_map_fix((isl_map *)set, type, pos, value);
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "map"
+ * to be equal to "v".
+ */
+__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map || !v)
+ goto error;
+
+ if (!isl_val_is_int(v))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "expecting integer value", goto error);
+ if (pos >= isl_map_dim(map, type))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "index out of bounds", goto error);
+ for (i = map->n - 1; i >= 0; --i) {
+ map->p[i] = isl_basic_map_fix_val(map->p[i], type, pos,
+ isl_val_copy(v));
+ if (remove_if_empty(map, i) < 0)
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ isl_val_free(v);
+ return map;
+error:
+ isl_map_free(map);
+ isl_val_free(v);
+ return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "set"
+ * to be equal to "v".
+ */
+__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+ return isl_map_fix_val(set, type, pos, v);
+}
+
+struct isl_map *isl_map_fix_input_si(struct isl_map *map,
+ unsigned input, int value)
+{
+ return isl_map_fix_si(map, isl_dim_in, input, value);
+}
+
+struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value)
+{
+ return (struct isl_set *)
+ isl_map_fix_si((struct isl_map *)set, isl_dim_set, dim, value);
+}
+
+static __isl_give isl_basic_map *basic_map_bound_si(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+ int j;
+
+ if (!bmap)
+ return NULL;
+ isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+ pos += isl_basic_map_offset(bmap, type);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+ j = isl_basic_map_alloc_inequality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+ if (upper) {
+ isl_int_set_si(bmap->ineq[j][pos], -1);
+ isl_int_set_si(bmap->ineq[j][0], value);
+ } else {
+ isl_int_set_si(bmap->ineq[j][pos], 1);
+ isl_int_set_si(bmap->ineq[j][0], -value);
+ }
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return basic_map_bound_si(bmap, type, pos, value, 0);
+}
+
+/* Constrain the values of the given dimension to be no greater than "value".
+ */
+__isl_give isl_basic_map *isl_basic_map_upper_bound_si(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return basic_map_bound_si(bmap, type, pos, value, 1);
+}
+
+struct isl_basic_set *isl_basic_set_lower_bound_dim(struct isl_basic_set *bset,
+ unsigned dim, isl_int value)
+{
+ int j;
+
+ bset = isl_basic_set_cow(bset);
+ bset = isl_basic_set_extend_constraints(bset, 0, 1);
+ j = isl_basic_set_alloc_inequality(bset);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bset->ineq[j], 1 + isl_basic_set_total_dim(bset));
+ isl_int_set_si(bset->ineq[j][1 + isl_basic_set_n_param(bset) + dim], 1);
+ isl_int_neg(bset->ineq[j][0], value);
+ bset = isl_basic_set_simplify(bset);
+ return isl_basic_set_finalize(bset);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+static __isl_give isl_map *map_bound_si(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = basic_map_bound_si(map->p[i],
+ type, pos, value, upper);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return map_bound_si(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return map_bound_si(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return (struct isl_set *)
+ isl_map_lower_bound_si((struct isl_map *)set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, int value)
+{
+ return isl_map_upper_bound_si(set, type, pos, value);
+}
+
+/* Bound the given variable of "bmap" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_map *basic_map_bound(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+ int j;
+
+ if (!bmap)
+ return NULL;
+ if (pos >= isl_basic_map_dim(bmap, type))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+ pos += isl_basic_map_offset(bmap, type);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+ j = isl_basic_map_alloc_inequality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+ if (upper) {
+ isl_int_set_si(bmap->ineq[j][pos], -1);
+ isl_int_set(bmap->ineq[j][0], value);
+ } else {
+ isl_int_set_si(bmap->ineq[j][pos], 1);
+ isl_int_neg(bmap->ineq[j][0], value);
+ }
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Bound the given variable of "map" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_map *map_bound(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ if (pos >= isl_map_dim(map, type))
+ isl_die(map->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+ for (i = map->n - 1; i >= 0; --i) {
+ map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper);
+ if (remove_if_empty(map, i) < 0)
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return map_bound(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return map_bound(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return isl_map_lower_bound(set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, isl_int value)
+{
+ return isl_map_upper_bound(set, type, pos, value);
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no smaller than "value".
+ */
+__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+ if (!value)
+ goto error;
+ if (!isl_val_is_int(value))
+ isl_die(isl_set_get_ctx(set), isl_error_invalid,
+ "expecting integer value", goto error);
+ set = isl_set_lower_bound(set, type, pos, value->n);
+ isl_val_free(value);
+ return set;
+error:
+ isl_val_free(value);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no greater than "value".
+ */
+__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+ if (!value)
+ goto error;
+ if (!isl_val_is_int(value))
+ isl_die(isl_set_get_ctx(set), isl_error_invalid,
+ "expecting integer value", goto error);
+ set = isl_set_upper_bound(set, type, pos, value->n);
+ isl_val_free(value);
+ return set;
+error:
+ isl_val_free(value);
+ isl_set_free(set);
+ return NULL;
+}
+
+struct isl_set *isl_set_lower_bound_dim(struct isl_set *set, unsigned dim,
+ isl_int value)
+{
+ int i;
+
+ set = isl_set_cow(set);
+ if (!set)
+ return NULL;
+
+ isl_assert(set->ctx, dim < isl_set_n_dim(set), goto error);
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_lower_bound_dim(set->p[i], dim, value);
+ if (!set->p[i])
+ goto error;
+ }
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+struct isl_map *isl_map_reverse(struct isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ map->dim = isl_space_reverse(map->dim);
+ if (!map->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_reverse(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+static struct isl_map *isl_basic_map_partial_lexopt(
+ struct isl_basic_map *bmap, struct isl_basic_set *dom,
+ struct isl_set **empty, int max)
+{
+ return isl_tab_basic_map_partial_lexopt(bmap, dom, empty, max);
+}
+
+struct isl_map *isl_basic_map_partial_lexmax(
+ struct isl_basic_map *bmap, struct isl_basic_set *dom,
+ struct isl_set **empty)
+{
+ return isl_basic_map_partial_lexopt(bmap, dom, empty, 1);
+}
+
+struct isl_map *isl_basic_map_partial_lexmin(
+ struct isl_basic_map *bmap, struct isl_basic_set *dom,
+ struct isl_set **empty)
+{
+ return isl_basic_map_partial_lexopt(bmap, dom, empty, 0);
+}
+
+struct isl_set *isl_basic_set_partial_lexmin(
+ struct isl_basic_set *bset, struct isl_basic_set *dom,
+ struct isl_set **empty)
+{
+ return (struct isl_set *)
+ isl_basic_map_partial_lexmin((struct isl_basic_map *)bset,
+ dom, empty);
+}
+
+struct isl_set *isl_basic_set_partial_lexmax(
+ struct isl_basic_set *bset, struct isl_basic_set *dom,
+ struct isl_set **empty)
+{
+ return (struct isl_set *)
+ isl_basic_map_partial_lexmax((struct isl_basic_map *)bset,
+ dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff(
+ __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 0);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff(
+ __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 1);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff(
+ __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_basic_map_partial_lexmin_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff(
+ __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_basic_map_partial_lexmax_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexopt_pw_multi_aff(
+ __isl_take isl_basic_map *bmap, int max)
+{
+ isl_basic_set *dom = NULL;
+ isl_space *dom_space;
+
+ if (!bmap)
+ goto error;
+ dom_space = isl_space_domain(isl_space_copy(bmap->dim));
+ dom = isl_basic_set_universe(dom_space);
+ return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, NULL, max);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff(
+ __isl_take isl_basic_map *bmap)
+{
+ return isl_basic_map_lexopt_pw_multi_aff(bmap, 0);
+}
+
+#undef TYPE
+#define TYPE isl_pw_multi_aff
+#undef SUFFIX
+#define SUFFIX _pw_multi_aff
+#undef EMPTY
+#define EMPTY isl_pw_multi_aff_empty
+#undef ADD
+#define ADD isl_pw_multi_aff_union_add
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom,
+ * in the form of an isl_pw_multi_aff.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first compute the lexicographically minimal or maximal element
+ * in the first basic map. This results in a partial solution "res"
+ * and a subset "todo" of dom that still need to be handled.
+ * We then consider each of the remaining maps in "map" and successively
+ * update both "res" and "todo".
+ */
+static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty, int max)
+{
+ int i;
+ isl_pw_multi_aff *res;
+ isl_set *todo;
+
+ if (!map || !dom)
+ goto error;
+
+ if (isl_map_plain_is_empty(map)) {
+ if (empty)
+ *empty = dom;
+ else
+ isl_set_free(dom);
+ return isl_pw_multi_aff_from_map(map);
+ }
+
+ res = basic_map_partial_lexopt_pw_multi_aff(
+ isl_basic_map_copy(map->p[0]),
+ isl_set_copy(dom), &todo, max);
+
+ for (i = 1; i < map->n; ++i) {
+ isl_pw_multi_aff *res_i;
+ isl_set *todo_i;
+
+ res_i = basic_map_partial_lexopt_pw_multi_aff(
+ isl_basic_map_copy(map->p[i]),
+ isl_set_copy(dom), &todo_i, max);
+
+ if (max)
+ res = isl_pw_multi_aff_union_lexmax(res, res_i);
+ else
+ res = isl_pw_multi_aff_union_lexmin(res, res_i);
+
+ todo = isl_set_intersect(todo, todo_i);
+ }
+
+ isl_set_free(dom);
+ isl_map_free(map);
+
+ if (empty)
+ *empty = todo;
+ else
+ isl_set_free(todo);
+
+ return res;
+error:
+ if (empty)
+ *empty = NULL;
+ isl_set_free(dom);
+ isl_map_free(map);
+ return NULL;
+}
+
+#undef TYPE
+#define TYPE isl_map
+#undef SUFFIX
+#define SUFFIX
+#undef EMPTY
+#define EMPTY isl_map_empty
+#undef ADD
+#define ADD isl_map_union_disjoint
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first compute the lexicographically minimal or maximal element
+ * in the first basic map. This results in a partial solution "res"
+ * and a subset "todo" of dom that still need to be handled.
+ * We then consider each of the remaining maps in "map" and successively
+ * update both "res" and "todo".
+ *
+ * Let res^k and todo^k be the results after k steps and let i = k + 1.
+ * Assume we are computing the lexicographical maximum.
+ * We first compute the lexicographically maximal element in basic map i.
+ * This results in a partial solution res_i and a subset todo_i.
+ * Then we combine these results with those obtain for the first k basic maps
+ * to obtain a result that is valid for the first k+1 basic maps.
+ * In particular, the set where there is no solution is the set where
+ * there is no solution for the first k basic maps and also no solution
+ * for the ith basic map, i.e.,
+ *
+ * todo^i = todo^k * todo_i
+ *
+ * On dom(res^k) * dom(res_i), we need to pick the larger of the two
+ * solutions, arbitrarily breaking ties in favor of res^k.
+ * That is, when res^k(a) >= res_i(a), we pick res^k and
+ * when res^k(a) < res_i(a), we pick res_i. (Here, ">=" and "<" denote
+ * the lexicographic order.)
+ * In practice, we compute
+ *
+ * res^k * (res_i . "<=")
+ *
+ * and
+ *
+ * res_i * (res^k . "<")
+ *
+ * Finally, we consider the symmetric difference of dom(res^k) and dom(res_i),
+ * where only one of res^k and res_i provides a solution and we simply pick
+ * that one, i.e.,
+ *
+ * res^k * todo_i
+ * and
+ * res_i * todo^k
+ *
+ * Note that we only compute these intersections when dom(res^k) intersects
+ * dom(res_i). Otherwise, the only effect of these intersections is to
+ * potentially break up res^k and res_i into smaller pieces.
+ * We want to avoid such splintering as much as possible.
+ * In fact, an earlier implementation of this function would look for
+ * better results in the domain of res^k and for extra results in todo^k,
+ * but this would always result in a splintering according to todo^k,
+ * even when the domain of basic map i is disjoint from the domains of
+ * the previous basic maps.
+ */
+static __isl_give isl_map *isl_map_partial_lexopt_aligned(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty, int max)
+{
+ int i;
+ struct isl_map *res;
+ struct isl_set *todo;
+
+ if (!map || !dom)
+ goto error;
+
+ if (isl_map_plain_is_empty(map)) {
+ if (empty)
+ *empty = dom;
+ else
+ isl_set_free(dom);
+ return map;
+ }
+
+ res = basic_map_partial_lexopt(isl_basic_map_copy(map->p[0]),
+ isl_set_copy(dom), &todo, max);
+
+ for (i = 1; i < map->n; ++i) {
+ isl_map *lt, *le;
+ isl_map *res_i;
+ isl_set *todo_i;
+ isl_space *dim = isl_space_range(isl_map_get_space(res));
+
+ res_i = basic_map_partial_lexopt(isl_basic_map_copy(map->p[i]),
+ isl_set_copy(dom), &todo_i, max);
+
+ if (max) {
+ lt = isl_map_lex_lt(isl_space_copy(dim));
+ le = isl_map_lex_le(dim);
+ } else {
+ lt = isl_map_lex_gt(isl_space_copy(dim));
+ le = isl_map_lex_ge(dim);
+ }
+ lt = isl_map_apply_range(isl_map_copy(res), lt);
+ lt = isl_map_intersect(lt, isl_map_copy(res_i));
+ le = isl_map_apply_range(isl_map_copy(res_i), le);
+ le = isl_map_intersect(le, isl_map_copy(res));
+
+ if (!isl_map_is_empty(lt) || !isl_map_is_empty(le)) {
+ res = isl_map_intersect_domain(res,
+ isl_set_copy(todo_i));
+ res_i = isl_map_intersect_domain(res_i,
+ isl_set_copy(todo));
+ }
+
+ res = isl_map_union_disjoint(res, res_i);
+ res = isl_map_union_disjoint(res, lt);
+ res = isl_map_union_disjoint(res, le);
+
+ todo = isl_set_intersect(todo, todo_i);
+ }
+
+ isl_set_free(dom);
+ isl_map_free(map);
+
+ if (empty)
+ *empty = todo;
+ else
+ isl_set_free(todo);
+
+ return res;
+error:
+ if (empty)
+ *empty = NULL;
+ isl_set_free(dom);
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_partial_lexmax(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_map_partial_lexopt(map, dom, empty, 1);
+}
+
+__isl_give isl_map *isl_map_partial_lexmin(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty)
+{
+ return isl_map_partial_lexopt(map, dom, empty, 0);
+}
+
+__isl_give isl_set *isl_set_partial_lexmin(
+ __isl_take isl_set *set, __isl_take isl_set *dom,
+ __isl_give isl_set **empty)
+{
+ return (struct isl_set *)
+ isl_map_partial_lexmin((struct isl_map *)set,
+ dom, empty);
+}
+
+__isl_give isl_set *isl_set_partial_lexmax(
+ __isl_take isl_set *set, __isl_take isl_set *dom,
+ __isl_give isl_set **empty)
+{
+ return (struct isl_set *)
+ isl_map_partial_lexmax((struct isl_map *)set,
+ dom, empty);
+}
+
+/* Compute the lexicographic minimum (or maximum if "max" is set)
+ * of "bmap" over its domain.
+ *
+ * Since we are not interested in the part of the domain space where
+ * there is no solution, we initialize the domain to those constraints
+ * of "bmap" that only involve the parameters and the input dimensions.
+ * This relieves the parametric programming engine from detecting those
+ * inequalities and transferring them to the context. More importantly,
+ * it ensures that those inequalities are transferred first and not
+ * intermixed with inequalities that actually split the domain.
+ */
+__isl_give isl_map *isl_basic_map_lexopt(__isl_take isl_basic_map *bmap, int max)
+{
+ int n_div;
+ int n_out;
+ isl_basic_map *copy;
+ isl_basic_set *dom;
+
+ n_div = isl_basic_map_dim(bmap, isl_dim_div);
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+ copy = isl_basic_map_copy(bmap);
+ copy = isl_basic_map_drop_constraints_involving_dims(copy,
+ isl_dim_div, 0, n_div);
+ copy = isl_basic_map_drop_constraints_involving_dims(copy,
+ isl_dim_out, 0, n_out);
+ dom = isl_basic_map_domain(copy);
+ return isl_basic_map_partial_lexopt(bmap, dom, NULL, max);
+}
+
+__isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap)
+{
+ return isl_basic_map_lexopt(bmap, 0);
+}
+
+__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap)
+{
+ return isl_basic_map_lexopt(bmap, 1);
+}
+
+__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset)
+{
+ return (isl_set *)isl_basic_map_lexmin((isl_basic_map *)bset);
+}
+
+__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
+{
+ return (isl_set *)isl_basic_map_lexmax((isl_basic_map *)bset);
+}
+
+/* Extract the first and only affine expression from list
+ * and then add it to *pwaff with the given dom.
+ * This domain is known to be disjoint from other domains
+ * because of the way isl_basic_map_foreach_lexmax works.
+ */
+static int update_dim_opt(__isl_take isl_basic_set *dom,
+ __isl_take isl_aff_list *list, void *user)
+{
+ isl_ctx *ctx = isl_basic_set_get_ctx(dom);
+ isl_aff *aff;
+ isl_pw_aff **pwaff = user;
+ isl_pw_aff *pwaff_i;
+
+ if (!list)
+ goto error;
+ if (isl_aff_list_n_aff(list) != 1)
+ isl_die(ctx, isl_error_internal,
+ "expecting single element list", goto error);
+
+ aff = isl_aff_list_get_aff(list, 0);
+ pwaff_i = isl_pw_aff_alloc(isl_set_from_basic_set(dom), aff);
+
+ *pwaff = isl_pw_aff_add_disjoint(*pwaff, pwaff_i);
+
+ isl_aff_list_free(list);
+
+ return 0;
+error:
+ isl_basic_set_free(dom);
+ isl_aff_list_free(list);
+ return -1;
+}
+
+/* Given a basic map with one output dimension, compute the minimum or
+ * maximum of that dimension as an isl_pw_aff.
+ *
+ * The isl_pw_aff is constructed by having isl_basic_map_foreach_lexopt
+ * call update_dim_opt on each leaf of the result.
+ */
+static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap,
+ int max)
+{
+ isl_space *dim = isl_basic_map_get_space(bmap);
+ isl_pw_aff *pwaff;
+ int r;
+
+ dim = isl_space_from_domain(isl_space_domain(dim));
+ dim = isl_space_add_dims(dim, isl_dim_out, 1);
+ pwaff = isl_pw_aff_empty(dim);
+
+ r = isl_basic_map_foreach_lexopt(bmap, max, &update_dim_opt, &pwaff);
+ if (r < 0)
+ return isl_pw_aff_free(pwaff);
+
+ return pwaff;
+}
+
+/* Compute the minimum or maximum of the given output dimension
+ * as a function of the parameters and the input dimensions,
+ * but independently of the other output dimensions.
+ *
+ * We first project out the other output dimension and then compute
+ * the "lexicographic" maximum in each basic map, combining the results
+ * using isl_pw_aff_union_max.
+ */
+static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos,
+ int max)
+{
+ int i;
+ isl_pw_aff *pwaff;
+ unsigned n_out;
+
+ n_out = isl_map_dim(map, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1));
+ map = isl_map_project_out(map, isl_dim_out, 0, pos);
+ if (!map)
+ return NULL;
+
+ if (map->n == 0) {
+ isl_space *dim = isl_map_get_space(map);
+ isl_map_free(map);
+ return isl_pw_aff_empty(dim);
+ }
+
+ pwaff = basic_map_dim_opt(map->p[0], max);
+ for (i = 1; i < map->n; ++i) {
+ isl_pw_aff *pwaff_i;
+
+ pwaff_i = basic_map_dim_opt(map->p[i], max);
+ pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max);
+ }
+
+ isl_map_free(map);
+
+ return pwaff;
+}
+
+/* Compute the maximum of the given output dimension as a function of the
+ * parameters and input dimensions, but independently of
+ * the other output dimensions.
+ */
+__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos)
+{
+ return map_dim_opt(map, pos, 1);
+}
+
+/* Compute the minimum or maximum of the given set dimension
+ * as a function of the parameters,
+ * but independently of the other set dimensions.
+ */
+static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos,
+ int max)
+{
+ return map_dim_opt(set, pos, max);
+}
+
+/* Compute the maximum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos)
+{
+ return set_dim_opt(set, pos, 1);
+}
+
+/* Compute the minimum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos)
+{
+ return set_dim_opt(set, pos, 0);
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "bset".
+ * bset is assumed to have only parameters and divs.
+ */
+static struct isl_basic_set *basic_set_parameter_preimage(
+ struct isl_basic_set *bset, struct isl_mat *mat)
+{
+ unsigned nparam;
+
+ if (!bset || !mat)
+ goto error;
+
+ bset->dim = isl_space_cow(bset->dim);
+ if (!bset->dim)
+ goto error;
+
+ nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+ isl_assert(bset->ctx, mat->n_row == 1 + nparam, goto error);
+
+ bset->dim->nparam = 0;
+ bset->dim->n_out = nparam;
+ bset = isl_basic_set_preimage(bset, mat);
+ if (bset) {
+ bset->dim->nparam = bset->dim->n_out;
+ bset->dim->n_out = 0;
+ }
+ return bset;
+error:
+ isl_mat_free(mat);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "set".
+ * set is assumed to have only parameters and divs.
+ */
+static struct isl_set *set_parameter_preimage(
+ struct isl_set *set, struct isl_mat *mat)
+{
+ isl_space *dim = NULL;
+ unsigned nparam;
+
+ if (!set || !mat)
+ goto error;
+
+ dim = isl_space_copy(set->dim);
+ dim = isl_space_cow(dim);
+ if (!dim)
+ goto error;
+
+ nparam = isl_set_dim(set, isl_dim_param);
+
+ isl_assert(set->ctx, mat->n_row == 1 + nparam, goto error);
+
+ dim->nparam = 0;
+ dim->n_out = nparam;
+ isl_set_reset_space(set, dim);
+ set = isl_set_preimage(set, mat);
+ if (!set)
+ goto error2;
+ dim = isl_space_copy(set->dim);
+ dim = isl_space_cow(dim);
+ if (!dim)
+ goto error2;
+ dim->nparam = dim->n_out;
+ dim->n_out = 0;
+ isl_set_reset_space(set, dim);
+ return set;
+error:
+ isl_space_free(dim);
+ isl_mat_free(mat);
+error2:
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Intersect the basic set "bset" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_basic_set *basic_set_append_equalities(
+ struct isl_basic_set *bset, struct isl_mat *eq)
+{
+ int i, k;
+ unsigned len;
+
+ if (!bset || !eq)
+ goto error;
+
+ bset = isl_basic_set_extend_space(bset, isl_space_copy(bset->dim), 0,
+ eq->n_row, 0);
+ if (!bset)
+ goto error;
+
+ len = 1 + isl_space_dim(bset->dim, isl_dim_all) + bset->extra;
+ for (i = 0; i < eq->n_row; ++i) {
+ k = isl_basic_set_alloc_equality(bset);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bset->eq[k], eq->row[i], eq->n_col);
+ isl_seq_clr(bset->eq[k] + eq->n_col, len - eq->n_col);
+ }
+ isl_mat_free(eq);
+
+ bset = isl_basic_set_gauss(bset, NULL);
+ bset = isl_basic_set_finalize(bset);
+
+ return bset;
+error:
+ isl_mat_free(eq);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Intersect the set "set" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_set *set_append_equalities(struct isl_set *set,
+ struct isl_mat *eq)
+{
+ int i;
+
+ if (!set || !eq)
+ goto error;
+
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = basic_set_append_equalities(set->p[i],
+ isl_mat_copy(eq));
+ if (!set->p[i])
+ goto error;
+ }
+ isl_mat_free(eq);
+ return set;
+error:
+ isl_mat_free(eq);
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Given a basic set "bset" that only involves parameters and existentially
+ * quantified variables, return the index of the first equality
+ * that only involves parameters. If there is no such equality then
+ * return bset->n_eq.
+ *
+ * This function assumes that isl_basic_set_gauss has been called on "bset".
+ */
+static int first_parameter_equality(__isl_keep isl_basic_set *bset)
+{
+ int i, j;
+ unsigned nparam, n_div;
+
+ if (!bset)
+ return -1;
+
+ nparam = isl_basic_set_dim(bset, isl_dim_param);
+ n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+ for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) {
+ if (!isl_int_is_zero(bset->eq[i][1 + nparam + j]))
+ ++i;
+ }
+
+ return i;
+}
+
+/* Compute an explicit representation for the existentially quantified
+ * variables in "bset" by computing the "minimal value" of the set
+ * variables. Since there are no set variables, the computation of
+ * the minimal value essentially computes an explicit representation
+ * of the non-empty part(s) of "bset".
+ *
+ * The input only involves parameters and existentially quantified variables.
+ * All equalities among parameters have been removed.
+ *
+ * Since the existentially quantified variables in the result are in general
+ * going to be different from those in the input, we first replace
+ * them by the minimal number of variables based on their equalities.
+ * This should simplify the parametric integer programming.
+ */
+static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset)
+{
+ isl_morph *morph1, *morph2;
+ isl_set *set;
+ unsigned n;
+
+ if (!bset)
+ return NULL;
+ if (bset->n_eq == 0)
+ return isl_basic_set_lexmin(bset);
+
+ morph1 = isl_basic_set_parameter_compression(bset);
+ bset = isl_morph_basic_set(isl_morph_copy(morph1), bset);
+ bset = isl_basic_set_lift(bset);
+ morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+ bset = isl_morph_basic_set(morph2, bset);
+ n = isl_basic_set_dim(bset, isl_dim_set);
+ bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+
+ set = isl_basic_set_lexmin(bset);
+
+ set = isl_morph_set(isl_morph_inverse(morph1), set);
+
+ return set;
+}
+
+/* Project the given basic set onto its parameter domain, possibly introducing
+ * new, explicit, existential variables in the constraints.
+ * The input has parameters and (possibly implicit) existential variables.
+ * The output has the same parameters, but only
+ * explicit existentially quantified variables.
+ *
+ * The actual projection is performed by pip, but pip doesn't seem
+ * to like equalities very much, so we first remove the equalities
+ * among the parameters by performing a variable compression on
+ * the parameters. Afterward, an inverse transformation is performed
+ * and the equalities among the parameters are inserted back in.
+ *
+ * The variable compression on the parameters may uncover additional
+ * equalities that were only implicit before. We therefore check
+ * if there are any new parameter equalities in the result and
+ * if so recurse. The removal of parameter equalities is required
+ * for the parameter compression performed by base_compute_divs.
+ */
+static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
+{
+ int i;
+ struct isl_mat *eq;
+ struct isl_mat *T, *T2;
+ struct isl_set *set;
+ unsigned nparam;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ return NULL;
+
+ if (bset->n_eq == 0)
+ return base_compute_divs(bset);
+
+ bset = isl_basic_set_gauss(bset, NULL);
+ if (!bset)
+ return NULL;
+ if (isl_basic_set_plain_is_empty(bset))
+ return isl_set_from_basic_set(bset);
+
+ i = first_parameter_equality(bset);
+ if (i == bset->n_eq)
+ return base_compute_divs(bset);
+
+ nparam = isl_basic_set_dim(bset, isl_dim_param);
+ eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, i, bset->n_eq - i,
+ 0, 1 + nparam);
+ eq = isl_mat_cow(eq);
+ T = isl_mat_variable_compression(isl_mat_copy(eq), &T2);
+ if (T && T->n_col == 0) {
+ isl_mat_free(T);
+ isl_mat_free(T2);
+ isl_mat_free(eq);
+ bset = isl_basic_set_set_to_empty(bset);
+ return isl_set_from_basic_set(bset);
+ }
+ bset = basic_set_parameter_preimage(bset, T);
+
+ i = first_parameter_equality(bset);
+ if (!bset)
+ set = NULL;
+ else if (i == bset->n_eq)
+ set = base_compute_divs(bset);
+ else
+ set = parameter_compute_divs(bset);
+ set = set_parameter_preimage(set, T2);
+ set = set_append_equalities(set, eq);
+ return set;
+}
+
+/* Insert the divs from "ls" before those of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the divs from "ls".
+ * The caller is responsible for removing the same number of dimensions
+ * from the space of "bmap".
+ */
+static __isl_give isl_basic_map *insert_divs_from_local_space(
+ __isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls)
+{
+ int i;
+ int n_div;
+ int old_n_div;
+
+ n_div = isl_local_space_dim(ls, isl_dim_div);
+ if (n_div == 0)
+ return bmap;
+
+ old_n_div = bmap->n_div;
+ bmap = insert_div_rows(bmap, n_div);
+ if (!bmap)
+ return NULL;
+
+ for (i = 0; i < n_div; ++i) {
+ isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+ isl_seq_clr(bmap->div[i] + ls->div->n_col, old_n_div);
+ }
+
+ return bmap;
+}
+
+/* Replace the space of "bmap" by the space and divs of "ls".
+ *
+ * If "ls" has any divs, then we simplify the result since we may
+ * have discovered some additional equalities that could simplify
+ * the div expressions.
+ */
+static __isl_give isl_basic_map *basic_replace_space_by_local_space(
+ __isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls)
+{
+ int n_div;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap || !ls)
+ goto error;
+
+ n_div = isl_local_space_dim(ls, isl_dim_div);
+ bmap = insert_divs_from_local_space(bmap, ls);
+ if (!bmap)
+ goto error;
+
+ isl_space_free(bmap->dim);
+ bmap->dim = isl_local_space_get_space(ls);
+ if (!bmap->dim)
+ goto error;
+
+ isl_local_space_free(ls);
+ if (n_div > 0)
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_local_space_free(ls);
+ return NULL;
+}
+
+/* Replace the space of "map" by the space and divs of "ls".
+ */
+static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map,
+ __isl_take isl_local_space *ls)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map || !ls)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = basic_replace_space_by_local_space(map->p[i],
+ isl_local_space_copy(ls));
+ if (!map->p[i])
+ goto error;
+ }
+ isl_space_free(map->dim);
+ map->dim = isl_local_space_get_space(ls);
+ if (!map->dim)
+ goto error;
+
+ isl_local_space_free(ls);
+ return map;
+error:
+ isl_local_space_free(ls);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Compute an explicit representation for the existentially
+ * quantified variables for which do not know any explicit representation yet.
+ *
+ * We first sort the existentially quantified variables so that the
+ * existentially quantified variables for which we already have an explicit
+ * representation are placed before those for which we do not.
+ * The input dimensions, the output dimensions and the existentially
+ * quantified variables for which we already have an explicit
+ * representation are then turned into parameters.
+ * compute_divs returns a map with the same parameters and
+ * no input or output dimensions and the dimension specification
+ * is reset to that of the input, including the existentially quantified
+ * variables for which we already had an explicit representation.
+ */
+static struct isl_map *compute_divs(struct isl_basic_map *bmap)
+{
+ struct isl_basic_set *bset;
+ struct isl_set *set;
+ struct isl_map *map;
+ isl_space *dim;
+ isl_local_space *ls;
+ unsigned nparam;
+ unsigned n_in;
+ unsigned n_out;
+ unsigned n_known;
+ int i;
+
+ bmap = isl_basic_map_sort_divs(bmap);
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ for (n_known = 0; n_known < bmap->n_div; ++n_known)
+ if (isl_int_is_zero(bmap->div[n_known][0]))
+ break;
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ n_in = isl_basic_map_dim(bmap, isl_dim_in);
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+ dim = isl_space_set_alloc(bmap->ctx,
+ nparam + n_in + n_out + n_known, 0);
+ if (!dim)
+ goto error;
+
+ ls = isl_basic_map_get_local_space(bmap);
+ ls = isl_local_space_drop_dims(ls, isl_dim_div,
+ n_known, bmap->n_div - n_known);
+ if (n_known > 0) {
+ for (i = n_known; i < bmap->n_div; ++i)
+ swap_div(bmap, i - n_known, i);
+ bmap->n_div -= n_known;
+ bmap->extra -= n_known;
+ }
+ bmap = isl_basic_map_reset_space(bmap, dim);
+ bset = (struct isl_basic_set *)bmap;
+
+ set = parameter_compute_divs(bset);
+ map = (struct isl_map *)set;
+ map = replace_space_by_local_space(map, ls);
+
+ return map;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap)
+{
+ int i;
+ unsigned off;
+
+ if (!bmap)
+ return -1;
+
+ off = isl_space_dim(bmap->dim, isl_dim_all);
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ return 0;
+ isl_assert(bmap->ctx, isl_int_is_zero(bmap->div[i][1+1+off+i]),
+ return -1);
+ }
+ return 1;
+}
+
+static int map_divs_known(__isl_keep isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i) {
+ int known = isl_basic_map_divs_known(map->p[i]);
+ if (known <= 0)
+ return known;
+ }
+
+ return 1;
+}
+
+/* If bmap contains any unknown divs, then compute explicit
+ * expressions for them. However, this computation may be
+ * quite expensive, so first try to remove divs that aren't
+ * strictly needed.
+ */
+struct isl_map *isl_basic_map_compute_divs(struct isl_basic_map *bmap)
+{
+ int known;
+ struct isl_map *map;
+
+ known = isl_basic_map_divs_known(bmap);
+ if (known < 0)
+ goto error;
+ if (known)
+ return isl_map_from_basic_map(bmap);
+
+ bmap = isl_basic_map_drop_redundant_divs(bmap);
+
+ known = isl_basic_map_divs_known(bmap);
+ if (known < 0)
+ goto error;
+ if (known)
+ return isl_map_from_basic_map(bmap);
+
+ map = compute_divs(bmap);
+ return map;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_map *isl_map_compute_divs(struct isl_map *map)
+{
+ int i;
+ int known;
+ struct isl_map *res;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0)
+ return map;
+
+ known = map_divs_known(map);
+ if (known < 0) {
+ isl_map_free(map);
+ return NULL;
+ }
+ if (known)
+ return map;
+
+ res = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[0]));
+ for (i = 1 ; i < map->n; ++i) {
+ struct isl_map *r2;
+ r2 = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[i]));
+ if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
+ res = isl_map_union_disjoint(res, r2);
+ else
+ res = isl_map_union(res, r2);
+ }
+ isl_map_free(map);
+
+ return res;
+}
+
+struct isl_set *isl_basic_set_compute_divs(struct isl_basic_set *bset)
+{
+ return (struct isl_set *)
+ isl_basic_map_compute_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_compute_divs(struct isl_set *set)
+{
+ return (struct isl_set *)
+ isl_map_compute_divs((struct isl_map *)set);
+}
+
+struct isl_set *isl_map_domain(struct isl_map *map)
+{
+ int i;
+ struct isl_set *set;
+
+ if (!map)
+ goto error;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ set = (struct isl_set *)map;
+ set->dim = isl_space_domain(set->dim);
+ if (!set->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ set->p[i] = isl_basic_map_domain(map->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+ ISL_F_CLR(set, ISL_MAP_DISJOINT);
+ ISL_F_CLR(set, ISL_SET_NORMALIZED);
+ return set;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Return the union of "map1" and "map2", where we assume for now that
+ * "map1" and "map2" are disjoint. Note that the basic maps inside
+ * "map1" or "map2" may not be disjoint from each other.
+ * Also note that this function is also called from isl_map_union,
+ * which takes care of handling the situation where "map1" and "map2"
+ * may not be disjoint.
+ *
+ * If one of the inputs is empty, we can simply return the other input.
+ * Similarly, if one of the inputs is universal, then it is equal to the union.
+ */
+static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ int i;
+ unsigned flags = 0;
+ struct isl_map *map = NULL;
+ int is_universe;
+
+ if (!map1 || !map2)
+ goto error;
+
+ if (!isl_space_is_equal(map1->dim, map2->dim))
+ isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+ "spaces don't match", goto error);
+
+ if (map1->n == 0) {
+ isl_map_free(map1);
+ return map2;
+ }
+ if (map2->n == 0) {
+ isl_map_free(map2);
+ return map1;
+ }
+
+ is_universe = isl_map_plain_is_universe(map1);
+ if (is_universe < 0)
+ goto error;
+ if (is_universe) {
+ isl_map_free(map2);
+ return map1;
+ }
+
+ is_universe = isl_map_plain_is_universe(map2);
+ if (is_universe < 0)
+ goto error;
+ if (is_universe) {
+ isl_map_free(map1);
+ return map2;
+ }
+
+ if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+ ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+ ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+ map = isl_map_alloc_space(isl_space_copy(map1->dim),
+ map1->n + map2->n, flags);
+ if (!map)
+ goto error;
+ for (i = 0; i < map1->n; ++i) {
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_copy(map1->p[i]));
+ if (!map)
+ goto error;
+ }
+ for (i = 0; i < map2->n; ++i) {
+ map = isl_map_add_basic_map(map,
+ isl_basic_map_copy(map2->p[i]));
+ if (!map)
+ goto error;
+ }
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return map;
+error:
+ isl_map_free(map);
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" are
+ * guaranteed to be disjoint by the caller.
+ *
+ * Note that this functions is called from within isl_map_make_disjoint,
+ * so we have to be careful not to touch the constraints of the inputs
+ * in any way.
+ */
+__isl_give isl_map *isl_map_union_disjoint(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_union_disjoint);
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint. The parameters are assumed to have been aligned.
+ *
+ * We currently simply call map_union_disjoint, the internal operation
+ * of which does not really depend on the inputs being disjoint.
+ * If the result contains more than one basic map, then we clear
+ * the disjoint flag since the result may contain basic maps from
+ * both inputs and these are not guaranteed to be disjoint.
+ *
+ * As a special case, if "map1" and "map2" are obviously equal,
+ * then we simply return "map1".
+ */
+static __isl_give isl_map *map_union_aligned(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ int equal;
+
+ if (!map1 || !map2)
+ goto error;
+
+ equal = isl_map_plain_is_equal(map1, map2);
+ if (equal < 0)
+ goto error;
+ if (equal) {
+ isl_map_free(map2);
+ return map1;
+ }
+
+ map1 = map_union_disjoint(map1, map2);
+ if (!map1)
+ return NULL;
+ if (map1->n > 1)
+ ISL_F_CLR(map1, ISL_MAP_DISJOINT);
+ return map1;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint.
+ */
+__isl_give isl_map *isl_map_union(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_union_aligned);
+}
+
+struct isl_set *isl_set_union_disjoint(
+ struct isl_set *set1, struct isl_set *set2)
+{
+ return (struct isl_set *)
+ isl_map_union_disjoint(
+ (struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+struct isl_set *isl_set_union(struct isl_set *set1, struct isl_set *set2)
+{
+ return (struct isl_set *)
+ isl_map_union((struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+/* Apply "fn" to pairs of elements from "map" and "set" and collect
+ * the results.
+ *
+ * "map" and "set" are assumed to be compatible and non-NULL.
+ */
+static __isl_give isl_map *map_intersect_set(__isl_take isl_map *map,
+ __isl_take isl_set *set,
+ __isl_give isl_basic_map *fn(__isl_take isl_basic_map *bmap,
+ __isl_take isl_basic_set *bset))
+{
+ unsigned flags = 0;
+ struct isl_map *result;
+ int i, j;
+
+ if (isl_set_plain_is_universe(set)) {
+ isl_set_free(set);
+ return map;
+ }
+
+ if (ISL_F_ISSET(map, ISL_MAP_DISJOINT) &&
+ ISL_F_ISSET(set, ISL_MAP_DISJOINT))
+ ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+ result = isl_map_alloc_space(isl_space_copy(map->dim),
+ map->n * set->n, flags);
+ for (i = 0; result && i < map->n; ++i)
+ for (j = 0; j < set->n; ++j) {
+ result = isl_map_add_basic_map(result,
+ fn(isl_basic_map_copy(map->p[i]),
+ isl_basic_set_copy(set->p[j])));
+ if (!result)
+ break;
+ }
+
+ isl_map_free(map);
+ isl_set_free(set);
+ return result;
+}
+
+static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map,
+ __isl_take isl_set *set)
+{
+ if (!map || !set)
+ goto error;
+
+ if (!isl_map_compatible_range(map, set))
+ isl_die(set->ctx, isl_error_invalid,
+ "incompatible spaces", goto error);
+
+ return map_intersect_set(map, set, &isl_basic_map_intersect_range);
+error:
+ isl_map_free(map);
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_range(__isl_take isl_map *map,
+ __isl_take isl_set *set)
+{
+ return isl_map_align_params_map_map_and(map, set, &map_intersect_range);
+}
+
+static __isl_give isl_map *map_intersect_domain(__isl_take isl_map *map,
+ __isl_take isl_set *set)
+{
+ if (!map || !set)
+ goto error;
+
+ if (!isl_map_compatible_domain(map, set))
+ isl_die(set->ctx, isl_error_invalid,
+ "incompatible spaces", goto error);
+
+ return map_intersect_set(map, set, &isl_basic_map_intersect_domain);
+error:
+ isl_map_free(map);
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_domain(__isl_take isl_map *map,
+ __isl_take isl_set *set)
+{
+ return isl_map_align_params_map_map_and(map, set,
+ &map_intersect_domain);
+}
+
+static __isl_give isl_map *map_apply_domain(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ if (!map1 || !map2)
+ goto error;
+ map1 = isl_map_reverse(map1);
+ map1 = isl_map_apply_range(map1, map2);
+ return isl_map_reverse(map1);
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_apply_domain);
+}
+
+static __isl_give isl_map *map_apply_range(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_space *dim_result;
+ struct isl_map *result;
+ int i, j;
+
+ if (!map1 || !map2)
+ goto error;
+
+ dim_result = isl_space_join(isl_space_copy(map1->dim),
+ isl_space_copy(map2->dim));
+
+ result = isl_map_alloc_space(dim_result, map1->n * map2->n, 0);
+ if (!result)
+ goto error;
+ for (i = 0; i < map1->n; ++i)
+ for (j = 0; j < map2->n; ++j) {
+ result = isl_map_add_basic_map(result,
+ isl_basic_map_apply_range(
+ isl_basic_map_copy(map1->p[i]),
+ isl_basic_map_copy(map2->p[j])));
+ if (!result)
+ goto error;
+ }
+ isl_map_free(map1);
+ isl_map_free(map2);
+ if (result && result->n <= 1)
+ ISL_F_SET(result, ISL_MAP_DISJOINT);
+ return result;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_apply_range);
+}
+
+/*
+ * returns range - domain
+ */
+struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
+{
+ isl_space *dims, *target_dim;
+ struct isl_basic_set *bset;
+ unsigned dim;
+ unsigned nparam;
+ int i;
+
+ if (!bmap)
+ goto error;
+ isl_assert(bmap->ctx, isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+ bmap->dim, isl_dim_out),
+ goto error);
+ target_dim = isl_space_domain(isl_basic_map_get_space(bmap));
+ dim = isl_basic_map_n_in(bmap);
+ nparam = isl_basic_map_n_param(bmap);
+ bset = isl_basic_set_from_basic_map(bmap);
+ bset = isl_basic_set_cow(bset);
+ dims = isl_basic_set_get_space(bset);
+ dims = isl_space_add_dims(dims, isl_dim_set, dim);
+ bset = isl_basic_set_extend_space(bset, dims, 0, dim, 0);
+ bset = isl_basic_set_swap_vars(bset, 2*dim);
+ for (i = 0; i < dim; ++i) {
+ int j = isl_basic_map_alloc_equality(
+ (struct isl_basic_map *)bset);
+ if (j < 0) {
+ bset = isl_basic_set_free(bset);
+ break;
+ }
+ isl_seq_clr(bset->eq[j], 1 + isl_basic_set_total_dim(bset));
+ isl_int_set_si(bset->eq[j][1+nparam+i], 1);
+ isl_int_set_si(bset->eq[j][1+nparam+dim+i], 1);
+ isl_int_set_si(bset->eq[j][1+nparam+2*dim+i], -1);
+ }
+ bset = isl_basic_set_project_out(bset, isl_dim_set, dim, 2*dim);
+ bset = isl_basic_set_reset_space(bset, target_dim);
+ return bset;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/*
+ * returns range - domain
+ */
+__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map)
+{
+ int i;
+ isl_space *dim;
+ struct isl_set *result;
+
+ if (!map)
+ return NULL;
+
+ isl_assert(map->ctx, isl_space_tuple_is_equal(map->dim, isl_dim_in,
+ map->dim, isl_dim_out),
+ goto error);
+ dim = isl_map_get_space(map);
+ dim = isl_space_domain(dim);
+ result = isl_set_alloc_space(dim, map->n, 0);
+ if (!result)
+ goto error;
+ for (i = 0; i < map->n; ++i)
+ result = isl_set_add_basic_set(result,
+ isl_basic_map_deltas(isl_basic_map_copy(map->p[i])));
+ isl_map_free(map);
+ return result;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_basic_map *isl_basic_map_deltas_map(
+ __isl_take isl_basic_map *bmap)
+{
+ int i, k;
+ isl_space *dim;
+ isl_basic_map *domain;
+ int nparam, n;
+ unsigned total;
+
+ if (!isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+ bmap->dim, isl_dim_out))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "domain and range don't match", goto error);
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ n = isl_basic_map_dim(bmap, isl_dim_in);
+
+ dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+ domain = isl_basic_map_universe(dim);
+
+ bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+ bmap = isl_basic_map_apply_range(bmap, domain);
+ bmap = isl_basic_map_extend_constraints(bmap, n, 0);
+
+ total = isl_basic_map_total_dim(bmap);
+
+ for (i = 0; i < n; ++i) {
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[k], 1 + total);
+ isl_int_set_si(bmap->eq[k][1 + nparam + i], 1);
+ isl_int_set_si(bmap->eq[k][1 + nparam + n + i], -1);
+ isl_int_set_si(bmap->eq[k][1 + nparam + n + n + i], 1);
+ }
+
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map)
+{
+ int i;
+ isl_space *domain_dim;
+
+ if (!map)
+ return NULL;
+
+ if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+ map->dim, isl_dim_out))
+ isl_die(map->ctx, isl_error_invalid,
+ "domain and range don't match", goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map)));
+ map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+ map->dim = isl_space_join(map->dim, domain_dim);
+ if (!map->dim)
+ goto error;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_deltas_map(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_identity(__isl_take isl_space *dims)
+{
+ struct isl_basic_map *bmap;
+ unsigned nparam;
+ unsigned dim;
+ int i;
+
+ if (!dims)
+ return NULL;
+
+ nparam = dims->nparam;
+ dim = dims->n_out;
+ bmap = isl_basic_map_alloc_space(dims, 0, dim, 0);
+ if (!bmap)
+ goto error;
+
+ for (i = 0; i < dim; ++i) {
+ int j = isl_basic_map_alloc_equality(bmap);
+ if (j < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap));
+ isl_int_set_si(bmap->eq[j][1+nparam+i], 1);
+ isl_int_set_si(bmap->eq[j][1+nparam+dim+i], -1);
+ }
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim)
+{
+ if (!dim)
+ return NULL;
+ if (dim->n_in != dim->n_out)
+ isl_die(dim->ctx, isl_error_invalid,
+ "number of input and output dimensions needs to be "
+ "the same", goto error);
+ return basic_map_identity(dim);
+error:
+ isl_space_free(dim);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_identity_like(struct isl_basic_map *model)
+{
+ if (!model || !model->dim)
+ return NULL;
+ return isl_basic_map_identity(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim)
+{
+ return isl_map_from_basic_map(isl_basic_map_identity(dim));
+}
+
+struct isl_map *isl_map_identity_like(struct isl_map *model)
+{
+ if (!model || !model->dim)
+ return NULL;
+ return isl_map_identity(isl_space_copy(model->dim));
+}
+
+struct isl_map *isl_map_identity_like_basic_map(struct isl_basic_map *model)
+{
+ if (!model || !model->dim)
+ return NULL;
+ return isl_map_identity(isl_space_copy(model->dim));
+}
+
+__isl_give isl_map *isl_set_identity(__isl_take isl_set *set)
+{
+ isl_space *dim = isl_set_get_space(set);
+ isl_map *id;
+ id = isl_map_identity(isl_space_map_from_set(dim));
+ return isl_map_intersect_range(id, set);
+}
+
+/* Construct a basic set with all set dimensions having only non-negative
+ * values.
+ */
+__isl_give isl_basic_set *isl_basic_set_positive_orthant(
+ __isl_take isl_space *space)
+{
+ int i;
+ unsigned nparam;
+ unsigned dim;
+ struct isl_basic_set *bset;
+
+ if (!space)
+ return NULL;
+ nparam = space->nparam;
+ dim = space->n_out;
+ bset = isl_basic_set_alloc_space(space, 0, 0, dim);
+ if (!bset)
+ return NULL;
+ for (i = 0; i < dim; ++i) {
+ int k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset));
+ isl_int_set_si(bset->ineq[k][1 + nparam + i], 1);
+ }
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Construct the half-space x_pos >= 0.
+ */
+static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *dim,
+ int pos)
+{
+ int k;
+ isl_basic_set *nonneg;
+
+ nonneg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+ k = isl_basic_set_alloc_inequality(nonneg);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(nonneg->ineq[k], 1 + isl_basic_set_total_dim(nonneg));
+ isl_int_set_si(nonneg->ineq[k][pos], 1);
+
+ return isl_basic_set_finalize(nonneg);
+error:
+ isl_basic_set_free(nonneg);
+ return NULL;
+}
+
+/* Construct the half-space x_pos <= -1.
+ */
+static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *dim, int pos)
+{
+ int k;
+ isl_basic_set *neg;
+
+ neg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+ k = isl_basic_set_alloc_inequality(neg);
+ if (k < 0)
+ goto error;
+ isl_seq_clr(neg->ineq[k], 1 + isl_basic_set_total_dim(neg));
+ isl_int_set_si(neg->ineq[k][0], -1);
+ isl_int_set_si(neg->ineq[k][pos], -1);
+
+ return isl_basic_set_finalize(neg);
+error:
+ isl_basic_set_free(neg);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+ isl_basic_set *nonneg;
+ isl_basic_set *neg;
+
+ if (!set)
+ return NULL;
+ if (n == 0)
+ return set;
+
+ isl_assert(set->ctx, first + n <= isl_set_dim(set, type), goto error);
+
+ for (i = 0; i < n; ++i) {
+ nonneg = nonneg_halfspace(isl_set_get_space(set),
+ pos(set->dim, type) + first + i);
+ neg = neg_halfspace(isl_set_get_space(set),
+ pos(set->dim, type) + first + i);
+
+ set = isl_set_intersect(set, isl_basic_set_union(nonneg, neg));
+ }
+
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+static int foreach_orthant(__isl_take isl_set *set, int *signs, int first,
+ int len, int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+ void *user)
+{
+ isl_set *half;
+
+ if (!set)
+ return -1;
+ if (isl_set_plain_is_empty(set)) {
+ isl_set_free(set);
+ return 0;
+ }
+ if (first == len)
+ return fn(set, signs, user);
+
+ signs[first] = 1;
+ half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_space(set),
+ 1 + first));
+ half = isl_set_intersect(half, isl_set_copy(set));
+ if (foreach_orthant(half, signs, first + 1, len, fn, user) < 0)
+ goto error;
+
+ signs[first] = -1;
+ half = isl_set_from_basic_set(neg_halfspace(isl_set_get_space(set),
+ 1 + first));
+ half = isl_set_intersect(half, set);
+ return foreach_orthant(half, signs, first + 1, len, fn, user);
+error:
+ isl_set_free(set);
+ return -1;
+}
+
+/* Call "fn" on the intersections of "set" with each of the orthants
+ * (except for obviously empty intersections). The orthant is identified
+ * by the signs array, with each entry having value 1 or -1 according
+ * to the sign of the corresponding variable.
+ */
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+ int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+ void *user)
+{
+ unsigned nparam;
+ unsigned nvar;
+ int *signs;
+ int r;
+
+ if (!set)
+ return -1;
+ if (isl_set_plain_is_empty(set))
+ return 0;
+
+ nparam = isl_set_dim(set, isl_dim_param);
+ nvar = isl_set_dim(set, isl_dim_set);
+
+ signs = isl_alloc_array(set->ctx, int, nparam + nvar);
+
+ r = foreach_orthant(isl_set_copy(set), signs, 0, nparam + nvar,
+ fn, user);
+
+ free(signs);
+
+ return r;
+}
+
+int isl_set_is_equal(struct isl_set *set1, struct isl_set *set2)
+{
+ return isl_map_is_equal((struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+int isl_basic_map_is_subset(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ int is_subset;
+ struct isl_map *map1;
+ struct isl_map *map2;
+
+ if (!bmap1 || !bmap2)
+ return -1;
+
+ map1 = isl_map_from_basic_map(isl_basic_map_copy(bmap1));
+ map2 = isl_map_from_basic_map(isl_basic_map_copy(bmap2));
+
+ is_subset = isl_map_is_subset(map1, map2);
+
+ isl_map_free(map1);
+ isl_map_free(map2);
+
+ return is_subset;
+}
+
+int isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1,
+ __isl_keep isl_basic_set *bset2)
+{
+ return isl_basic_map_is_subset(bset1, bset2);
+}
+
+int isl_basic_map_is_equal(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ int is_subset;
+
+ if (!bmap1 || !bmap2)
+ return -1;
+ is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+ if (is_subset != 1)
+ return is_subset;
+ is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+ return is_subset;
+}
+
+int isl_basic_set_is_equal(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ return isl_basic_map_is_equal(
+ (struct isl_basic_map *)bset1, (struct isl_basic_map *)bset2);
+}
+
+int isl_map_is_empty(struct isl_map *map)
+{
+ int i;
+ int is_empty;
+
+ if (!map)
+ return -1;
+ for (i = 0; i < map->n; ++i) {
+ is_empty = isl_basic_map_is_empty(map->p[i]);
+ if (is_empty < 0)
+ return -1;
+ if (!is_empty)
+ return 0;
+ }
+ return 1;
+}
+
+int isl_map_plain_is_empty(__isl_keep isl_map *map)
+{
+ return map ? map->n == 0 : -1;
+}
+
+int isl_map_fast_is_empty(__isl_keep isl_map *map)
+{
+ return isl_map_plain_is_empty(map);
+}
+
+int isl_set_plain_is_empty(struct isl_set *set)
+{
+ return set ? set->n == 0 : -1;
+}
+
+int isl_set_fast_is_empty(__isl_keep isl_set *set)
+{
+ return isl_set_plain_is_empty(set);
+}
+
+int isl_set_is_empty(struct isl_set *set)
+{
+ return isl_map_is_empty((struct isl_map *)set);
+}
+
+int isl_map_has_equal_space(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ if (!map1 || !map2)
+ return -1;
+
+ return isl_space_is_equal(map1->dim, map2->dim);
+}
+
+int isl_set_has_equal_space(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ if (!set1 || !set2)
+ return -1;
+
+ return isl_space_is_equal(set1->dim, set2->dim);
+}
+
+static int map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ int is_subset;
+
+ if (!map1 || !map2)
+ return -1;
+ is_subset = isl_map_is_subset(map1, map2);
+ if (is_subset != 1)
+ return is_subset;
+ is_subset = isl_map_is_subset(map2, map1);
+ return is_subset;
+}
+
+int isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal);
+}
+
+int isl_basic_map_is_strict_subset(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ int is_subset;
+
+ if (!bmap1 || !bmap2)
+ return -1;
+ is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+ if (is_subset != 1)
+ return is_subset;
+ is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+ if (is_subset == -1)
+ return is_subset;
+ return !is_subset;
+}
+
+int isl_map_is_strict_subset(struct isl_map *map1, struct isl_map *map2)
+{
+ int is_subset;
+
+ if (!map1 || !map2)
+ return -1;
+ is_subset = isl_map_is_subset(map1, map2);
+ if (is_subset != 1)
+ return is_subset;
+ is_subset = isl_map_is_subset(map2, map1);
+ if (is_subset == -1)
+ return is_subset;
+ return !is_subset;
+}
+
+int isl_set_is_strict_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ return isl_map_is_strict_subset((isl_map *)set1, (isl_map *)set2);
+}
+
+int isl_basic_map_is_universe(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ return bmap->n_eq == 0 && bmap->n_ineq == 0;
+}
+
+int isl_basic_set_is_universe(struct isl_basic_set *bset)
+{
+ if (!bset)
+ return -1;
+ return bset->n_eq == 0 && bset->n_ineq == 0;
+}
+
+int isl_map_plain_is_universe(__isl_keep isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i) {
+ int r = isl_basic_map_is_universe(map->p[i]);
+ if (r < 0 || r)
+ return r;
+ }
+
+ return 0;
+}
+
+int isl_set_plain_is_universe(__isl_keep isl_set *set)
+{
+ return isl_map_plain_is_universe((isl_map *) set);
+}
+
+int isl_set_fast_is_universe(__isl_keep isl_set *set)
+{
+ return isl_set_plain_is_universe(set);
+}
+
+int isl_basic_map_is_empty(struct isl_basic_map *bmap)
+{
+ struct isl_basic_set *bset = NULL;
+ struct isl_vec *sample = NULL;
+ int empty;
+ unsigned total;
+
+ if (!bmap)
+ return -1;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+ return 1;
+
+ if (isl_basic_map_is_universe(bmap))
+ return 0;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+ struct isl_basic_map *copy = isl_basic_map_copy(bmap);
+ copy = isl_basic_map_remove_redundancies(copy);
+ empty = isl_basic_map_plain_is_empty(copy);
+ isl_basic_map_free(copy);
+ return empty;
+ }
+
+ total = 1 + isl_basic_map_total_dim(bmap);
+ if (bmap->sample && bmap->sample->size == total) {
+ int contains = isl_basic_map_contains(bmap, bmap->sample);
+ if (contains < 0)
+ return -1;
+ if (contains)
+ return 0;
+ }
+ isl_vec_free(bmap->sample);
+ bmap->sample = NULL;
+ bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+ if (!bset)
+ return -1;
+ sample = isl_basic_set_sample_vec(bset);
+ if (!sample)
+ return -1;
+ empty = sample->size == 0;
+ isl_vec_free(bmap->sample);
+ bmap->sample = sample;
+ if (empty)
+ ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+
+ return empty;
+}
+
+int isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+ return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY);
+}
+
+int isl_basic_map_fast_is_empty(__isl_keep isl_basic_map *bmap)
+{
+ return isl_basic_map_plain_is_empty(bmap);
+}
+
+int isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset)
+{
+ if (!bset)
+ return -1;
+ return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY);
+}
+
+int isl_basic_set_fast_is_empty(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_set_plain_is_empty(bset);
+}
+
+int isl_basic_set_is_empty(struct isl_basic_set *bset)
+{
+ return isl_basic_map_is_empty((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_basic_map_union(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ struct isl_map *map;
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+ map = isl_map_alloc_space(isl_space_copy(bmap1->dim), 2, 0);
+ if (!map)
+ goto error;
+ map = isl_map_add_basic_map(map, bmap1);
+ map = isl_map_add_basic_map(map, bmap2);
+ return map;
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+struct isl_set *isl_basic_set_union(
+ struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+ return (struct isl_set *)isl_basic_map_union(
+ (struct isl_basic_map *)bset1,
+ (struct isl_basic_map *)bset2);
+}
+
+/* Order divs such that any div only depends on previous divs */
+struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap)
+{
+ int i;
+ unsigned off;
+
+ if (!bmap)
+ return NULL;
+
+ off = isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ int pos;
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ pos = isl_seq_first_non_zero(bmap->div[i]+1+1+off+i,
+ bmap->n_div-i);
+ if (pos == -1)
+ continue;
+ isl_basic_map_swap_div(bmap, i, i + pos);
+ --i;
+ }
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_order_divs((struct isl_basic_map *)bset);
+}
+
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return 0;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_order_divs(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ */
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+ __isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp)
+{
+ int i, j;
+ int n_div;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset || !div)
+ goto error;
+
+ if (div->n_row < bset->n_div)
+ isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+ "not an expansion", goto error);
+
+ n_div = bset->n_div;
+ bset = isl_basic_map_extend_space(bset, isl_space_copy(bset->dim),
+ div->n_row - n_div, 0,
+ 2 * (div->n_row - n_div));
+
+ for (i = n_div; i < div->n_row; ++i)
+ if (isl_basic_set_alloc_div(bset) < 0)
+ goto error;
+
+ j = n_div - 1;
+ for (i = div->n_row - 1; i >= 0; --i) {
+ if (j >= 0 && exp[j] == i) {
+ if (i != j)
+ isl_basic_map_swap_div(bset, i, j);
+ j--;
+ } else {
+ isl_seq_cpy(bset->div[i], div->row[i], div->n_col);
+ if (isl_basic_map_add_div_constraints(bset, i) < 0)
+ goto error;
+ }
+ }
+
+ isl_mat_free(div);
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ isl_mat_free(div);
+ return NULL;
+}
+
+/* Look for a div in dst that corresponds to the div "div" in src.
+ * The divs before "div" in src and dst are assumed to be the same.
+ *
+ * Returns -1 if no corresponding div was found and the position
+ * of the corresponding div in dst otherwise.
+ */
+static int find_div(struct isl_basic_map *dst,
+ struct isl_basic_map *src, unsigned div)
+{
+ int i;
+
+ unsigned total = isl_space_dim(src->dim, isl_dim_all);
+
+ isl_assert(dst->ctx, div <= dst->n_div, return -1);
+ for (i = div; i < dst->n_div; ++i)
+ if (isl_seq_eq(dst->div[i], src->div[div], 1+1+total+div) &&
+ isl_seq_first_non_zero(dst->div[i]+1+1+total+div,
+ dst->n_div - div) == -1)
+ return i;
+ return -1;
+}
+
+/* Align the divs of "dst" to those of "src", adding divs from "src"
+ * if needed. That is, make sure that the first src->n_div divs
+ * of the result are equal to those of src.
+ *
+ * The result is not finalized as by design it will have redundant
+ * divs if any divs from "src" were copied.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_divs(
+ __isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src)
+{
+ int i;
+ int known, extended;
+ unsigned total;
+
+ if (!dst || !src)
+ return isl_basic_map_free(dst);
+
+ if (src->n_div == 0)
+ return dst;
+
+ known = isl_basic_map_divs_known(src);
+ if (known < 0)
+ return isl_basic_map_free(dst);
+ if (!known)
+ isl_die(isl_basic_map_get_ctx(src), isl_error_invalid,
+ "some src divs are unknown",
+ return isl_basic_map_free(dst));
+
+ src = isl_basic_map_order_divs(src);
+
+ extended = 0;
+ total = isl_space_dim(src->dim, isl_dim_all);
+ for (i = 0; i < src->n_div; ++i) {
+ int j = find_div(dst, src, i);
+ if (j < 0) {
+ if (!extended) {
+ int extra = src->n_div - i;
+ dst = isl_basic_map_cow(dst);
+ if (!dst)
+ return NULL;
+ dst = isl_basic_map_extend_space(dst,
+ isl_space_copy(dst->dim),
+ extra, 0, 2 * extra);
+ extended = 1;
+ }
+ j = isl_basic_map_alloc_div(dst);
+ if (j < 0)
+ return isl_basic_map_free(dst);
+ isl_seq_cpy(dst->div[j], src->div[i], 1+1+total+i);
+ isl_seq_clr(dst->div[j]+1+1+total+i, dst->n_div - i);
+ if (isl_basic_map_add_div_constraints(dst, j) < 0)
+ return isl_basic_map_free(dst);
+ }
+ if (j != i)
+ isl_basic_map_swap_div(dst, i, j);
+ }
+ return dst;
+}
+
+struct isl_basic_set *isl_basic_set_align_divs(
+ struct isl_basic_set *dst, struct isl_basic_set *src)
+{
+ return (struct isl_basic_set *)isl_basic_map_align_divs(
+ (struct isl_basic_map *)dst, (struct isl_basic_map *)src);
+}
+
+struct isl_map *isl_map_align_divs(struct isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ if (map->n == 0)
+ return map;
+ map = isl_map_compute_divs(map);
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 1; i < map->n; ++i)
+ map->p[0] = isl_basic_map_align_divs(map->p[0], map->p[i]);
+ for (i = 1; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_align_divs(map->p[i], map->p[0]);
+ if (!map->p[i])
+ return isl_map_free(map);
+ }
+
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+}
+
+struct isl_set *isl_set_align_divs(struct isl_set *set)
+{
+ return (struct isl_set *)isl_map_align_divs((struct isl_map *)set);
+}
+
+/* Align the divs of the basic sets in "set" to those
+ * of the basic sets in "list", as well as to the other basic sets in "set".
+ * The elements in "list" are assumed to have known divs.
+ */
+__isl_give isl_set *isl_set_align_divs_to_basic_set_list(
+ __isl_take isl_set *set, __isl_keep isl_basic_set_list *list)
+{
+ int i, n;
+
+ set = isl_set_compute_divs(set);
+ set = isl_set_cow(set);
+ if (!set || !list)
+ return isl_set_free(set);
+ if (set->n == 0)
+ return set;
+
+ n = isl_basic_set_list_n_basic_set(list);
+ for (i = 0; i < n; ++i) {
+ isl_basic_set *bset;
+
+ bset = isl_basic_set_list_get_basic_set(list, i);
+ set->p[0] = isl_basic_set_align_divs(set->p[0], bset);
+ isl_basic_set_free(bset);
+ }
+ if (!set->p[0])
+ return isl_set_free(set);
+
+ return isl_set_align_divs(set);
+}
+
+/* Align the divs of each element of "list" to those of "bset".
+ * Both "bset" and the elements of "list" are assumed to have known divs.
+ */
+__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set(
+ __isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset)
+{
+ int i, n;
+
+ if (!list || !bset)
+ return isl_basic_set_list_free(list);
+
+ n = isl_basic_set_list_n_basic_set(list);
+ for (i = 0; i < n; ++i) {
+ isl_basic_set *bset_i;
+
+ bset_i = isl_basic_set_list_get_basic_set(list, i);
+ bset_i = isl_basic_set_align_divs(bset_i, bset);
+ list = isl_basic_set_list_set_basic_set(list, i, bset_i);
+ }
+
+ return list;
+}
+
+static __isl_give isl_set *set_apply( __isl_take isl_set *set,
+ __isl_take isl_map *map)
+{
+ if (!set || !map)
+ goto error;
+ isl_assert(set->ctx, isl_map_compatible_domain(map, set), goto error);
+ map = isl_map_intersect_domain(map, set);
+ set = isl_map_range(map);
+ return set;
+error:
+ isl_set_free(set);
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_apply( __isl_take isl_set *set,
+ __isl_take isl_map *map)
+{
+ return isl_map_align_params_map_map_and(set, map, &set_apply);
+}
+
+/* There is no need to cow as removing empty parts doesn't change
+ * the meaning of the set.
+ */
+struct isl_map *isl_map_remove_empty_parts(struct isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ for (i = map->n - 1; i >= 0; --i)
+ remove_if_empty(map, i);
+
+ return map;
+}
+
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set)
+{
+ return (struct isl_set *)
+ isl_map_remove_empty_parts((struct isl_map *)set);
+}
+
+struct isl_basic_map *isl_map_copy_basic_map(struct isl_map *map)
+{
+ struct isl_basic_map *bmap;
+ if (!map || map->n == 0)
+ return NULL;
+ bmap = map->p[map->n-1];
+ isl_assert(map->ctx, ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL), return NULL);
+ return isl_basic_map_copy(bmap);
+}
+
+struct isl_basic_set *isl_set_copy_basic_set(struct isl_set *set)
+{
+ return (struct isl_basic_set *)
+ isl_map_copy_basic_map((struct isl_map *)set);
+}
+
+__isl_give isl_map *isl_map_drop_basic_map(__isl_take isl_map *map,
+ __isl_keep isl_basic_map *bmap)
+{
+ int i;
+
+ if (!map || !bmap)
+ goto error;
+ for (i = map->n-1; i >= 0; --i) {
+ if (map->p[i] != bmap)
+ continue;
+ map = isl_map_cow(map);
+ if (!map)
+ goto error;
+ isl_basic_map_free(map->p[i]);
+ if (i != map->n-1) {
+ ISL_F_CLR(map, ISL_SET_NORMALIZED);
+ map->p[i] = map->p[map->n-1];
+ }
+ map->n--;
+ return map;
+ }
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_set *isl_set_drop_basic_set(struct isl_set *set,
+ struct isl_basic_set *bset)
+{
+ return (struct isl_set *)isl_map_drop_basic_map((struct isl_map *)set,
+ (struct isl_basic_map *)bset);
+}
+
+/* Given two basic sets bset1 and bset2, compute the maximal difference
+ * between the values of dimension pos in bset1 and those in bset2
+ * for any common value of the parameters and dimensions preceding pos.
+ */
+static enum isl_lp_result basic_set_maximal_difference_at(
+ __isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,
+ int pos, isl_int *opt)
+{
+ isl_space *dims;
+ struct isl_basic_map *bmap1 = NULL;
+ struct isl_basic_map *bmap2 = NULL;
+ struct isl_ctx *ctx;
+ struct isl_vec *obj;
+ unsigned total;
+ unsigned nparam;
+ unsigned dim1, dim2;
+ enum isl_lp_result res;
+
+ if (!bset1 || !bset2)
+ return isl_lp_error;
+
+ nparam = isl_basic_set_n_param(bset1);
+ dim1 = isl_basic_set_n_dim(bset1);
+ dim2 = isl_basic_set_n_dim(bset2);
+ dims = isl_space_alloc(bset1->ctx, nparam, pos, dim1 - pos);
+ bmap1 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset1), dims);
+ dims = isl_space_alloc(bset2->ctx, nparam, pos, dim2 - pos);
+ bmap2 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset2), dims);
+ if (!bmap1 || !bmap2)
+ goto error;
+ bmap1 = isl_basic_map_cow(bmap1);
+ bmap1 = isl_basic_map_extend(bmap1, nparam,
+ pos, (dim1 - pos) + (dim2 - pos),
+ bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+ bmap1 = add_constraints(bmap1, bmap2, 0, dim1 - pos);
+ if (!bmap1)
+ goto error2;
+ total = isl_basic_map_total_dim(bmap1);
+ ctx = bmap1->ctx;
+ obj = isl_vec_alloc(ctx, 1 + total);
+ if (!obj)
+ goto error2;
+ isl_seq_clr(obj->block.data, 1 + total);
+ isl_int_set_si(obj->block.data[1+nparam+pos], 1);
+ isl_int_set_si(obj->block.data[1+nparam+pos+(dim1-pos)], -1);
+ res = isl_basic_map_solve_lp(bmap1, 1, obj->block.data, ctx->one,
+ opt, NULL, NULL);
+ isl_basic_map_free(bmap1);
+ isl_vec_free(obj);
+ return res;
+error:
+ isl_basic_map_free(bmap2);
+error2:
+ isl_basic_map_free(bmap1);
+ return isl_lp_error;
+}
+
+/* Given two _disjoint_ basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * in both basic sets, the values of dimension pos in bset1 are
+ * smaller or larger than those in bset2.
+ *
+ * Returns
+ * 1 if bset1 follows bset2
+ * -1 if bset1 precedes bset2
+ * 0 if bset1 and bset2 are incomparable
+ * -2 if some error occurred.
+ */
+int isl_basic_set_compare_at(struct isl_basic_set *bset1,
+ struct isl_basic_set *bset2, int pos)
+{
+ isl_int opt;
+ enum isl_lp_result res;
+ int cmp;
+
+ isl_int_init(opt);
+
+ res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+ if (res == isl_lp_empty)
+ cmp = 0;
+ else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+ res == isl_lp_unbounded)
+ cmp = 1;
+ else if (res == isl_lp_ok && isl_int_is_neg(opt))
+ cmp = -1;
+ else
+ cmp = -2;
+
+ isl_int_clear(opt);
+ return cmp;
+}
+
+/* Given two basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in bset1 that is larger
+ * than a value of the same dimension in bset2.
+ *
+ * Return
+ * 1 if there exists such a pair
+ * 0 if there is no such pair, but there is a pair of equal values
+ * -1 otherwise
+ * -2 if some error occurred.
+ */
+int isl_basic_set_follows_at(__isl_keep isl_basic_set *bset1,
+ __isl_keep isl_basic_set *bset2, int pos)
+{
+ isl_int opt;
+ enum isl_lp_result res;
+ int cmp;
+
+ isl_int_init(opt);
+
+ res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+ if (res == isl_lp_empty)
+ cmp = -1;
+ else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+ res == isl_lp_unbounded)
+ cmp = 1;
+ else if (res == isl_lp_ok && isl_int_is_neg(opt))
+ cmp = -1;
+ else if (res == isl_lp_ok)
+ cmp = 0;
+ else
+ cmp = -2;
+
+ isl_int_clear(opt);
+ return cmp;
+}
+
+/* Given two sets set1 and set2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in set1 that is larger
+ * than a value of the same dimension in set2.
+ *
+ * Return
+ * 1 if there exists such a pair
+ * 0 if there is no such pair, but there is a pair of equal values
+ * -1 otherwise
+ * -2 if some error occurred.
+ */
+int isl_set_follows_at(__isl_keep isl_set *set1,
+ __isl_keep isl_set *set2, int pos)
+{
+ int i, j;
+ int follows = -1;
+
+ if (!set1 || !set2)
+ return -2;
+
+ for (i = 0; i < set1->n; ++i)
+ for (j = 0; j < set2->n; ++j) {
+ int f;
+ f = isl_basic_set_follows_at(set1->p[i], set2->p[j], pos);
+ if (f == 1 || f == -2)
+ return f;
+ if (f > follows)
+ follows = f;
+ }
+
+ return follows;
+}
+
+static int isl_basic_map_plain_has_fixed_var(__isl_keep isl_basic_map *bmap,
+ unsigned pos, isl_int *val)
+{
+ int i;
+ int d;
+ unsigned total;
+
+ if (!bmap)
+ return -1;
+ total = isl_basic_map_total_dim(bmap);
+ for (i = 0, d = total-1; i < bmap->n_eq && d+1 > pos; ++i) {
+ for (; d+1 > pos; --d)
+ if (!isl_int_is_zero(bmap->eq[i][1+d]))
+ break;
+ if (d != pos)
+ continue;
+ if (isl_seq_first_non_zero(bmap->eq[i]+1, d) != -1)
+ return 0;
+ if (isl_seq_first_non_zero(bmap->eq[i]+1+d+1, total-d-1) != -1)
+ return 0;
+ if (!isl_int_is_one(bmap->eq[i][1+d]))
+ return 0;
+ if (val)
+ isl_int_neg(*val, bmap->eq[i][0]);
+ return 1;
+ }
+ return 0;
+}
+
+static int isl_map_plain_has_fixed_var(__isl_keep isl_map *map,
+ unsigned pos, isl_int *val)
+{
+ int i;
+ isl_int v;
+ isl_int tmp;
+ int fixed;
+
+ if (!map)
+ return -1;
+ if (map->n == 0)
+ return 0;
+ if (map->n == 1)
+ return isl_basic_map_plain_has_fixed_var(map->p[0], pos, val);
+ isl_int_init(v);
+ isl_int_init(tmp);
+ fixed = isl_basic_map_plain_has_fixed_var(map->p[0], pos, &v);
+ for (i = 1; fixed == 1 && i < map->n; ++i) {
+ fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp);
+ if (fixed == 1 && isl_int_ne(tmp, v))
+ fixed = 0;
+ }
+ if (val)
+ isl_int_set(*val, v);
+ isl_int_clear(tmp);
+ isl_int_clear(v);
+ return fixed;
+}
+
+static int isl_basic_set_plain_has_fixed_var(__isl_keep isl_basic_set *bset,
+ unsigned pos, isl_int *val)
+{
+ return isl_basic_map_plain_has_fixed_var((struct isl_basic_map *)bset,
+ pos, val);
+}
+
+static int isl_set_plain_has_fixed_var(__isl_keep isl_set *set, unsigned pos,
+ isl_int *val)
+{
+ return isl_map_plain_has_fixed_var((struct isl_map *)set, pos, val);
+}
+
+int isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+ if (pos >= isl_basic_map_dim(bmap, type))
+ return -1;
+ return isl_basic_map_plain_has_fixed_var(bmap,
+ isl_basic_map_offset(bmap, type) - 1 + pos, val);
+}
+
+/* If "bmap" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed(
+ __isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ isl_ctx *ctx;
+ isl_val *v;
+ int fixed;
+
+ if (!bmap)
+ return NULL;
+ ctx = isl_basic_map_get_ctx(bmap);
+ v = isl_val_alloc(ctx);
+ if (!v)
+ return NULL;
+ fixed = isl_basic_map_plain_is_fixed(bmap, type, pos, &v->n);
+ if (fixed < 0)
+ return isl_val_free(v);
+ if (fixed) {
+ isl_int_set_si(v->d, 1);
+ return v;
+ }
+ isl_val_free(v);
+ return isl_val_nan(ctx);
+}
+
+int isl_map_plain_is_fixed(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+ if (pos >= isl_map_dim(map, type))
+ return -1;
+ return isl_map_plain_has_fixed_var(map,
+ map_offset(map, type) - 1 + pos, val);
+}
+
+/* If "map" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ isl_ctx *ctx;
+ isl_val *v;
+ int fixed;
+
+ if (!map)
+ return NULL;
+ ctx = isl_map_get_ctx(map);
+ v = isl_val_alloc(ctx);
+ if (!v)
+ return NULL;
+ fixed = isl_map_plain_is_fixed(map, type, pos, &v->n);
+ if (fixed < 0)
+ return isl_val_free(v);
+ if (fixed) {
+ isl_int_set_si(v->d, 1);
+ return v;
+ }
+ isl_val_free(v);
+ return isl_val_nan(ctx);
+}
+
+/* If "set" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_map_plain_get_val_if_fixed(set, type, pos);
+}
+
+int isl_set_plain_is_fixed(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+ return isl_map_plain_is_fixed(set, type, pos, val);
+}
+
+int isl_map_fast_is_fixed(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+ return isl_map_plain_is_fixed(map, type, pos, val);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+ unsigned dim, isl_int *val)
+{
+ return isl_basic_set_plain_has_fixed_var(bset,
+ isl_basic_set_n_param(bset) + dim, val);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_set_plain_dim_is_fixed(__isl_keep isl_set *set,
+ unsigned dim, isl_int *val)
+{
+ return isl_set_plain_has_fixed_var(set, isl_set_n_param(set) + dim, val);
+}
+
+int isl_set_fast_dim_is_fixed(__isl_keep isl_set *set,
+ unsigned dim, isl_int *val)
+{
+ return isl_set_plain_dim_is_fixed(set, dim, val);
+}
+
+/* Check if input variable in has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_map_plain_input_is_fixed(__isl_keep isl_map *map,
+ unsigned in, isl_int *val)
+{
+ return isl_map_plain_has_fixed_var(map, isl_map_n_param(map) + in, val);
+}
+
+/* Check if dimension dim has an (obvious) fixed lower bound and if so
+ * and if val is not NULL, then return this lower bound in *val.
+ */
+int isl_basic_set_plain_dim_has_fixed_lower_bound(
+ __isl_keep isl_basic_set *bset, unsigned dim, isl_int *val)
+{
+ int i, i_eq = -1, i_ineq = -1;
+ isl_int *c;
+ unsigned total;
+ unsigned nparam;
+
+ if (!bset)
+ return -1;
+ total = isl_basic_set_total_dim(bset);
+ nparam = isl_basic_set_n_param(bset);
+ for (i = 0; i < bset->n_eq; ++i) {
+ if (isl_int_is_zero(bset->eq[i][1+nparam+dim]))
+ continue;
+ if (i_eq != -1)
+ return 0;
+ i_eq = i;
+ }
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (!isl_int_is_pos(bset->ineq[i][1+nparam+dim]))
+ continue;
+ if (i_eq != -1 || i_ineq != -1)
+ return 0;
+ i_ineq = i;
+ }
+ if (i_eq == -1 && i_ineq == -1)
+ return 0;
+ c = i_eq != -1 ? bset->eq[i_eq] : bset->ineq[i_ineq];
+ /* The coefficient should always be one due to normalization. */
+ if (!isl_int_is_one(c[1+nparam+dim]))
+ return 0;
+ if (isl_seq_first_non_zero(c+1, nparam+dim) != -1)
+ return 0;
+ if (isl_seq_first_non_zero(c+1+nparam+dim+1,
+ total - nparam - dim - 1) != -1)
+ return 0;
+ if (val)
+ isl_int_neg(*val, c[0]);
+ return 1;
+}
+
+int isl_set_plain_dim_has_fixed_lower_bound(__isl_keep isl_set *set,
+ unsigned dim, isl_int *val)
+{
+ int i;
+ isl_int v;
+ isl_int tmp;
+ int fixed;
+
+ if (!set)
+ return -1;
+ if (set->n == 0)
+ return 0;
+ if (set->n == 1)
+ return isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+ dim, val);
+ isl_int_init(v);
+ isl_int_init(tmp);
+ fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+ dim, &v);
+ for (i = 1; fixed == 1 && i < set->n; ++i) {
+ fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[i],
+ dim, &tmp);
+ if (fixed == 1 && isl_int_ne(tmp, v))
+ fixed = 0;
+ }
+ if (val)
+ isl_int_set(*val, v);
+ isl_int_clear(tmp);
+ isl_int_clear(v);
+ return fixed;
+}
+
+/* uset_gist depends on constraints without existentially quantified
+ * variables sorting first.
+ */
+static int sort_constraint_cmp(const void *p1, const void *p2, void *arg)
+{
+ isl_int **c1 = (isl_int **) p1;
+ isl_int **c2 = (isl_int **) p2;
+ int l1, l2;
+ unsigned size = *(unsigned *) arg;
+
+ l1 = isl_seq_last_non_zero(*c1 + 1, size);
+ l2 = isl_seq_last_non_zero(*c2 + 1, size);
+
+ if (l1 != l2)
+ return l1 - l2;
+
+ return isl_seq_cmp(*c1 + 1, *c2 + 1, size);
+}
+
+static struct isl_basic_map *isl_basic_map_sort_constraints(
+ struct isl_basic_map *bmap)
+{
+ unsigned total;
+
+ if (!bmap)
+ return NULL;
+ if (bmap->n_ineq == 0)
+ return bmap;
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+ return bmap;
+ total = isl_basic_map_total_dim(bmap);
+ if (isl_sort(bmap->ineq, bmap->n_ineq, sizeof(isl_int *),
+ &sort_constraint_cmp, &total) < 0)
+ return isl_basic_map_free(bmap);
+ return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+ __isl_take isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)isl_basic_map_sort_constraints(
+ (struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_normalize(struct isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+ return bmap;
+ bmap = isl_basic_map_remove_redundancies(bmap);
+ bmap = isl_basic_map_sort_constraints(bmap);
+ if (bmap)
+ ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED);
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_normalize(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)isl_basic_map_normalize(
+ (struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+ const __isl_keep isl_basic_map *bmap2)
+{
+ int i, cmp;
+ unsigned total;
+
+ if (bmap1 == bmap2)
+ return 0;
+ if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) !=
+ ISL_F_ISSET(bmap2, ISL_BASIC_MAP_RATIONAL))
+ return ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) ? -1 : 1;
+ if (isl_basic_map_n_param(bmap1) != isl_basic_map_n_param(bmap2))
+ return isl_basic_map_n_param(bmap1) - isl_basic_map_n_param(bmap2);
+ if (isl_basic_map_n_in(bmap1) != isl_basic_map_n_in(bmap2))
+ return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+ if (isl_basic_map_n_out(bmap1) != isl_basic_map_n_out(bmap2))
+ return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+ if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY) &&
+ ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+ return 0;
+ if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY))
+ return 1;
+ if (ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+ return -1;
+ if (bmap1->n_eq != bmap2->n_eq)
+ return bmap1->n_eq - bmap2->n_eq;
+ if (bmap1->n_ineq != bmap2->n_ineq)
+ return bmap1->n_ineq - bmap2->n_ineq;
+ if (bmap1->n_div != bmap2->n_div)
+ return bmap1->n_div - bmap2->n_div;
+ total = isl_basic_map_total_dim(bmap1);
+ for (i = 0; i < bmap1->n_eq; ++i) {
+ cmp = isl_seq_cmp(bmap1->eq[i], bmap2->eq[i], 1+total);
+ if (cmp)
+ return cmp;
+ }
+ for (i = 0; i < bmap1->n_ineq; ++i) {
+ cmp = isl_seq_cmp(bmap1->ineq[i], bmap2->ineq[i], 1+total);
+ if (cmp)
+ return cmp;
+ }
+ for (i = 0; i < bmap1->n_div; ++i) {
+ cmp = isl_seq_cmp(bmap1->div[i], bmap2->div[i], 1+1+total);
+ if (cmp)
+ return cmp;
+ }
+ return 0;
+}
+
+int isl_basic_set_plain_cmp(const __isl_keep isl_basic_set *bset1,
+ const __isl_keep isl_basic_set *bset2)
+{
+ return isl_basic_map_plain_cmp(bset1, bset2);
+}
+
+int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ int i, cmp;
+
+ if (set1 == set2)
+ return 0;
+ if (set1->n != set2->n)
+ return set1->n - set2->n;
+
+ for (i = 0; i < set1->n; ++i) {
+ cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]);
+ if (cmp)
+ return cmp;
+ }
+
+ return 0;
+}
+
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+ __isl_keep isl_basic_map *bmap2)
+{
+ return isl_basic_map_plain_cmp(bmap1, bmap2) == 0;
+}
+
+int isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
+ __isl_keep isl_basic_set *bset2)
+{
+ return isl_basic_map_plain_is_equal((isl_basic_map *)bset1,
+ (isl_basic_map *)bset2);
+}
+
+static int qsort_bmap_cmp(const void *p1, const void *p2)
+{
+ const struct isl_basic_map *bmap1 = *(const struct isl_basic_map **)p1;
+ const struct isl_basic_map *bmap2 = *(const struct isl_basic_map **)p2;
+
+ return isl_basic_map_plain_cmp(bmap1, bmap2);
+}
+
+/* Sort the basic maps of "map" and remove duplicate basic maps.
+ *
+ * While removing basic maps, we make sure that the basic maps remain
+ * sorted because isl_map_normalize expects the basic maps of the result
+ * to be sorted.
+ */
+static __isl_give isl_map *sort_and_remove_duplicates(__isl_take isl_map *map)
+{
+ int i, j;
+
+ map = isl_map_remove_empty_parts(map);
+ if (!map)
+ return NULL;
+ qsort(map->p, map->n, sizeof(struct isl_basic_map *), qsort_bmap_cmp);
+ for (i = map->n - 1; i >= 1; --i) {
+ if (!isl_basic_map_plain_is_equal(map->p[i - 1], map->p[i]))
+ continue;
+ isl_basic_map_free(map->p[i-1]);
+ for (j = i; j < map->n; ++j)
+ map->p[j - 1] = map->p[j];
+ map->n--;
+ }
+
+ return map;
+}
+
+/* Remove obvious duplicates among the basic maps of "map".
+ *
+ * Unlike isl_map_normalize, this function does not remove redundant
+ * constraints and only removes duplicates that have exactly the same
+ * constraints in the input. It does sort the constraints and
+ * the basic maps to ease the detection of duplicates.
+ *
+ * If "map" has already been normalized or if the basic maps are
+ * disjoint, then there can be no duplicates.
+ */
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map)
+{
+ int i;
+ isl_basic_map *bmap;
+
+ if (!map)
+ return NULL;
+ if (map->n <= 1)
+ return map;
+ if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED | ISL_MAP_DISJOINT))
+ return map;
+ for (i = 0; i < map->n; ++i) {
+ bmap = isl_basic_map_copy(map->p[i]);
+ bmap = isl_basic_map_sort_constraints(bmap);
+ if (!bmap)
+ return isl_map_free(map);
+ isl_basic_map_free(map->p[i]);
+ map->p[i] = bmap;
+ }
+
+ map = sort_and_remove_duplicates(map);
+ return map;
+}
+
+/* We normalize in place, but if anything goes wrong we need
+ * to return NULL, so we need to make sure we don't change the
+ * meaning of any possible other copies of map.
+ */
+__isl_give isl_map *isl_map_normalize(__isl_take isl_map *map)
+{
+ int i;
+ struct isl_basic_map *bmap;
+
+ if (!map)
+ return NULL;
+ if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED))
+ return map;
+ for (i = 0; i < map->n; ++i) {
+ bmap = isl_basic_map_normalize(isl_basic_map_copy(map->p[i]));
+ if (!bmap)
+ goto error;
+ isl_basic_map_free(map->p[i]);
+ map->p[i] = bmap;
+ }
+
+ map = sort_and_remove_duplicates(map);
+ if (map)
+ ISL_F_SET(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_set *isl_set_normalize(struct isl_set *set)
+{
+ return (struct isl_set *)isl_map_normalize((struct isl_map *)set);
+}
+
+int isl_map_plain_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ int i;
+ int equal;
+
+ if (!map1 || !map2)
+ return -1;
+
+ if (map1 == map2)
+ return 1;
+ if (!isl_space_is_equal(map1->dim, map2->dim))
+ return 0;
+
+ map1 = isl_map_copy(map1);
+ map2 = isl_map_copy(map2);
+ map1 = isl_map_normalize(map1);
+ map2 = isl_map_normalize(map2);
+ if (!map1 || !map2)
+ goto error;
+ equal = map1->n == map2->n;
+ for (i = 0; equal && i < map1->n; ++i) {
+ equal = isl_basic_map_plain_is_equal(map1->p[i], map2->p[i]);
+ if (equal < 0)
+ goto error;
+ }
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return equal;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return -1;
+}
+
+int isl_map_fast_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ return isl_map_plain_is_equal(map1, map2);
+}
+
+int isl_set_plain_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ return isl_map_plain_is_equal((struct isl_map *)set1,
+ (struct isl_map *)set2);
+}
+
+int isl_set_fast_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ return isl_set_plain_is_equal(set1, set2);
+}
+
+/* Return an interval that ranges from min to max (inclusive)
+ */
+struct isl_basic_set *isl_basic_set_interval(struct isl_ctx *ctx,
+ isl_int min, isl_int max)
+{
+ int k;
+ struct isl_basic_set *bset = NULL;
+
+ bset = isl_basic_set_alloc(ctx, 0, 1, 0, 0, 2);
+ if (!bset)
+ goto error;
+
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(bset->ineq[k][1], 1);
+ isl_int_neg(bset->ineq[k][0], min);
+
+ k = isl_basic_set_alloc_inequality(bset);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(bset->ineq[k][1], -1);
+ isl_int_set(bset->ineq[k][0], max);
+
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Return the basic sets in "set" as a list.
+ */
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+ __isl_keep isl_set *set)
+{
+ int i;
+ isl_ctx *ctx;
+ isl_basic_set_list *list;
+
+ if (!set)
+ return NULL;
+ ctx = isl_set_get_ctx(set);
+ list = isl_basic_set_list_alloc(ctx, set->n);
+
+ for (i = 0; i < set->n; ++i) {
+ isl_basic_set *bset;
+
+ bset = isl_basic_set_copy(set->p[i]);
+ list = isl_basic_set_list_add(list, bset);
+ }
+
+ return list;
+}
+
+/* Return the intersection of the elements in the non-empty list "list".
+ * All elements are assumed to live in the same space.
+ */
+__isl_give isl_basic_set *isl_basic_set_list_intersect(
+ __isl_take struct isl_basic_set_list *list)
+{
+ int i, n;
+ isl_basic_set *bset;
+
+ if (!list)
+ return NULL;
+ n = isl_basic_set_list_n_basic_set(list);
+ if (n < 1)
+ isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid,
+ "expecting non-empty list", goto error);
+
+ bset = isl_basic_set_list_get_basic_set(list, 0);
+ for (i = 1; i < n; ++i) {
+ isl_basic_set *bset_i;
+
+ bset_i = isl_basic_set_list_get_basic_set(list, i);
+ bset = isl_basic_set_intersect(bset, bset_i);
+ }
+
+ isl_basic_set_list_free(list);
+ return bset;
+error:
+ isl_basic_set_list_free(list);
+ return NULL;
+}
+
+/* Return the Cartesian product of the basic sets in list (in the given order).
+ */
+__isl_give isl_basic_set *isl_basic_set_list_product(
+ __isl_take struct isl_basic_set_list *list)
+{
+ int i;
+ unsigned dim;
+ unsigned nparam;
+ unsigned extra;
+ unsigned n_eq;
+ unsigned n_ineq;
+ struct isl_basic_set *product = NULL;
+
+ if (!list)
+ goto error;
+ isl_assert(list->ctx, list->n > 0, goto error);
+ isl_assert(list->ctx, list->p[0], goto error);
+ nparam = isl_basic_set_n_param(list->p[0]);
+ dim = isl_basic_set_n_dim(list->p[0]);
+ extra = list->p[0]->n_div;
+ n_eq = list->p[0]->n_eq;
+ n_ineq = list->p[0]->n_ineq;
+ for (i = 1; i < list->n; ++i) {
+ isl_assert(list->ctx, list->p[i], goto error);
+ isl_assert(list->ctx,
+ nparam == isl_basic_set_n_param(list->p[i]), goto error);
+ dim += isl_basic_set_n_dim(list->p[i]);
+ extra += list->p[i]->n_div;
+ n_eq += list->p[i]->n_eq;
+ n_ineq += list->p[i]->n_ineq;
+ }
+ product = isl_basic_set_alloc(list->ctx, nparam, dim, extra,
+ n_eq, n_ineq);
+ if (!product)
+ goto error;
+ dim = 0;
+ for (i = 0; i < list->n; ++i) {
+ isl_basic_set_add_constraints(product,
+ isl_basic_set_copy(list->p[i]), dim);
+ dim += isl_basic_set_n_dim(list->p[i]);
+ }
+ isl_basic_set_list_free(list);
+ return product;
+error:
+ isl_basic_set_free(product);
+ isl_basic_set_list_free(list);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_product(
+ struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+ isl_space *dim_result = NULL;
+ struct isl_basic_map *bmap;
+ unsigned in1, in2, out1, out2, nparam, total, pos;
+ struct isl_dim_map *dim_map1, *dim_map2;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+ bmap2->dim, isl_dim_param), goto error);
+ dim_result = isl_space_product(isl_space_copy(bmap1->dim),
+ isl_space_copy(bmap2->dim));
+
+ in1 = isl_basic_map_n_in(bmap1);
+ in2 = isl_basic_map_n_in(bmap2);
+ out1 = isl_basic_map_n_out(bmap1);
+ out2 = isl_basic_map_n_out(bmap2);
+ nparam = isl_basic_map_n_param(bmap1);
+
+ total = nparam + in1 + in2 + out1 + out2 + bmap1->n_div + bmap2->n_div;
+ dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+ dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+ isl_dim_map_div(dim_map1, bmap1, pos += out2);
+ isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+ bmap = isl_basic_map_alloc_space(dim_result,
+ bmap1->n_div + bmap2->n_div,
+ bmap1->n_eq + bmap2->n_eq,
+ bmap1->n_ineq + bmap2->n_ineq);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_product(
+ __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+ isl_basic_map *prod;
+
+ prod = isl_basic_map_product(bmap1, bmap2);
+ prod = isl_basic_map_flatten(prod);
+ return prod;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flat_product(
+ __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+ return isl_basic_map_flat_range_product(bset1, bset2);
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_product(
+ __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+ isl_space *space_result = NULL;
+ isl_basic_map *bmap;
+ unsigned in1, in2, out, nparam, total, pos;
+ struct isl_dim_map *dim_map1, *dim_map2;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ space_result = isl_space_domain_product(isl_space_copy(bmap1->dim),
+ isl_space_copy(bmap2->dim));
+
+ in1 = isl_basic_map_dim(bmap1, isl_dim_in);
+ in2 = isl_basic_map_dim(bmap2, isl_dim_in);
+ out = isl_basic_map_dim(bmap1, isl_dim_out);
+ nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+ total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div;
+ dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+ dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos);
+ isl_dim_map_div(dim_map1, bmap1, pos += out);
+ isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+ bmap = isl_basic_map_alloc_space(space_result,
+ bmap1->n_div + bmap2->n_div,
+ bmap1->n_eq + bmap2->n_eq,
+ bmap1->n_ineq + bmap2->n_ineq);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_product(
+ __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+ isl_space *dim_result = NULL;
+ isl_basic_map *bmap;
+ unsigned in, out1, out2, nparam, total, pos;
+ struct isl_dim_map *dim_map1, *dim_map2;
+
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ if (!isl_space_match(bmap1->dim, isl_dim_param,
+ bmap2->dim, isl_dim_param))
+ isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+ "parameters don't match", goto error);
+
+ dim_result = isl_space_range_product(isl_space_copy(bmap1->dim),
+ isl_space_copy(bmap2->dim));
+
+ in = isl_basic_map_dim(bmap1, isl_dim_in);
+ out1 = isl_basic_map_n_out(bmap1);
+ out2 = isl_basic_map_n_out(bmap2);
+ nparam = isl_basic_map_n_param(bmap1);
+
+ total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div;
+ dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+ dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+ isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in);
+ isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+ isl_dim_map_div(dim_map1, bmap1, pos += out2);
+ isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+ bmap = isl_basic_map_alloc_space(dim_result,
+ bmap1->n_div + bmap2->n_div,
+ bmap1->n_eq + bmap2->n_eq,
+ bmap1->n_ineq + bmap2->n_ineq);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+ bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap1);
+ isl_basic_map_free(bmap2);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+ __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+ isl_basic_map *prod;
+
+ prod = isl_basic_map_range_product(bmap1, bmap2);
+ prod = isl_basic_map_flatten_range(prod);
+ return prod;
+}
+
+/* Apply "basic_map_product" to each pair of basic maps in "map1" and "map2"
+ * and collect the results.
+ * The result live in the space obtained by calling "space_product"
+ * on the spaces of "map1" and "map2".
+ * If "remove_duplicates" is set then the result may contain duplicates
+ * (even if the inputs do not) and so we try and remove the obvious
+ * duplicates.
+ */
+static __isl_give isl_map *map_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2,
+ __isl_give isl_space *(*space_product)(__isl_take isl_space *left,
+ __isl_take isl_space *right),
+ __isl_give isl_basic_map *(*basic_map_product)(
+ __isl_take isl_basic_map *left,
+ __isl_take isl_basic_map *right),
+ int remove_duplicates)
+{
+ unsigned flags = 0;
+ struct isl_map *result;
+ int i, j;
+
+ if (!map1 || !map2)
+ goto error;
+
+ isl_assert(map1->ctx, isl_space_match(map1->dim, isl_dim_param,
+ map2->dim, isl_dim_param), goto error);
+
+ if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+ ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+ ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+ result = isl_map_alloc_space(space_product(isl_space_copy(map1->dim),
+ isl_space_copy(map2->dim)),
+ map1->n * map2->n, flags);
+ if (!result)
+ goto error;
+ for (i = 0; i < map1->n; ++i)
+ for (j = 0; j < map2->n; ++j) {
+ struct isl_basic_map *part;
+ part = basic_map_product(isl_basic_map_copy(map1->p[i]),
+ isl_basic_map_copy(map2->p[j]));
+ if (isl_basic_map_is_empty(part))
+ isl_basic_map_free(part);
+ else
+ result = isl_map_add_basic_map(result, part);
+ if (!result)
+ goto error;
+ }
+ if (remove_duplicates)
+ result = isl_map_remove_obvious_duplicates(result);
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return result;
+error:
+ isl_map_free(map1);
+ isl_map_free(map2);
+ return NULL;
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> [B -> D]
+ */
+static __isl_give isl_map *map_product_aligned(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return map_product(map1, map2, &isl_space_product,
+ &isl_basic_map_product, 0);
+}
+
+__isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2, &map_product_aligned);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *prod;
+
+ prod = isl_map_product(map1, map2);
+ prod = isl_map_flatten(prod);
+ return prod;
+}
+
+/* Given two set A and B, construct its Cartesian product A x B.
+ */
+struct isl_set *isl_set_product(struct isl_set *set1, struct isl_set *set2)
+{
+ return isl_map_range_product(set1, set2);
+}
+
+__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
+ __isl_take isl_set *set2)
+{
+ return isl_map_flat_range_product(set1, set2);
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)
+ */
+static __isl_give isl_map *map_domain_product_aligned(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return map_product(map1, map2, &isl_space_domain_product,
+ &isl_basic_map_domain_product, 1);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D]
+ */
+static __isl_give isl_map *map_range_product_aligned(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return map_product(map1, map2, &isl_space_range_product,
+ &isl_basic_map_range_product, 1);
+}
+
+__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2,
+ &map_domain_product_aligned);
+}
+
+__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ return isl_map_align_params_map_map_and(map1, map2,
+ &map_range_product_aligned);
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map A -> C.
+ */
+__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total1, keep1, total2, keep2;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_domain_is_wrapping(map->dim) ||
+ !isl_space_range_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total1 = isl_space_dim(space, isl_dim_in);
+ total2 = isl_space_dim(space, isl_dim_out);
+ space = isl_space_factor_domain(space);
+ keep1 = isl_space_dim(space, isl_dim_in);
+ keep2 = isl_space_dim(space, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_in, keep1, total1 - keep1);
+ map = isl_map_project_out(map, isl_dim_out, keep2, total2 - keep2);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map B -> D.
+ */
+__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total1, keep1, total2, keep2;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_domain_is_wrapping(map->dim) ||
+ !isl_space_range_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total1 = isl_space_dim(space, isl_dim_in);
+ total2 = isl_space_dim(space, isl_dim_out);
+ space = isl_space_factor_range(space);
+ keep1 = isl_space_dim(space, isl_dim_in);
+ keep2 = isl_space_dim(space, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_in, 0, total1 - keep1);
+ map = isl_map_project_out(map, isl_dim_out, 0, total2 - keep2);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map A -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_domain_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "domain is not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total = isl_space_dim(space, isl_dim_in);
+ space = isl_space_domain_factor_domain(space);
+ keep = isl_space_dim(space, isl_dim_in);
+ map = isl_map_project_out(map, isl_dim_in, keep, total - keep);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map B -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_domain_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "domain is not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total = isl_space_dim(space, isl_dim_in);
+ space = isl_space_domain_factor_range(space);
+ keep = isl_space_dim(space, isl_dim_in);
+ map = isl_map_project_out(map, isl_dim_in, 0, total - keep);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> B.
+ */
+__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_range_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "range is not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total = isl_space_dim(space, isl_dim_out);
+ space = isl_space_range_factor_domain(space);
+ keep = isl_space_dim(space, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_out, keep, total - keep);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> C.
+ */
+__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map)
+{
+ isl_space *space;
+ int total, keep;
+
+ if (!map)
+ return NULL;
+ if (!isl_space_range_is_wrapping(map->dim))
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "range is not a product", return isl_map_free(map));
+
+ space = isl_map_get_space(map);
+ total = isl_space_dim(space, isl_dim_out);
+ space = isl_space_range_factor_range(space);
+ keep = isl_space_dim(space, isl_dim_out);
+ map = isl_map_project_out(map, isl_dim_out, 0, total - keep);
+ map = isl_map_reset_space(map, space);
+
+ return map;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D)
+ */
+__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *prod;
+
+ prod = isl_map_domain_product(map1, map2);
+ prod = isl_map_flatten_domain(prod);
+ return prod;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1,
+ __isl_take isl_map *map2)
+{
+ isl_map *prod;
+
+ prod = isl_map_range_product(map1, map2);
+ prod = isl_map_flatten_range(prod);
+ return prod;
+}
+
+uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap)
+{
+ int i;
+ uint32_t hash = isl_hash_init();
+ unsigned total;
+
+ if (!bmap)
+ return 0;
+ bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_normalize(bmap);
+ if (!bmap)
+ return 0;
+ total = isl_basic_map_total_dim(bmap);
+ isl_hash_byte(hash, bmap->n_eq & 0xFF);
+ for (i = 0; i < bmap->n_eq; ++i) {
+ uint32_t c_hash;
+ c_hash = isl_seq_get_hash(bmap->eq[i], 1 + total);
+ isl_hash_hash(hash, c_hash);
+ }
+ isl_hash_byte(hash, bmap->n_ineq & 0xFF);
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ uint32_t c_hash;
+ c_hash = isl_seq_get_hash(bmap->ineq[i], 1 + total);
+ isl_hash_hash(hash, c_hash);
+ }
+ isl_hash_byte(hash, bmap->n_div & 0xFF);
+ for (i = 0; i < bmap->n_div; ++i) {
+ uint32_t c_hash;
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ isl_hash_byte(hash, i & 0xFF);
+ c_hash = isl_seq_get_hash(bmap->div[i], 1 + 1 + total);
+ isl_hash_hash(hash, c_hash);
+ }
+ isl_basic_map_free(bmap);
+ return hash;
+}
+
+uint32_t isl_basic_set_get_hash(__isl_keep isl_basic_set *bset)
+{
+ return isl_basic_map_get_hash((isl_basic_map *)bset);
+}
+
+uint32_t isl_map_get_hash(__isl_keep isl_map *map)
+{
+ int i;
+ uint32_t hash;
+
+ if (!map)
+ return 0;
+ map = isl_map_copy(map);
+ map = isl_map_normalize(map);
+ if (!map)
+ return 0;
+
+ hash = isl_hash_init();
+ for (i = 0; i < map->n; ++i) {
+ uint32_t bmap_hash;
+ bmap_hash = isl_basic_map_get_hash(map->p[i]);
+ isl_hash_hash(hash, bmap_hash);
+ }
+
+ isl_map_free(map);
+
+ return hash;
+}
+
+uint32_t isl_set_get_hash(__isl_keep isl_set *set)
+{
+ return isl_map_get_hash((isl_map *)set);
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality.
+ */
+int isl_basic_set_dim_is_unique(struct isl_basic_set *bset, unsigned dim)
+{
+ int i;
+ unsigned nparam;
+
+ if (!bset)
+ return -1;
+ nparam = isl_basic_set_n_param(bset);
+ for (i = 0; i < bset->n_eq; ++i)
+ if (!isl_int_is_zero(bset->eq[i][1 + nparam + dim]))
+ return 1;
+ return 0;
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality
+ * for each of the subsets.
+ */
+int isl_set_dim_is_unique(struct isl_set *set, unsigned dim)
+{
+ int i;
+
+ if (!set)
+ return -1;
+ for (i = 0; i < set->n; ++i) {
+ int unique;
+ unique = isl_basic_set_dim_is_unique(set->p[i], dim);
+ if (unique != 1)
+ return unique;
+ }
+ return 1;
+}
+
+/* Return the number of basic maps in the (current) representation of "map".
+ */
+int isl_map_n_basic_map(__isl_keep isl_map *map)
+{
+ return map ? map->n : 0;
+}
+
+int isl_set_n_basic_set(__isl_keep isl_set *set)
+{
+ return set ? set->n : 0;
+}
+
+int isl_map_foreach_basic_map(__isl_keep isl_map *map,
+ int (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user)
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i)
+ if (fn(isl_basic_map_copy(map->p[i]), user) < 0)
+ return -1;
+
+ return 0;
+}
+
+int isl_set_foreach_basic_set(__isl_keep isl_set *set,
+ int (*fn)(__isl_take isl_basic_set *bset, void *user), void *user)
+{
+ int i;
+
+ if (!set)
+ return -1;
+
+ for (i = 0; i < set->n; ++i)
+ if (fn(isl_basic_set_copy(set->p[i]), user) < 0)
+ return -1;
+
+ return 0;
+}
+
+__isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset)
+{
+ isl_space *dim;
+
+ if (!bset)
+ return NULL;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ return NULL;
+
+ dim = isl_basic_set_get_space(bset);
+ dim = isl_space_lift(dim, bset->n_div);
+ if (!dim)
+ goto error;
+ isl_space_free(bset->dim);
+ bset->dim = dim;
+ bset->extra -= bset->n_div;
+ bset->n_div = 0;
+
+ bset = isl_basic_set_finalize(bset);
+
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_lift(__isl_take isl_set *set)
+{
+ int i;
+ isl_space *dim;
+ unsigned n_div;
+
+ set = isl_set_align_divs(set);
+
+ if (!set)
+ return NULL;
+
+ set = isl_set_cow(set);
+ if (!set)
+ return NULL;
+
+ n_div = set->p[0]->n_div;
+ dim = isl_set_get_space(set);
+ dim = isl_space_lift(dim, n_div);
+ if (!dim)
+ goto error;
+ isl_space_free(set->dim);
+ set->dim = dim;
+
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_lift(set->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_map *isl_set_lifting(__isl_take isl_set *set)
+{
+ isl_space *dim;
+ struct isl_basic_map *bmap;
+ unsigned n_set;
+ unsigned n_div;
+ unsigned n_param;
+ unsigned total;
+ int i, k, l;
+
+ set = isl_set_align_divs(set);
+
+ if (!set)
+ return NULL;
+
+ dim = isl_set_get_space(set);
+ if (set->n == 0 || set->p[0]->n_div == 0) {
+ isl_set_free(set);
+ return isl_map_identity(isl_space_map_from_set(dim));
+ }
+
+ n_div = set->p[0]->n_div;
+ dim = isl_space_map_from_set(dim);
+ n_param = isl_space_dim(dim, isl_dim_param);
+ n_set = isl_space_dim(dim, isl_dim_in);
+ dim = isl_space_extend(dim, n_param, n_set, n_set + n_div);
+ bmap = isl_basic_map_alloc_space(dim, 0, n_set, 2 * n_div);
+ for (i = 0; i < n_set; ++i)
+ bmap = var_equal(bmap, i);
+
+ total = n_param + n_set + n_set + n_div;
+ for (i = 0; i < n_div; ++i) {
+ k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bmap->ineq[k], set->p[0]->div[i]+1, 1+n_param);
+ isl_seq_clr(bmap->ineq[k]+1+n_param, n_set);
+ isl_seq_cpy(bmap->ineq[k]+1+n_param+n_set,
+ set->p[0]->div[i]+1+1+n_param, n_set + n_div);
+ isl_int_neg(bmap->ineq[k][1+n_param+n_set+n_set+i],
+ set->p[0]->div[i][0]);
+
+ l = isl_basic_map_alloc_inequality(bmap);
+ if (l < 0)
+ goto error;
+ isl_seq_neg(bmap->ineq[l], bmap->ineq[k], 1 + total);
+ isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0],
+ set->p[0]->div[i][0]);
+ isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+ }
+
+ isl_set_free(set);
+ bmap = isl_basic_map_simplify(bmap);
+ bmap = isl_basic_map_finalize(bmap);
+ return isl_map_from_basic_map(bmap);
+error:
+ isl_set_free(set);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+int isl_basic_set_size(__isl_keep isl_basic_set *bset)
+{
+ unsigned dim;
+ int size = 0;
+
+ if (!bset)
+ return -1;
+
+ dim = isl_basic_set_total_dim(bset);
+ size += bset->n_eq * (1 + dim);
+ size += bset->n_ineq * (1 + dim);
+ size += bset->n_div * (2 + dim);
+
+ return size;
+}
+
+int isl_set_size(__isl_keep isl_set *set)
+{
+ int i;
+ int size = 0;
+
+ if (!set)
+ return -1;
+
+ for (i = 0; i < set->n; ++i)
+ size += isl_basic_set_size(set->p[i]);
+
+ return size;
+}
+
+/* Check if there is any lower bound (if lower == 0) and/or upper
+ * bound (if upper == 0) on the specified dim.
+ */
+static int basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos, int lower, int upper)
+{
+ int i;
+
+ if (!bmap)
+ return -1;
+
+ isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), return -1);
+
+ pos += isl_basic_map_offset(bmap, type);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (!isl_int_is_zero(bmap->div[i][1 + pos]))
+ return 1;
+ }
+
+ for (i = 0; i < bmap->n_eq; ++i)
+ if (!isl_int_is_zero(bmap->eq[i][pos]))
+ return 1;
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ int sgn = isl_int_sgn(bmap->ineq[i][pos]);
+ if (sgn > 0)
+ lower = 1;
+ if (sgn < 0)
+ upper = 1;
+ }
+
+ return lower && upper;
+}
+
+int isl_basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ return basic_map_dim_is_bounded(bmap, type, pos, 0, 0);
+}
+
+int isl_basic_map_dim_has_lower_bound(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ return basic_map_dim_is_bounded(bmap, type, pos, 0, 1);
+}
+
+int isl_basic_map_dim_has_upper_bound(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos)
+{
+ return basic_map_dim_is_bounded(bmap, type, pos, 1, 0);
+}
+
+int isl_map_dim_is_bounded(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos)
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i) {
+ int bounded;
+ bounded = isl_basic_map_dim_is_bounded(map->p[i], type, pos);
+ if (bounded < 0 || !bounded)
+ return bounded;
+ }
+
+ return 1;
+}
+
+/* Return 1 if the specified dim is involved in both an upper bound
+ * and a lower bound.
+ */
+int isl_set_dim_is_bounded(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return isl_map_dim_is_bounded((isl_map *)set, type, pos);
+}
+
+/* Does "map" have a bound (according to "fn") for any of its basic maps?
+ */
+static int has_any_bound(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos,
+ int (*fn)(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos))
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i) {
+ int bounded;
+ bounded = fn(map->p[i], type, pos);
+ if (bounded < 0 || bounded)
+ return bounded;
+ }
+
+ return 0;
+}
+
+/* Return 1 if the specified dim is involved in any lower bound.
+ */
+int isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return has_any_bound(set, type, pos,
+ &isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim is involved in any upper bound.
+ */
+int isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return has_any_bound(set, type, pos,
+ &isl_basic_map_dim_has_upper_bound);
+}
+
+/* Does "map" have a bound (according to "fn") for all of its basic maps?
+ */
+static int has_bound(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos,
+ int (*fn)(__isl_keep isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned pos))
+{
+ int i;
+
+ if (!map)
+ return -1;
+
+ for (i = 0; i < map->n; ++i) {
+ int bounded;
+ bounded = fn(map->p[i], type, pos);
+ if (bounded < 0 || !bounded)
+ return bounded;
+ }
+
+ return 1;
+}
+
+/* Return 1 if the specified dim has a lower bound (in each of its basic sets).
+ */
+int isl_set_dim_has_lower_bound(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return has_bound(set, type, pos, &isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim has an upper bound (in each of its basic sets).
+ */
+int isl_set_dim_has_upper_bound(__isl_keep isl_set *set,
+ enum isl_dim_type type, unsigned pos)
+{
+ return has_bound(set, type, pos, &isl_basic_map_dim_has_upper_bound);
+}
+
+/* For each of the "n" variables starting at "first", determine
+ * the sign of the variable and put the results in the first "n"
+ * elements of the array "signs".
+ * Sign
+ * 1 means that the variable is non-negative
+ * -1 means that the variable is non-positive
+ * 0 means the variable attains both positive and negative values.
+ */
+int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+ unsigned first, unsigned n, int *signs)
+{
+ isl_vec *bound = NULL;
+ struct isl_tab *tab = NULL;
+ struct isl_tab_undo *snap;
+ int i;
+
+ if (!bset || !signs)
+ return -1;
+
+ bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset));
+ tab = isl_tab_from_basic_set(bset, 0);
+ if (!bound || !tab)
+ goto error;
+
+ isl_seq_clr(bound->el, bound->size);
+ isl_int_set_si(bound->el[0], -1);
+
+ snap = isl_tab_snap(tab);
+ for (i = 0; i < n; ++i) {
+ int empty;
+
+ isl_int_set_si(bound->el[1 + first + i], -1);
+ if (isl_tab_add_ineq(tab, bound->el) < 0)
+ goto error;
+ empty = tab->empty;
+ isl_int_set_si(bound->el[1 + first + i], 0);
+ if (isl_tab_rollback(tab, snap) < 0)
+ goto error;
+
+ if (empty) {
+ signs[i] = 1;
+ continue;
+ }
+
+ isl_int_set_si(bound->el[1 + first + i], 1);
+ if (isl_tab_add_ineq(tab, bound->el) < 0)
+ goto error;
+ empty = tab->empty;
+ isl_int_set_si(bound->el[1 + first + i], 0);
+ if (isl_tab_rollback(tab, snap) < 0)
+ goto error;
+
+ signs[i] = empty ? -1 : 0;
+ }
+
+ isl_tab_free(tab);
+ isl_vec_free(bound);
+ return 0;
+error:
+ isl_tab_free(tab);
+ isl_vec_free(bound);
+ return -1;
+}
+
+int isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n, int *signs)
+{
+ if (!bset || !signs)
+ return -1;
+ isl_assert(bset->ctx, first + n <= isl_basic_set_dim(bset, type),
+ return -1);
+
+ first += pos(bset->dim, type) - 1;
+ return isl_basic_set_vars_get_sign(bset, first, n, signs);
+}
+
+/* Is it possible for the integer division "div" to depend (possibly
+ * indirectly) on any output dimensions?
+ *
+ * If the div is undefined, then we conservatively assume that it
+ * may depend on them.
+ * Otherwise, we check if it actually depends on them or on any integer
+ * divisions that may depend on them.
+ */
+static int div_may_involve_output(__isl_keep isl_basic_map *bmap, int div)
+{
+ int i;
+ unsigned n_out, o_out;
+ unsigned n_div, o_div;
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return 1;
+
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+ o_out = isl_basic_map_offset(bmap, isl_dim_out);
+
+ if (isl_seq_first_non_zero(bmap->div[div] + 1 + o_out, n_out) != -1)
+ return 1;
+
+ n_div = isl_basic_map_dim(bmap, isl_dim_div);
+ o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+ for (i = 0; i < n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[div][1 + o_div + i]))
+ continue;
+ if (div_may_involve_output(bmap, i))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return the index of the equality of "bmap" that defines
+ * the output dimension "pos" in terms of earlier dimensions.
+ * The equality may also involve integer divisions, as long
+ * as those integer divisions are defined in terms of
+ * parameters or input dimensions.
+ * Return bmap->n_eq if there is no such equality.
+ * Return -1 on error.
+ */
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+ int pos)
+{
+ int j, k;
+ unsigned n_out, o_out;
+ unsigned n_div, o_div;
+
+ if (!bmap)
+ return -1;
+
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+ o_out = isl_basic_map_offset(bmap, isl_dim_out);
+ n_div = isl_basic_map_dim(bmap, isl_dim_div);
+ o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+ for (j = 0; j < bmap->n_eq; ++j) {
+ if (isl_int_is_zero(bmap->eq[j][o_out + pos]))
+ continue;
+ if (isl_seq_first_non_zero(bmap->eq[j] + o_out + pos + 1,
+ n_out - (pos + 1)) != -1)
+ continue;
+ for (k = 0; k < n_div; ++k) {
+ if (isl_int_is_zero(bmap->eq[j][o_div + k]))
+ continue;
+ if (div_may_involve_output(bmap, k))
+ break;
+ }
+ if (k >= n_div)
+ return j;
+ }
+
+ return bmap->n_eq;
+}
+
+/* Check if the given basic map is obviously single-valued.
+ * In particular, for each output dimension, check that there is
+ * an equality that defines the output dimension in terms of
+ * earlier dimensions.
+ */
+int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+ int i;
+ unsigned n_out;
+
+ if (!bmap)
+ return -1;
+
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+ for (i = 0; i < n_out; ++i) {
+ int eq;
+
+ eq = isl_basic_map_output_defining_equality(bmap, i);
+ if (eq < 0)
+ return -1;
+ if (eq >= bmap->n_eq)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Check if the given basic map is single-valued.
+ * We simply compute
+ *
+ * M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+ isl_space *space;
+ isl_basic_map *test;
+ isl_basic_map *id;
+ int sv;
+
+ sv = isl_basic_map_plain_is_single_valued(bmap);
+ if (sv < 0 || sv)
+ return sv;
+
+ test = isl_basic_map_reverse(isl_basic_map_copy(bmap));
+ test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap));
+
+ space = isl_basic_map_get_space(bmap);
+ space = isl_space_map_from_set(isl_space_range(space));
+ id = isl_basic_map_identity(space);
+
+ sv = isl_basic_map_is_subset(test, id);
+
+ isl_basic_map_free(test);
+ isl_basic_map_free(id);
+
+ return sv;
+}
+
+/* Check if the given map is obviously single-valued.
+ */
+int isl_map_plain_is_single_valued(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+ if (map->n == 0)
+ return 1;
+ if (map->n >= 2)
+ return 0;
+
+ return isl_basic_map_plain_is_single_valued(map->p[0]);
+}
+
+/* Check if the given map is single-valued.
+ * We simply compute
+ *
+ * M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_map_is_single_valued(__isl_keep isl_map *map)
+{
+ isl_space *dim;
+ isl_map *test;
+ isl_map *id;
+ int sv;
+
+ sv = isl_map_plain_is_single_valued(map);
+ if (sv < 0 || sv)
+ return sv;
+
+ test = isl_map_reverse(isl_map_copy(map));
+ test = isl_map_apply_range(test, isl_map_copy(map));
+
+ dim = isl_space_map_from_set(isl_space_range(isl_map_get_space(map)));
+ id = isl_map_identity(dim);
+
+ sv = isl_map_is_subset(test, id);
+
+ isl_map_free(test);
+ isl_map_free(id);
+
+ return sv;
+}
+
+int isl_map_is_injective(__isl_keep isl_map *map)
+{
+ int in;
+
+ map = isl_map_copy(map);
+ map = isl_map_reverse(map);
+ in = isl_map_is_single_valued(map);
+ isl_map_free(map);
+
+ return in;
+}
+
+/* Check if the given map is obviously injective.
+ */
+int isl_map_plain_is_injective(__isl_keep isl_map *map)
+{
+ int in;
+
+ map = isl_map_copy(map);
+ map = isl_map_reverse(map);
+ in = isl_map_plain_is_single_valued(map);
+ isl_map_free(map);
+
+ return in;
+}
+
+int isl_map_is_bijective(__isl_keep isl_map *map)
+{
+ int sv;
+
+ sv = isl_map_is_single_valued(map);
+ if (sv < 0 || !sv)
+ return sv;
+
+ return isl_map_is_injective(map);
+}
+
+int isl_set_is_singleton(__isl_keep isl_set *set)
+{
+ return isl_map_is_single_valued((isl_map *)set);
+}
+
+int isl_map_is_translation(__isl_keep isl_map *map)
+{
+ int ok;
+ isl_set *delta;
+
+ delta = isl_map_deltas(isl_map_copy(map));
+ ok = isl_set_is_singleton(delta);
+ isl_set_free(delta);
+
+ return ok;
+}
+
+static int unique(isl_int *p, unsigned pos, unsigned len)
+{
+ if (isl_seq_first_non_zero(p, pos) != -1)
+ return 0;
+ if (isl_seq_first_non_zero(p + pos + 1, len - pos - 1) != -1)
+ return 0;
+ return 1;
+}
+
+int isl_basic_set_is_box(__isl_keep isl_basic_set *bset)
+{
+ int i, j;
+ unsigned nvar;
+ unsigned ovar;
+
+ if (!bset)
+ return -1;
+
+ if (isl_basic_set_dim(bset, isl_dim_div) != 0)
+ return 0;
+
+ nvar = isl_basic_set_dim(bset, isl_dim_set);
+ ovar = isl_space_offset(bset->dim, isl_dim_set);
+ for (j = 0; j < nvar; ++j) {
+ int lower = 0, upper = 0;
+ for (i = 0; i < bset->n_eq; ++i) {
+ if (isl_int_is_zero(bset->eq[i][1 + ovar + j]))
+ continue;
+ if (!unique(bset->eq[i] + 1 + ovar, j, nvar))
+ return 0;
+ break;
+ }
+ if (i < bset->n_eq)
+ continue;
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_zero(bset->ineq[i][1 + ovar + j]))
+ continue;
+ if (!unique(bset->ineq[i] + 1 + ovar, j, nvar))
+ return 0;
+ if (isl_int_is_pos(bset->ineq[i][1 + ovar + j]))
+ lower = 1;
+ else
+ upper = 1;
+ }
+ if (!lower || !upper)
+ return 0;
+ }
+
+ return 1;
+}
+
+int isl_set_is_box(__isl_keep isl_set *set)
+{
+ if (!set)
+ return -1;
+ if (set->n != 1)
+ return 0;
+
+ return isl_basic_set_is_box(set->p[0]);
+}
+
+int isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset)
+{
+ if (!bset)
+ return -1;
+
+ return isl_space_is_wrapping(bset->dim);
+}
+
+int isl_set_is_wrapping(__isl_keep isl_set *set)
+{
+ if (!set)
+ return -1;
+
+ return isl_space_is_wrapping(set->dim);
+}
+
+/* Is the domain of "map" a wrapped relation?
+ */
+int isl_map_domain_is_wrapping(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+
+ return isl_space_domain_is_wrapping(map->dim);
+}
+
+/* Is the range of "map" a wrapped relation?
+ */
+int isl_map_range_is_wrapping(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+
+ return isl_space_range_is_wrapping(map->dim);
+}
+
+__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap)
+{
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_wrap(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return (isl_basic_set *)bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map)
+{
+ int i;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = (isl_basic_map *)isl_basic_map_wrap(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ map->dim = isl_space_wrap(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return (isl_set *)map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset)
+{
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ return NULL;
+
+ bset->dim = isl_space_unwrap(bset->dim);
+ if (!bset->dim)
+ goto error;
+
+ bset = isl_basic_set_finalize(bset);
+
+ return (isl_basic_map *)bset;
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set)
+{
+ int i;
+
+ if (!set)
+ return NULL;
+
+ if (!isl_set_is_wrapping(set))
+ isl_die(set->ctx, isl_error_invalid, "not a wrapping set",
+ goto error);
+
+ set = isl_set_cow(set);
+ if (!set)
+ return NULL;
+
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = (isl_basic_set *)isl_basic_set_unwrap(set->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+
+ set->dim = isl_space_unwrap(set->dim);
+ if (!set->dim)
+ goto error;
+
+ return (isl_map *)set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type)
+{
+ if (!bmap)
+ return NULL;
+
+ if (!isl_space_is_named_or_nested(bmap->dim, type))
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_reset(bmap->dim, type);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+ enum isl_dim_type type)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!isl_space_is_named_or_nested(map->dim, type))
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_reset(map->p[i], type);
+ if (!map->p[i])
+ goto error;
+ }
+ map->dim = isl_space_reset(map->dim, type);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (!bmap->dim->nested[0] && !bmap->dim->nested[1])
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_flatten(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset)
+{
+ return (isl_basic_set *)isl_basic_map_flatten((isl_basic_map *)bset);
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+ __isl_take isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (!bmap->dim->nested[0])
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_flatten_domain(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_range(
+ __isl_take isl_basic_map *bmap)
+{
+ if (!bmap)
+ return NULL;
+
+ if (!bmap->dim->nested[1])
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ bmap->dim = isl_space_flatten_range(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!map->dim->nested[0] && !map->dim->nested[1])
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_flatten(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ map->dim = isl_space_flatten(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set)
+{
+ return (isl_set *)isl_map_flatten((isl_map *)set);
+}
+
+__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set)
+{
+ isl_space *dim, *flat_dim;
+ isl_map *map;
+
+ dim = isl_set_get_space(set);
+ flat_dim = isl_space_flatten(isl_space_copy(dim));
+ map = isl_map_identity(isl_space_join(isl_space_reverse(dim), flat_dim));
+ map = isl_map_intersect_domain(map, set);
+
+ return map;
+}
+
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!map->dim->nested[0])
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_flatten_domain(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ map->dim = isl_space_flatten_domain(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!map->dim->nested[1])
+ return map;
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_flatten_range(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ map->dim = isl_space_flatten_range(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Reorder the dimensions of "bmap" according to the given dim_map
+ * and set the dimension specification to "dim".
+ */
+__isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap,
+ __isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map)
+{
+ isl_basic_map *res;
+ unsigned flags;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap || !dim || !dim_map)
+ goto error;
+
+ flags = bmap->flags;
+ ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL);
+ ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED);
+ ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS);
+ res = isl_basic_map_alloc_space(dim,
+ bmap->n_div, bmap->n_eq, bmap->n_ineq);
+ res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+ if (res)
+ res->flags = flags;
+ res = isl_basic_map_finalize(res);
+ return res;
+error:
+ free(dim_map);
+ isl_basic_map_free(bmap);
+ isl_space_free(dim);
+ return NULL;
+}
+
+/* Reorder the dimensions of "map" according to given reordering.
+ */
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+ __isl_take isl_reordering *r)
+{
+ int i;
+ struct isl_dim_map *dim_map;
+
+ map = isl_map_cow(map);
+ dim_map = isl_dim_map_from_reordering(r);
+ if (!map || !r || !dim_map)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ struct isl_dim_map *dim_map_i;
+
+ dim_map_i = isl_dim_map_extend(dim_map, map->p[i]);
+
+ map->p[i] = isl_basic_map_realign(map->p[i],
+ isl_space_copy(r->dim), dim_map_i);
+
+ if (!map->p[i])
+ goto error;
+ }
+
+ map = isl_map_reset_space(map, isl_space_copy(r->dim));
+
+ isl_reordering_free(r);
+ free(dim_map);
+ return map;
+error:
+ free(dim_map);
+ isl_map_free(map);
+ isl_reordering_free(r);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+ __isl_take isl_reordering *r)
+{
+ return (isl_set *)isl_map_realign((isl_map *)set, r);
+}
+
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+ __isl_take isl_space *model)
+{
+ isl_ctx *ctx;
+
+ if (!map || !model)
+ goto error;
+
+ ctx = isl_space_get_ctx(model);
+ if (!isl_space_has_named_params(model))
+ isl_die(ctx, isl_error_invalid,
+ "model has unnamed parameters", goto error);
+ if (!isl_space_has_named_params(map->dim))
+ isl_die(ctx, isl_error_invalid,
+ "relation has unnamed parameters", goto error);
+ if (!isl_space_match(map->dim, isl_dim_param, model, isl_dim_param)) {
+ isl_reordering *exp;
+
+ model = isl_space_drop_dims(model, isl_dim_in,
+ 0, isl_space_dim(model, isl_dim_in));
+ model = isl_space_drop_dims(model, isl_dim_out,
+ 0, isl_space_dim(model, isl_dim_out));
+ exp = isl_parameter_alignment_reordering(map->dim, model);
+ exp = isl_reordering_extend_space(exp, isl_map_get_space(map));
+ map = isl_map_realign(map, exp);
+ }
+
+ isl_space_free(model);
+ return map;
+error:
+ isl_space_free(model);
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+ __isl_take isl_space *model)
+{
+ return isl_map_align_params(set, model);
+}
+
+/* Align the parameters of "bmap" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_params(
+ __isl_take isl_basic_map *bmap, __isl_take isl_space *model)
+{
+ isl_ctx *ctx;
+
+ if (!bmap || !model)
+ goto error;
+
+ ctx = isl_space_get_ctx(model);
+ if (!isl_space_has_named_params(model))
+ isl_die(ctx, isl_error_invalid,
+ "model has unnamed parameters", goto error);
+ if (!isl_space_has_named_params(bmap->dim))
+ isl_die(ctx, isl_error_invalid,
+ "relation has unnamed parameters", goto error);
+ if (!isl_space_match(bmap->dim, isl_dim_param, model, isl_dim_param)) {
+ isl_reordering *exp;
+ struct isl_dim_map *dim_map;
+
+ model = isl_space_drop_dims(model, isl_dim_in,
+ 0, isl_space_dim(model, isl_dim_in));
+ model = isl_space_drop_dims(model, isl_dim_out,
+ 0, isl_space_dim(model, isl_dim_out));
+ exp = isl_parameter_alignment_reordering(bmap->dim, model);
+ exp = isl_reordering_extend_space(exp,
+ isl_basic_map_get_space(bmap));
+ dim_map = isl_dim_map_from_reordering(exp);
+ bmap = isl_basic_map_realign(bmap,
+ exp ? isl_space_copy(exp->dim) : NULL,
+ isl_dim_map_extend(dim_map, bmap));
+ isl_reordering_free(exp);
+ free(dim_map);
+ }
+
+ isl_space_free(model);
+ return bmap;
+error:
+ isl_space_free(model);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Align the parameters of "bset" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_set *isl_basic_set_align_params(
+ __isl_take isl_basic_set *bset, __isl_take isl_space *model)
+{
+ return isl_basic_map_align_params(bset, model);
+}
+
+__isl_give isl_mat *isl_basic_map_equalities_matrix(
+ __isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3,
+ enum isl_dim_type c4, enum isl_dim_type c5)
+{
+ enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+ struct isl_mat *mat;
+ int i, j, k;
+ int pos;
+
+ if (!bmap)
+ return NULL;
+ mat = isl_mat_alloc(bmap->ctx, bmap->n_eq,
+ isl_basic_map_total_dim(bmap) + 1);
+ if (!mat)
+ return NULL;
+ for (i = 0; i < bmap->n_eq; ++i)
+ for (j = 0, pos = 0; j < 5; ++j) {
+ int off = isl_basic_map_offset(bmap, c[j]);
+ for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+ isl_int_set(mat->row[i][pos],
+ bmap->eq[i][off + k]);
+ ++pos;
+ }
+ }
+
+ return mat;
+}
+
+__isl_give isl_mat *isl_basic_map_inequalities_matrix(
+ __isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3,
+ enum isl_dim_type c4, enum isl_dim_type c5)
+{
+ enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+ struct isl_mat *mat;
+ int i, j, k;
+ int pos;
+
+ if (!bmap)
+ return NULL;
+ mat = isl_mat_alloc(bmap->ctx, bmap->n_ineq,
+ isl_basic_map_total_dim(bmap) + 1);
+ if (!mat)
+ return NULL;
+ for (i = 0; i < bmap->n_ineq; ++i)
+ for (j = 0, pos = 0; j < 5; ++j) {
+ int off = isl_basic_map_offset(bmap, c[j]);
+ for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+ isl_int_set(mat->row[i][pos],
+ bmap->ineq[i][off + k]);
+ ++pos;
+ }
+ }
+
+ return mat;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
+ __isl_take isl_space *dim,
+ __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3,
+ enum isl_dim_type c4, enum isl_dim_type c5)
+{
+ enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+ isl_basic_map *bmap;
+ unsigned total;
+ unsigned extra;
+ int i, j, k, l;
+ int pos;
+
+ if (!dim || !eq || !ineq)
+ goto error;
+
+ if (eq->n_col != ineq->n_col)
+ isl_die(dim->ctx, isl_error_invalid,
+ "equalities and inequalities matrices should have "
+ "same number of columns", goto error);
+
+ total = 1 + isl_space_dim(dim, isl_dim_all);
+
+ if (eq->n_col < total)
+ isl_die(dim->ctx, isl_error_invalid,
+ "number of columns too small", goto error);
+
+ extra = eq->n_col - total;
+
+ bmap = isl_basic_map_alloc_space(isl_space_copy(dim), extra,
+ eq->n_row, ineq->n_row);
+ if (!bmap)
+ goto error;
+ for (i = 0; i < extra; ++i) {
+ k = isl_basic_map_alloc_div(bmap);
+ if (k < 0)
+ goto error;
+ isl_int_set_si(bmap->div[k][0], 0);
+ }
+ for (i = 0; i < eq->n_row; ++i) {
+ l = isl_basic_map_alloc_equality(bmap);
+ if (l < 0)
+ goto error;
+ for (j = 0, pos = 0; j < 5; ++j) {
+ int off = isl_basic_map_offset(bmap, c[j]);
+ for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+ isl_int_set(bmap->eq[l][off + k],
+ eq->row[i][pos]);
+ ++pos;
+ }
+ }
+ }
+ for (i = 0; i < ineq->n_row; ++i) {
+ l = isl_basic_map_alloc_inequality(bmap);
+ if (l < 0)
+ goto error;
+ for (j = 0, pos = 0; j < 5; ++j) {
+ int off = isl_basic_map_offset(bmap, c[j]);
+ for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+ isl_int_set(bmap->ineq[l][off + k],
+ ineq->row[i][pos]);
+ ++pos;
+ }
+ }
+ }
+
+ isl_space_free(dim);
+ isl_mat_free(eq);
+ isl_mat_free(ineq);
+
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_space_free(dim);
+ isl_mat_free(eq);
+ isl_mat_free(ineq);
+ return NULL;
+}
+
+__isl_give isl_mat *isl_basic_set_equalities_matrix(
+ __isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+ return isl_basic_map_equalities_matrix((isl_basic_map *)bset,
+ c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_mat *isl_basic_set_inequalities_matrix(
+ __isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+ return isl_basic_map_inequalities_matrix((isl_basic_map *)bset,
+ c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
+ __isl_take isl_space *dim,
+ __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+ enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+ return (isl_basic_set*)
+ isl_basic_map_from_constraint_matrices(dim, eq, ineq,
+ c1, c2, c3, c4, isl_dim_in);
+}
+
+int isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+
+ return isl_space_can_zip(bmap->dim);
+}
+
+int isl_map_can_zip(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+
+ return isl_space_can_zip(map->dim);
+}
+
+/* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap)
+{
+ unsigned pos;
+ unsigned n1;
+ unsigned n2;
+
+ if (!bmap)
+ return NULL;
+
+ if (!isl_basic_map_can_zip(bmap))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "basic map cannot be zipped", goto error);
+ pos = isl_basic_map_offset(bmap, isl_dim_in) +
+ isl_space_dim(bmap->dim->nested[0], isl_dim_in);
+ n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out);
+ n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2);
+ if (!bmap)
+ return NULL;
+ bmap->dim = isl_space_zip(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Given a map (A -> B) -> (C -> D), return the corresponding map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_map *isl_map_zip(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!isl_map_can_zip(map))
+ isl_die(map->ctx, isl_error_invalid, "map cannot be zipped",
+ goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_zip(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+
+ map->dim = isl_space_zip(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Can we apply isl_basic_map_curry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+
+ return isl_space_can_curry(bmap->dim);
+}
+
+/* Can we apply isl_map_curry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_map_can_curry(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+
+ return isl_space_can_curry(map->dim);
+}
+
+/* Given a basic map (A -> B) -> C, return the corresponding basic map
+ * A -> (B -> C).
+ */
+__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap)
+{
+
+ if (!bmap)
+ return NULL;
+
+ if (!isl_basic_map_can_curry(bmap))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "basic map cannot be curried", goto error);
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ bmap->dim = isl_space_curry(bmap->dim);
+ if (!bmap->dim)
+ goto error;
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Given a map (A -> B) -> C, return the corresponding map
+ * A -> (B -> C).
+ */
+__isl_give isl_map *isl_map_curry(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!isl_map_can_curry(map))
+ isl_die(map->ctx, isl_error_invalid, "map cannot be curried",
+ goto error);
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_curry(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+
+ map->dim = isl_space_curry(map->dim);
+ if (!map->dim)
+ goto error;
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Can we apply isl_basic_map_uncurry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap)
+{
+ if (!bmap)
+ return -1;
+
+ return isl_space_can_uncurry(bmap->dim);
+}
+
+/* Can we apply isl_map_uncurry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_map_can_uncurry(__isl_keep isl_map *map)
+{
+ if (!map)
+ return -1;
+
+ return isl_space_can_uncurry(map->dim);
+}
+
+/* Given a basic map A -> (B -> C), return the corresponding basic map
+ * (A -> B) -> C.
+ */
+__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap)
+{
+
+ if (!bmap)
+ return NULL;
+
+ if (!isl_basic_map_can_uncurry(bmap))
+ isl_die(bmap->ctx, isl_error_invalid,
+ "basic map cannot be uncurried",
+ return isl_basic_map_free(bmap));
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ bmap->dim = isl_space_uncurry(bmap->dim);
+ if (!bmap->dim)
+ return isl_basic_map_free(bmap);
+ return bmap;
+}
+
+/* Given a map A -> (B -> C), return the corresponding map
+ * (A -> B) -> C.
+ */
+__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (!isl_map_can_uncurry(map))
+ isl_die(map->ctx, isl_error_invalid, "map cannot be uncurried",
+ return isl_map_free(map));
+
+ map = isl_map_cow(map);
+ if (!map)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_uncurry(map->p[i]);
+ if (!map->p[i])
+ return isl_map_free(map);
+ }
+
+ map->dim = isl_space_uncurry(map->dim);
+ if (!map->dim)
+ return isl_map_free(map);
+
+ return map;
+}
+
+/* Construct a basic map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff)
+{
+ int k;
+ int pos;
+ isl_local_space *ls;
+ isl_basic_map *bmap;
+
+ if (!aff)
+ return NULL;
+
+ ls = isl_aff_get_local_space(aff);
+ bmap = isl_basic_map_from_local_space(ls);
+ bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ goto error;
+
+ pos = isl_basic_map_offset(bmap, isl_dim_out);
+ isl_seq_cpy(bmap->eq[k], aff->v->el + 1, pos);
+ isl_int_neg(bmap->eq[k][pos], aff->v->el[0]);
+ isl_seq_cpy(bmap->eq[k] + pos + 1, aff->v->el + 1 + pos,
+ aff->v->size - (pos + 1));
+
+ isl_aff_free(aff);
+ bmap = isl_basic_map_finalize(bmap);
+ return bmap;
+error:
+ isl_aff_free(aff);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Construct a map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff)
+{
+ isl_basic_map *bmap;
+
+ bmap = isl_basic_map_from_aff(aff);
+ return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+ __isl_take isl_multi_aff *maff)
+{
+ int i;
+ isl_space *space;
+ isl_basic_map *bmap;
+
+ if (!maff)
+ return NULL;
+
+ if (isl_space_dim(maff->space, isl_dim_out) != maff->n)
+ isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal,
+ "invalid space", goto error);
+
+ space = isl_space_domain(isl_multi_aff_get_space(maff));
+ bmap = isl_basic_map_universe(isl_space_from_domain(space));
+
+ for (i = 0; i < maff->n; ++i) {
+ isl_aff *aff;
+ isl_basic_map *bmap_i;
+
+ aff = isl_aff_copy(maff->p[i]);
+ bmap_i = isl_basic_map_from_aff(aff);
+
+ bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+ }
+
+ bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff));
+
+ isl_multi_aff_free(maff);
+ return bmap;
+error:
+ isl_multi_aff_free(maff);
+ return NULL;
+}
+
+/* Construct a map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff)
+{
+ isl_basic_map *bmap;
+
+ bmap = isl_basic_map_from_multi_aff(maff);
+ return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping a domain in the given space to
+ * to an n-dimensional range, with n the number of elements in the list,
+ * where each coordinate in the range is prescribed by the
+ * corresponding affine expression.
+ * The domains of all affine expressions in the list are assumed to match
+ * domain_dim.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff_list(
+ __isl_take isl_space *domain_dim, __isl_take isl_aff_list *list)
+{
+ int i;
+ isl_space *dim;
+ isl_basic_map *bmap;
+
+ if (!list)
+ return NULL;
+
+ dim = isl_space_from_domain(domain_dim);
+ bmap = isl_basic_map_universe(dim);
+
+ for (i = 0; i < list->n; ++i) {
+ isl_aff *aff;
+ isl_basic_map *bmap_i;
+
+ aff = isl_aff_copy(list->p[i]);
+ bmap_i = isl_basic_map_from_aff(aff);
+
+ bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+ }
+
+ isl_aff_list_free(list);
+ return bmap;
+}
+
+__isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ return isl_map_equate(set, type1, pos1, type2, pos2);
+}
+
+/* Construct a basic map where the given dimensions are equal to each other.
+ */
+static __isl_give isl_basic_map *equator(__isl_take isl_space *space,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *bmap = NULL;
+ int i;
+
+ if (!space)
+ return NULL;
+
+ if (pos1 >= isl_space_dim(space, type1))
+ isl_die(isl_space_get_ctx(space), isl_error_invalid,
+ "index out of bounds", goto error);
+ if (pos2 >= isl_space_dim(space, type2))
+ isl_die(isl_space_get_ctx(space), isl_error_invalid,
+ "index out of bounds", goto error);
+
+ if (type1 == type2 && pos1 == pos2)
+ return isl_basic_map_universe(space);
+
+ bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0);
+ i = isl_basic_map_alloc_equality(bmap);
+ if (i < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+ pos1 += isl_basic_map_offset(bmap, type1);
+ pos2 += isl_basic_map_offset(bmap, type2);
+ isl_int_set_si(bmap->eq[i][pos1], -1);
+ isl_int_set_si(bmap->eq[i][pos2], 1);
+ bmap = isl_basic_map_finalize(bmap);
+ isl_space_free(space);
+ return bmap;
+error:
+ isl_space_free(space);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *eq;
+
+ eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+ bmap = isl_basic_map_intersect(bmap, eq);
+
+ return bmap;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *bmap;
+
+ bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+ map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+ return map;
+}
+
+/* Add a constraint imposing that the given two dimensions have opposite values.
+ */
+__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *bmap = NULL;
+ int i;
+
+ if (!map)
+ return NULL;
+
+ if (pos1 >= isl_map_dim(map, type1))
+ isl_die(map->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+ if (pos2 >= isl_map_dim(map, type2))
+ isl_die(map->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+
+ bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0);
+ i = isl_basic_map_alloc_equality(bmap);
+ if (i < 0)
+ goto error;
+ isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+ pos1 += isl_basic_map_offset(bmap, type1);
+ pos2 += isl_basic_map_offset(bmap, type2);
+ isl_int_set_si(bmap->eq[i][pos1], 1);
+ isl_int_set_si(bmap->eq[i][pos2], 1);
+ bmap = isl_basic_map_finalize(bmap);
+
+ map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+ return map;
+error:
+ isl_basic_map_free(bmap);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Construct a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+static __isl_give isl_constraint *constraint_order_ge(
+ __isl_take isl_space *space, enum isl_dim_type type1, int pos1,
+ enum isl_dim_type type2, int pos2)
+{
+ isl_constraint *c;
+
+ if (!space)
+ return NULL;
+
+ c = isl_inequality_alloc(isl_local_space_from_space(space));
+
+ if (pos1 >= isl_constraint_dim(c, type1))
+ isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+ "index out of bounds", return isl_constraint_free(c));
+ if (pos2 >= isl_constraint_dim(c, type2))
+ isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+ "index out of bounds", return isl_constraint_free(c));
+
+ if (type1 == type2 && pos1 == pos2)
+ return c;
+
+ c = isl_constraint_set_coefficient_si(c, type1, pos1, 1);
+ c = isl_constraint_set_coefficient_si(c, type2, pos2, -1);
+
+ return c;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_constraint *c;
+ isl_space *space;
+
+ if (type1 == type2 && pos1 == pos2)
+ return bmap;
+ space = isl_basic_map_get_space(bmap);
+ c = constraint_order_ge(space, type1, pos1, type2, pos2);
+ bmap = isl_basic_map_add_constraint(bmap, c);
+
+ return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_constraint *c;
+ isl_space *space;
+
+ if (type1 == type2 && pos1 == pos2)
+ return map;
+ space = isl_map_get_space(map);
+ c = constraint_order_ge(space, type1, pos1, type2, pos2);
+ map = isl_map_add_constraint(map, c);
+
+ return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * less than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ return isl_map_order_ge(map, type2, pos2, type1, pos1);
+}
+
+/* Construct a basic map where the value of the first dimension is
+ * greater than that of the second.
+ */
+static __isl_give isl_basic_map *greator(__isl_take isl_space *space,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *bmap = NULL;
+ int i;
+
+ if (!space)
+ return NULL;
+
+ if (pos1 >= isl_space_dim(space, type1))
+ isl_die(isl_space_get_ctx(space), isl_error_invalid,
+ "index out of bounds", goto error);
+ if (pos2 >= isl_space_dim(space, type2))
+ isl_die(isl_space_get_ctx(space), isl_error_invalid,
+ "index out of bounds", goto error);
+
+ if (type1 == type2 && pos1 == pos2)
+ return isl_basic_map_empty(space);
+
+ bmap = isl_basic_map_alloc_space(space, 0, 0, 1);
+ i = isl_basic_map_alloc_inequality(bmap);
+ if (i < 0)
+ return isl_basic_map_free(bmap);
+ isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+ pos1 += isl_basic_map_offset(bmap, type1);
+ pos2 += isl_basic_map_offset(bmap, type2);
+ isl_int_set_si(bmap->ineq[i][pos1], 1);
+ isl_int_set_si(bmap->ineq[i][pos2], -1);
+ isl_int_set_si(bmap->ineq[i][0], -1);
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_space_free(space);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *gt;
+
+ gt = greator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+ bmap = isl_basic_map_intersect(bmap, gt);
+
+ return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ isl_basic_map *bmap;
+
+ bmap = greator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+ map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+ return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * smaller than that of the second.
+ */
+__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+ enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+ return isl_map_order_gt(map, type2, pos2, type1, pos1);
+}
+
+__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap,
+ int pos)
+{
+ isl_aff *div;
+ isl_local_space *ls;
+
+ if (!bmap)
+ return NULL;
+
+ if (!isl_basic_map_divs_known(bmap))
+ isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+ "some divs are unknown", return NULL);
+
+ ls = isl_basic_map_get_local_space(bmap);
+ div = isl_local_space_get_div(ls, pos);
+ isl_local_space_free(ls);
+
+ return div;
+}
+
+__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
+ int pos)
+{
+ return isl_basic_map_get_div(bset, pos);
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "bset".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ * f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ * floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ * floor((a f + d g)/(m d))
+ *
+ * Constraints of the form
+ *
+ * a i + g
+ *
+ * are replaced by
+ *
+ * a f + d g
+ *
+ * We currently require that "subs" is an integral expression.
+ * Handling rational expressions may require us to add stride constraints
+ * as we do in isl_basic_set_preimage_multi_aff.
+ */
+__isl_give isl_basic_set *isl_basic_set_substitute(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+ int i;
+ isl_int v;
+ isl_ctx *ctx;
+
+ if (bset && isl_basic_set_plain_is_empty(bset))
+ return bset;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset || !subs)
+ goto error;
+
+ ctx = isl_basic_set_get_ctx(bset);
+ if (!isl_space_is_equal(bset->dim, subs->ls->dim))
+ isl_die(ctx, isl_error_invalid,
+ "spaces don't match", goto error);
+ if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+ isl_die(ctx, isl_error_unsupported,
+ "cannot handle divs yet", goto error);
+ if (!isl_int_is_one(subs->v->el[0]))
+ isl_die(ctx, isl_error_invalid,
+ "can only substitute integer expressions", goto error);
+
+ pos += isl_basic_set_offset(bset, type);
+
+ isl_int_init(v);
+
+ for (i = 0; i < bset->n_eq; ++i) {
+ if (isl_int_is_zero(bset->eq[i][pos]))
+ continue;
+ isl_int_set(v, bset->eq[i][pos]);
+ isl_int_set_si(bset->eq[i][pos], 0);
+ isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i],
+ v, subs->v->el + 1, subs->v->size - 1);
+ }
+
+ for (i = 0; i < bset->n_ineq; ++i) {
+ if (isl_int_is_zero(bset->ineq[i][pos]))
+ continue;
+ isl_int_set(v, bset->ineq[i][pos]);
+ isl_int_set_si(bset->ineq[i][pos], 0);
+ isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i],
+ v, subs->v->el + 1, subs->v->size - 1);
+ }
+
+ for (i = 0; i < bset->n_div; ++i) {
+ if (isl_int_is_zero(bset->div[i][1 + pos]))
+ continue;
+ isl_int_set(v, bset->div[i][1 + pos]);
+ isl_int_set_si(bset->div[i][1 + pos], 0);
+ isl_seq_combine(bset->div[i] + 1,
+ subs->v->el[0], bset->div[i] + 1,
+ v, subs->v->el + 1, subs->v->size - 1);
+ isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]);
+ }
+
+ isl_int_clear(v);
+
+ bset = isl_basic_set_simplify(bset);
+ return isl_basic_set_finalize(bset);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "set".
+ */
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+ int i;
+
+ if (set && isl_set_plain_is_empty(set))
+ return set;
+
+ set = isl_set_cow(set);
+ if (!set || !subs)
+ goto error;
+
+ for (i = set->n - 1; i >= 0; --i) {
+ set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs);
+ if (remove_if_empty(set, i) < 0)
+ goto error;
+ }
+
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "bmap".
+ * Return -1 if anything is wrong.
+ */
+static int check_basic_map_compatible_range_multi_aff(
+ __isl_keep isl_basic_map *bmap, enum isl_dim_type type,
+ __isl_keep isl_multi_aff *ma)
+{
+ int m;
+ isl_space *ma_space;
+
+ ma_space = isl_multi_aff_get_space(ma);
+
+ m = isl_space_match(bmap->dim, isl_dim_param, ma_space, isl_dim_param);
+ if (m < 0)
+ goto error;
+ if (!m)
+ isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+ "parameters don't match", goto error);
+ m = isl_space_tuple_is_equal(bmap->dim, type, ma_space, isl_dim_out);
+ if (m < 0)
+ goto error;
+ if (!m)
+ isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+ "spaces don't match", goto error);
+
+ isl_space_free(ma_space);
+ return m;
+error:
+ isl_space_free(ma_space);
+ return -1;
+}
+
+/* Copy the divs from "ma" to "bmap", adding zeros for the "n_before"
+ * coefficients before the transformed range of dimensions,
+ * the "n_after" coefficients after the transformed range of dimensions
+ * and the coefficients of the other divs in "bmap".
+ */
+static int set_ma_divs(__isl_keep isl_basic_map *bmap,
+ __isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div)
+{
+ int i;
+ int n_param;
+ int n_set;
+ isl_local_space *ls;
+
+ if (n_div == 0)
+ return 0;
+
+ ls = isl_aff_get_domain_local_space(ma->p[0]);
+ if (!ls)
+ return -1;
+
+ n_param = isl_local_space_dim(ls, isl_dim_param);
+ n_set = isl_local_space_dim(ls, isl_dim_set);
+ for (i = 0; i < n_div; ++i) {
+ int o_bmap = 0, o_ls = 0;
+
+ isl_seq_cpy(bmap->div[i], ls->div->row[i], 1 + 1 + n_param);
+ o_bmap += 1 + 1 + n_param;
+ o_ls += 1 + 1 + n_param;
+ isl_seq_clr(bmap->div[i] + o_bmap, n_before);
+ o_bmap += n_before;
+ isl_seq_cpy(bmap->div[i] + o_bmap,
+ ls->div->row[i] + o_ls, n_set);
+ o_bmap += n_set;
+ o_ls += n_set;
+ isl_seq_clr(bmap->div[i] + o_bmap, n_after);
+ o_bmap += n_after;
+ isl_seq_cpy(bmap->div[i] + o_bmap,
+ ls->div->row[i] + o_ls, n_div);
+ o_bmap += n_div;
+ o_ls += n_div;
+ isl_seq_clr(bmap->div[i] + o_bmap, bmap->n_div - n_div);
+ if (isl_basic_set_add_div_constraints(bmap, i) < 0)
+ goto error;
+ }
+
+ isl_local_space_free(ls);
+ return 0;
+error:
+ isl_local_space_free(ls);
+ return -1;
+}
+
+/* How many stride constraints does "ma" enforce?
+ * That is, how many of the affine expressions have a denominator
+ * different from one?
+ */
+static int multi_aff_strides(__isl_keep isl_multi_aff *ma)
+{
+ int i;
+ int strides = 0;
+
+ for (i = 0; i < ma->n; ++i)
+ if (!isl_int_is_one(ma->p[i]->v->el[0]))
+ strides++;
+
+ return strides;
+}
+
+/* For each affine expression in ma of the form
+ *
+ * x_i = (f_i y + h_i)/m_i
+ *
+ * with m_i different from one, add a constraint to "bmap"
+ * of the form
+ *
+ * f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ */
+static __isl_give isl_basic_map *add_ma_strides(
+ __isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma,
+ int n_before, int n_after)
+{
+ int i, k;
+ int div;
+ int total;
+ int n_param;
+ int n_in;
+ int n_div;
+
+ total = isl_basic_map_total_dim(bmap);
+ n_param = isl_multi_aff_dim(ma, isl_dim_param);
+ n_in = isl_multi_aff_dim(ma, isl_dim_in);
+ n_div = isl_multi_aff_dim(ma, isl_dim_div);
+ for (i = 0; i < ma->n; ++i) {
+ int o_bmap = 0, o_ma = 1;
+
+ if (isl_int_is_one(ma->p[i]->v->el[0]))
+ continue;
+ div = isl_basic_map_alloc_div(bmap);
+ k = isl_basic_map_alloc_equality(bmap);
+ if (div < 0 || k < 0)
+ goto error;
+ isl_int_set_si(bmap->div[div][0], 0);
+ isl_seq_cpy(bmap->eq[k] + o_bmap,
+ ma->p[i]->v->el + o_ma, 1 + n_param);
+ o_bmap += 1 + n_param;
+ o_ma += 1 + n_param;
+ isl_seq_clr(bmap->eq[k] + o_bmap, n_before);
+ o_bmap += n_before;
+ isl_seq_cpy(bmap->eq[k] + o_bmap,
+ ma->p[i]->v->el + o_ma, n_in);
+ o_bmap += n_in;
+ o_ma += n_in;
+ isl_seq_clr(bmap->eq[k] + o_bmap, n_after);
+ o_bmap += n_after;
+ isl_seq_cpy(bmap->eq[k] + o_bmap,
+ ma->p[i]->v->el + o_ma, n_div);
+ o_bmap += n_div;
+ o_ma += n_div;
+ isl_seq_clr(bmap->eq[k] + o_bmap, 1 + total - o_bmap);
+ isl_int_neg(bmap->eq[k][1 + total], ma->p[i]->v->el[0]);
+ total++;
+ }
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Replace the domain or range space (depending on "type) of "space" by "set".
+ */
+static __isl_give isl_space *isl_space_set(__isl_take isl_space *space,
+ enum isl_dim_type type, __isl_take isl_space *set)
+{
+ if (type == isl_dim_in) {
+ space = isl_space_range(space);
+ space = isl_space_map_from_domain_and_range(set, space);
+ } else {
+ space = isl_space_domain(space);
+ space = isl_space_map_from_domain_and_range(space, set);
+ }
+
+ return space;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "bmap" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * If bmap is represented by
+ *
+ * A(p) + S u + B x + T v + C(divs) >= 0,
+ *
+ * where u and x are input and output dimensions if type == isl_dim_out
+ * while x and v are input and output dimensions if type == isl_dim_in,
+ * and ma is represented by
+ *
+ * x = D(p) + F(y) + G(divs')
+ *
+ * then the result is
+ *
+ * A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0
+ *
+ * The divs in the input set are similarly adjusted.
+ * In particular
+ *
+ * floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i)
+ *
+ * becomes
+ *
+ * floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v +
+ * B_i G(divs') + c_i(divs))/n_i)
+ *
+ * If bmap is not a rational map and if F(y) involves any denominators
+ *
+ * x_i = (f_i y + h_i)/m_i
+ *
+ * then additional constraints are added to ensure that we only
+ * map back integer points. That is we enforce
+ *
+ * f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ *
+ * We first copy over the divs from "ma".
+ * Then we add the modified constraints and divs from "bmap".
+ * Finally, we add the stride constraints, if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_multi_aff(
+ __isl_take isl_basic_map *bmap, enum isl_dim_type type,
+ __isl_take isl_multi_aff *ma)
+{
+ int i, k;
+ isl_space *space;
+ isl_basic_map *res = NULL;
+ int n_before, n_after, n_div_bmap, n_div_ma;
+ isl_int f, c1, c2, g;
+ int rational, strides;
+
+ isl_int_init(f);
+ isl_int_init(c1);
+ isl_int_init(c2);
+ isl_int_init(g);
+
+ ma = isl_multi_aff_align_divs(ma);
+ if (!bmap || !ma)
+ goto error;
+ if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0)
+ goto error;
+
+ if (type == isl_dim_in) {
+ n_before = 0;
+ n_after = isl_basic_map_dim(bmap, isl_dim_out);
+ } else {
+ n_before = isl_basic_map_dim(bmap, isl_dim_in);
+ n_after = 0;
+ }
+ n_div_bmap = isl_basic_map_dim(bmap, isl_dim_div);
+ n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+ space = isl_multi_aff_get_domain_space(ma);
+ space = isl_space_set(isl_basic_map_get_space(bmap), type, space);
+ rational = isl_basic_map_is_rational(bmap);
+ strides = rational ? 0 : multi_aff_strides(ma);
+ res = isl_basic_map_alloc_space(space, n_div_ma + n_div_bmap + strides,
+ bmap->n_eq + strides, bmap->n_ineq + 2 * n_div_ma);
+ if (rational)
+ res = isl_basic_map_set_rational(res);
+
+ for (i = 0; i < n_div_ma + n_div_bmap; ++i)
+ if (isl_basic_map_alloc_div(res) < 0)
+ goto error;
+
+ if (set_ma_divs(res, ma, n_before, n_after, n_div_ma) < 0)
+ goto error;
+
+ for (i = 0; i < bmap->n_eq; ++i) {
+ k = isl_basic_map_alloc_equality(res);
+ if (k < 0)
+ goto error;
+ isl_seq_preimage(res->eq[k], bmap->eq[i], ma, n_before,
+ n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+ }
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ k = isl_basic_map_alloc_inequality(res);
+ if (k < 0)
+ goto error;
+ isl_seq_preimage(res->ineq[k], bmap->ineq[i], ma, n_before,
+ n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+ }
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0])) {
+ isl_int_set_si(res->div[n_div_ma + i][0], 0);
+ continue;
+ }
+ isl_seq_preimage(res->div[n_div_ma + i], bmap->div[i], ma,
+ n_before, n_after, n_div_ma, n_div_bmap,
+ f, c1, c2, g, 1);
+ }
+
+ if (strides)
+ res = add_ma_strides(res, ma, n_before, n_after);
+
+ isl_int_clear(f);
+ isl_int_clear(c1);
+ isl_int_clear(c2);
+ isl_int_clear(g);
+ isl_basic_map_free(bmap);
+ isl_multi_aff_free(ma);
+ res = isl_basic_set_simplify(res);
+ return isl_basic_map_finalize(res);
+error:
+ isl_int_clear(f);
+ isl_int_clear(c1);
+ isl_int_clear(c2);
+ isl_int_clear(g);
+ isl_basic_map_free(bmap);
+ isl_multi_aff_free(ma);
+ isl_basic_map_free(res);
+ return NULL;
+}
+
+/* Compute the preimage of "bset" under the function represented by "ma".
+ * In other words, plug in "ma" in "bset". The result is a basic set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
+ __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma)
+{
+ return isl_basic_map_preimage_multi_aff(bset, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff(
+ __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+ return isl_basic_map_preimage_multi_aff(bmap, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff(
+ __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+ return isl_basic_map_preimage_multi_aff(bmap, isl_dim_out, ma);
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "map".
+ * Return -1 if anything is wrong.
+ */
+static int check_map_compatible_range_multi_aff(
+ __isl_keep isl_map *map, enum isl_dim_type type,
+ __isl_keep isl_multi_aff *ma)
+{
+ int m;
+ isl_space *ma_space;
+
+ ma_space = isl_multi_aff_get_space(ma);
+ m = isl_space_tuple_is_equal(map->dim, type, ma_space, isl_dim_out);
+ isl_space_free(ma_space);
+ if (m >= 0 && !m)
+ isl_die(isl_map_get_ctx(map), isl_error_invalid,
+ "spaces don't match", return -1);
+ return m;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map,
+ enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+ int i;
+ isl_space *space;
+
+ map = isl_map_cow(map);
+ ma = isl_multi_aff_align_divs(ma);
+ if (!map || !ma)
+ goto error;
+ if (check_map_compatible_range_multi_aff(map, type, ma) < 0)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_preimage_multi_aff(map->p[i], type,
+ isl_multi_aff_copy(ma));
+ if (!map->p[i])
+ goto error;
+ }
+
+ space = isl_multi_aff_get_domain_space(ma);
+ space = isl_space_set(isl_map_get_space(map), type, space);
+
+ isl_space_free(map->dim);
+ map->dim = space;
+ if (!map->dim)
+ goto error;
+
+ isl_multi_aff_free(ma);
+ if (map->n > 1)
+ ISL_F_CLR(map, ISL_MAP_DISJOINT);
+ ISL_F_CLR(map, ISL_SET_NORMALIZED);
+ return map;
+error:
+ isl_multi_aff_free(ma);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map,
+ enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+ if (!map || !ma)
+ goto error;
+
+ if (isl_space_match(map->dim, isl_dim_param, ma->space, isl_dim_param))
+ return map_preimage_multi_aff(map, type, ma);
+
+ if (!isl_space_has_named_params(map->dim) ||
+ !isl_space_has_named_params(ma->space))
+ isl_die(map->ctx, isl_error_invalid,
+ "unaligned unnamed parameters", goto error);
+ map = isl_map_align_params(map, isl_multi_aff_get_space(ma));
+ ma = isl_multi_aff_align_params(ma, isl_map_get_space(map));
+
+ return map_preimage_multi_aff(map, type, ma);
+error:
+ isl_multi_aff_free(ma);
+ return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "ma".
+ * In other words, plug in "ma" in "set". The result is a set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+ __isl_take isl_multi_aff *ma)
+{
+ return isl_map_preimage_multi_aff(set, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+ __isl_take isl_multi_aff *ma)
+{
+ return isl_map_preimage_multi_aff(map, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map,
+ __isl_take isl_multi_aff *ma)
+{
+ return isl_map_preimage_multi_aff(map, isl_dim_out, ma);
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ *
+ * The parameters of "map" and "pma" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_map_preimage_pw_multi_aff_aligned(
+ __isl_take isl_map *map, enum isl_dim_type type,
+ __isl_take isl_pw_multi_aff *pma)
+{
+ int i;
+ isl_map *res;
+
+ if (!pma)
+ goto error;
+
+ if (pma->n == 0) {
+ isl_pw_multi_aff_free(pma);
+ res = isl_map_empty(isl_map_get_space(map));
+ isl_map_free(map);
+ return res;
+ }
+
+ res = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+ isl_multi_aff_copy(pma->p[0].maff));
+ if (type == isl_dim_in)
+ res = isl_map_intersect_domain(res,
+ isl_map_copy(pma->p[0].set));
+ else
+ res = isl_map_intersect_range(res,
+ isl_map_copy(pma->p[0].set));
+
+ for (i = 1; i < pma->n; ++i) {
+ isl_map *res_i;
+
+ res_i = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+ isl_multi_aff_copy(pma->p[i].maff));
+ if (type == isl_dim_in)
+ res_i = isl_map_intersect_domain(res_i,
+ isl_map_copy(pma->p[i].set));
+ else
+ res_i = isl_map_intersect_range(res_i,
+ isl_map_copy(pma->p[i].set));
+ res = isl_map_union(res, res_i);
+ }
+
+ isl_pw_multi_aff_free(pma);
+ isl_map_free(map);
+ return res;
+error:
+ isl_pw_multi_aff_free(pma);
+ isl_map_free(map);
+ return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_pw_multi_aff(__isl_take isl_map *map,
+ enum isl_dim_type type, __isl_take isl_pw_multi_aff *pma)
+{
+ if (!map || !pma)
+ goto error;
+
+ if (isl_space_match(map->dim, isl_dim_param, pma->dim, isl_dim_param))
+ return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+
+ if (!isl_space_has_named_params(map->dim) ||
+ !isl_space_has_named_params(pma->dim))
+ isl_die(map->ctx, isl_error_invalid,
+ "unaligned unnamed parameters", goto error);
+ map = isl_map_align_params(map, isl_pw_multi_aff_get_space(pma));
+ pma = isl_pw_multi_aff_align_params(pma, isl_map_get_space(map));
+
+ return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+error:
+ isl_pw_multi_aff_free(pma);
+ return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "pma".
+ * In other words, plug in "pma" in "set". The result is a set
+ * that lives in the domain space of "pma".
+ */
+__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set,
+ __isl_take isl_pw_multi_aff *pma)
+{
+ return isl_map_preimage_pw_multi_aff(set, isl_dim_set, pma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the domain of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff(
+ __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+ return isl_map_preimage_pw_multi_aff(map, isl_dim_in, pma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that range space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_range_pw_multi_aff(
+ __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+ return isl_map_preimage_pw_multi_aff(map, isl_dim_out, pma);
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "mpa".
+ *
+ * If the map does not involve any constraints that refer to the
+ * dimensions of the substituted space, then the only possible
+ * effect of "mpa" on the map is to map the space to a different space.
+ * We create a separate isl_multi_aff to effectuate this change
+ * in order to avoid spurious splitting of the map along the pieces
+ * of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_multi_pw_aff(__isl_take isl_map *map,
+ enum isl_dim_type type, __isl_take isl_multi_pw_aff *mpa)
+{
+ int n;
+ isl_pw_multi_aff *pma;
+
+ if (!map || !mpa)
+ goto error;
+
+ n = isl_map_dim(map, type);
+ if (!isl_map_involves_dims(map, type, 0, n)) {
+ isl_space *space;
+ isl_multi_aff *ma;
+
+ space = isl_multi_pw_aff_get_space(mpa);
+ isl_multi_pw_aff_free(mpa);
+ ma = isl_multi_aff_zero(space);
+ return isl_map_preimage_multi_aff(map, type, ma);
+ }
+
+ pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
+ return isl_map_preimage_pw_multi_aff(map, type, pma);
+error:
+ isl_map_free(map);
+ isl_multi_pw_aff_free(mpa);
+ return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff(
+ __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa)
+{
+ return isl_map_preimage_multi_pw_aff(map, isl_dim_in, mpa);
+}
+
+/* Compute the preimage of "set" by the function represented by "mpa".
+ * In other words, plug in "mpa" in "set".
+ */
+__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set,
+ __isl_take isl_multi_pw_aff *mpa)
+{
+ return isl_map_preimage_multi_pw_aff(set, isl_dim_set, mpa);
+}
Added: polly/trunk/lib/External/isl/isl_map_lexopt_templ.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_lexopt_templ.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_lexopt_templ.c (added)
+++ polly/trunk/lib/External/isl/isl_map_lexopt_templ.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2010 INRIA Saclay
+ * Copyright 2012 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ */
+
+/* Function for computing the lexicographic optimum of a map
+ * in the form of either an isl_map or an isl_pw_multi_aff.
+ */
+
+#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX
+#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX)
+
+/* Given a basic map "bmap", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * We first make sure the basic sets in dom are disjoint and then
+ * simply collect the results over each of the basic sets separately.
+ * We could probably improve the efficiency a bit by moving the union
+ * domain down into the parametric integer programming.
+ */
+static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)(
+ __isl_take isl_basic_map *bmap, __isl_take isl_set *dom,
+ __isl_give isl_set **empty, int max)
+{
+ int i;
+ TYPE *res;
+
+ dom = isl_set_make_disjoint(dom);
+ if (!dom)
+ goto error;
+
+ if (isl_set_plain_is_empty(dom)) {
+ isl_space *space = isl_basic_map_get_space(bmap);
+ if (empty)
+ *empty = dom;
+ else
+ isl_set_free(dom);
+ isl_basic_map_free(bmap);
+ return EMPTY(space);
+ }
+
+ res = SF(isl_basic_map_partial_lexopt,SUFFIX)(isl_basic_map_copy(bmap),
+ isl_basic_set_copy(dom->p[0]), empty, max);
+
+ for (i = 1; i < dom->n; ++i) {
+ TYPE *res_i;
+ isl_set *empty_i;
+
+ res_i = SF(isl_basic_map_partial_lexopt,SUFFIX)(
+ isl_basic_map_copy(bmap),
+ isl_basic_set_copy(dom->p[i]), &empty_i, max);
+
+ res = ADD(res, res_i);
+ *empty = isl_set_union_disjoint(*empty, empty_i);
+ }
+
+ isl_set_free(dom);
+ isl_basic_map_free(bmap);
+ return res;
+error:
+ *empty = NULL;
+ isl_set_free(dom);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static __isl_give TYPE *SF(isl_map_partial_lexopt_aligned,SUFFIX)(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty, int max);
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * Align parameters if needed and then call isl_map_partial_lexopt_aligned.
+ */
+static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)(
+ __isl_take isl_map *map, __isl_take isl_set *dom,
+ __isl_give isl_set **empty, int max)
+{
+ if (!map || !dom)
+ goto error;
+ if (isl_space_match(map->dim, isl_dim_param, dom->dim, isl_dim_param))
+ return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom,
+ empty, max);
+ if (!isl_space_has_named_params(map->dim) ||
+ !isl_space_has_named_params(dom->dim))
+ isl_die(map->ctx, isl_error_invalid,
+ "unaligned unnamed parameters", goto error);
+ map = isl_map_align_params(map, isl_map_get_space(dom));
+ dom = isl_map_align_params(dom, isl_map_get_space(map));
+ return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom, empty, max);
+error:
+ if (empty)
+ *empty = NULL;
+ isl_set_free(dom);
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give TYPE *SF(isl_map_lexopt,SUFFIX)(__isl_take isl_map *map, int max)
+{
+ isl_set *dom = NULL;
+ isl_space *dom_space;
+
+ if (!map)
+ goto error;
+ dom_space = isl_space_domain(isl_space_copy(map->dim));
+ dom = isl_set_universe(dom_space);
+ return SF(isl_map_partial_lexopt,SUFFIX)(map, dom, NULL, max);
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+__isl_give TYPE *SF(isl_map_lexmin,SUFFIX)(__isl_take isl_map *map)
+{
+ return SF(isl_map_lexopt,SUFFIX)(map, 0);
+}
+
+__isl_give TYPE *SF(isl_map_lexmax,SUFFIX)(__isl_take isl_map *map)
+{
+ return SF(isl_map_lexopt,SUFFIX)(map, 1);
+}
+
+__isl_give TYPE *SF(isl_set_lexmin,SUFFIX)(__isl_take isl_set *set)
+{
+ return SF(isl_map_lexmin,SUFFIX)(set);
+}
+
+__isl_give TYPE *SF(isl_set_lexmax,SUFFIX)(__isl_take isl_set *set)
+{
+ return SF(isl_map_lexmax,SUFFIX)(set);
+}
Added: polly/trunk/lib/External/isl/isl_map_private.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_private.h?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_private.h (added)
+++ polly/trunk/lib/External/isl/isl_map_private.h Wed Feb 4 14:55:43 2015
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_MAP_PRIVATE_H
+#define ISL_MAP_PRIVATE_H
+
+#define isl_basic_set isl_basic_map
+#define isl_set isl_map
+#define isl_basic_set_list isl_basic_map_list
+#define isl_set_list isl_map_list
+#include <isl/list.h>
+ISL_DECLARE_LIST(basic_map)
+ISL_DECLARE_LIST(map)
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include <isl/vec.h>
+#include <isl_blk.h>
+
+/* A "basic map" is a relation between two sets of variables,
+ * called the "in" and "out" variables.
+ * A "basic set" is a basic map with a zero-dimensional
+ * domain.
+ *
+ * It is implemented as a set with two extra fields:
+ * n_in is the number of in variables
+ * n_out is the number of out variables
+ * n_in + n_out should be equal to set.dim
+ */
+struct isl_basic_map {
+ int ref;
+#define ISL_BASIC_MAP_FINAL (1 << 0)
+#define ISL_BASIC_MAP_EMPTY (1 << 1)
+#define ISL_BASIC_MAP_NO_IMPLICIT (1 << 2)
+#define ISL_BASIC_MAP_NO_REDUNDANT (1 << 3)
+#define ISL_BASIC_MAP_RATIONAL (1 << 4)
+#define ISL_BASIC_MAP_NORMALIZED (1 << 5)
+#define ISL_BASIC_MAP_NORMALIZED_DIVS (1 << 6)
+#define ISL_BASIC_MAP_ALL_EQUALITIES (1 << 7)
+#define ISL_BASIC_SET_FINAL (1 << 0)
+#define ISL_BASIC_SET_EMPTY (1 << 1)
+#define ISL_BASIC_SET_NO_IMPLICIT (1 << 2)
+#define ISL_BASIC_SET_NO_REDUNDANT (1 << 3)
+#define ISL_BASIC_SET_RATIONAL (1 << 4)
+#define ISL_BASIC_SET_NORMALIZED (1 << 5)
+#define ISL_BASIC_SET_NORMALIZED_DIVS (1 << 6)
+#define ISL_BASIC_SET_ALL_EQUALITIES (1 << 7)
+ unsigned flags;
+
+ struct isl_ctx *ctx;
+
+ isl_space *dim;
+ unsigned extra;
+
+ unsigned n_eq;
+ unsigned n_ineq;
+
+ size_t c_size;
+ isl_int **eq;
+ isl_int **ineq;
+
+ unsigned n_div;
+
+ isl_int **div;
+
+ struct isl_vec *sample;
+
+ struct isl_blk block;
+ struct isl_blk block2;
+};
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+/* A "map" is a (possibly disjoint) union of basic maps.
+ * A "set" is a (possibly disjoint) union of basic sets.
+ *
+ * Currently, the isl_set structure is identical to the isl_map structure
+ * and the library depends on this correspondence internally.
+ * However, users should not depend on this correspondence.
+ */
+struct isl_map {
+ int ref;
+#define ISL_MAP_DISJOINT (1 << 0)
+#define ISL_MAP_NORMALIZED (1 << 1)
+#define ISL_SET_DISJOINT (1 << 0)
+#define ISL_SET_NORMALIZED (1 << 1)
+ unsigned flags;
+
+ struct isl_ctx *ctx;
+
+ isl_space *dim;
+
+ int n;
+
+ size_t size;
+ struct isl_basic_map *p[1];
+};
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+ __isl_take isl_reordering *r);
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+ __isl_take isl_reordering *r);
+
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+ enum isl_dim_type type);
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+ __isl_take isl_basic_set *bset, __isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+ __isl_take isl_basic_map *bmap, __isl_take isl_space *dim);
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+ __isl_take isl_space *dim);
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+ enum isl_dim_type type);
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+ enum isl_dim_type type);
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap);
+int isl_map_may_be_set(__isl_keep isl_map *map);
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set);
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+ struct isl_basic_set *bset);
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+ struct isl_basic_set *bset);
+
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+ __isl_take isl_space *dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+ __isl_take isl_space *dim, unsigned extra,
+ unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+ struct isl_basic_set *bset2, unsigned pos);
+
+struct isl_map *isl_map_grow(struct isl_map *map, int n);
+struct isl_set *isl_set_grow(struct isl_set *set, int n);
+
+int isl_basic_set_contains(struct isl_basic_set *bset, struct isl_vec *vec);
+int isl_basic_map_contains(struct isl_basic_map *bmap, struct isl_vec *vec);
+
+__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+ unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+ unsigned flags);
+__isl_give isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+ unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+ unsigned flags);
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap);
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap);
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset);
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_set_alloc_inequality(struct isl_basic_set *bset);
+int isl_basic_map_alloc_inequality(struct isl_basic_map *bmap);
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap);
+int isl_basic_set_alloc_div(struct isl_basic_set *bset);
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n);
+void isl_basic_map_inequality_to_equality(
+ struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_set_drop_equality(struct isl_basic_set *bset, unsigned pos);
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos);
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos);
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+ isl_int *eq);
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+ isl_int *eq);
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+ isl_int *ineq);
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+ isl_int *ineq);
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos);
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap);
+struct isl_set *isl_set_cow(struct isl_set *set);
+struct isl_map *isl_map_cow(struct isl_map *map);
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset);
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b);
+struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap);
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map);
+struct isl_basic_map *isl_basic_map_align_divs(
+ struct isl_basic_map *dst, struct isl_basic_map *src);
+struct isl_basic_set *isl_basic_set_align_divs(
+ struct isl_basic_set *dst, struct isl_basic_set *src);
+__isl_give isl_set *isl_set_align_divs_to_basic_set_list(
+ __isl_take isl_set *set, __isl_keep isl_basic_set_list *list);
+__isl_give isl_basic_set_list *isl_basic_set_list_align_divs_to_basic_set(
+ __isl_take isl_basic_set_list *list, __isl_keep isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+ __isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map);
+struct isl_basic_map *isl_basic_map_gauss(
+ struct isl_basic_map *bmap, int *progress);
+struct isl_basic_set *isl_basic_set_gauss(
+ struct isl_basic_set *bset, int *progress);
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+ __isl_take isl_basic_set *bset);
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+ const __isl_keep isl_basic_map *bmap2);
+int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+ __isl_keep isl_basic_map *bmap2);
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+ struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+ struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_implicit_equalities(
+ struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_map_underlying_set(struct isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+ __isl_take isl_basic_set *bset);
+__isl_give isl_basic_set_list *isl_basic_set_list_underlying_set(
+ __isl_take isl_basic_set_list *list);
+struct isl_set *isl_map_underlying_set(struct isl_map *map);
+struct isl_basic_map *isl_basic_map_overlying_set(struct isl_basic_set *bset,
+ struct isl_basic_map *like);
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving(
+ __isl_take isl_basic_set *bset, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_set *isl_set_drop(struct isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_basic_set *isl_basic_set_drop_dims(
+ struct isl_basic_set *bset, unsigned first, unsigned n);
+struct isl_set *isl_set_drop_dims(
+ struct isl_set *set, unsigned first, unsigned n);
+struct isl_map *isl_map_drop_inputs(
+ struct isl_map *map, unsigned first, unsigned n);
+struct isl_map *isl_map_drop(struct isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+ __isl_take isl_basic_map *bmap, int *progress, int detect_divs);
+
+struct isl_map *isl_map_remove_empty_parts(struct isl_map *map);
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set);
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map);
+
+struct isl_set *isl_set_normalize(struct isl_set *set);
+
+struct isl_set *isl_set_drop_vars(
+ struct isl_set *set, unsigned first, unsigned n);
+
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+ struct isl_basic_map *bmap, unsigned pos, unsigned n);
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+ struct isl_basic_set *bset, unsigned pos, unsigned n);
+
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n);
+
+int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
+ isl_int *c, isl_int *opt_n, isl_int *opt_d);
+
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+ unsigned div, int sign);
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div);
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+ __isl_take isl_basic_map *bmap);
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+ struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+ struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_recession_cone(struct isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_set_rational(struct isl_basic_set *bset);
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set);
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+ __isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map);
+
+int isl_map_has_rational(__isl_keep isl_map *map);
+int isl_set_has_rational(__isl_keep isl_set *set);
+
+struct isl_mat;
+
+struct isl_basic_set *isl_basic_set_preimage(struct isl_basic_set *bset,
+ struct isl_mat *mat);
+struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat);
+
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+ __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+ __isl_take isl_mat *trans);
+
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+ isl_int *facet, isl_int *ridge);
+
+int isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
+ __isl_keep isl_point *point);
+int isl_set_contains_point(__isl_keep isl_set *set, __isl_keep isl_point *point);
+
+int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+ unsigned first, unsigned n, int *signs);
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+ int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+ void *user);
+
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+ unsigned pos, isl_int *div);
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+ unsigned pos, isl_int *div);
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+ isl_int *constraint, unsigned div);
+int isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+ isl_int *constraint, unsigned div);
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+ __isl_take isl_local_space *ls);
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+ __isl_take isl_local_space *ls);
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+ __isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp);
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap);
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset);
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+ __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap));
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+ __isl_take isl_map *map1, __isl_take isl_map *map2,
+ __isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+ __isl_take isl_map *map2));
+int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+ __isl_keep isl_map *map2,
+ int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2));
+
+int isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+ int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+ void *user),
+ void *user);
+int isl_basic_set_foreach_lexopt(__isl_keep isl_basic_set *bset, int max,
+ int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+ void *user),
+ void *user);
+
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+ __isl_take isl_basic_set *context);
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set);
+
+int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap);
+
+int isl_map_is_set(__isl_keep isl_map *map);
+
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+ unsigned dim, isl_int *val);
+
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+ int pos, isl_int *modulo, isl_int *residue);
+int isl_set_dim_residue_class(struct isl_set *set,
+ int pos, isl_int *modulo, isl_int *residue);
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+ enum isl_dim_type type, unsigned pos, isl_int value);
+int isl_map_plain_is_fixed(__isl_keep isl_map *map,
+ enum isl_dim_type type, unsigned pos, isl_int *val);
+
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+ int pos);
+
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+ __isl_keep isl_set *set);
+
+__isl_give isl_map *isl_map_fixed_power(__isl_take isl_map *map, isl_int exp);
+
+int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
+ isl_int max, isl_int *count);
+int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count);
+
+#endif
Added: polly/trunk/lib/External/isl/isl_map_simplify.c
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/External/isl/isl_map_simplify.c?rev=228193&view=auto
==============================================================================
--- polly/trunk/lib/External/isl/isl_map_simplify.c (added)
+++ polly/trunk/lib/External/isl/isl_map_simplify.c Wed Feb 4 14:55:43 2015
@@ -0,0 +1,3257 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2012 Ecole Normale Superieure
+ * Copyright 2014 INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue dâUlm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <strings.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include "isl_equalities.h"
+#include <isl/map.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+static void swap_equality(struct isl_basic_map *bmap, int a, int b)
+{
+ isl_int *t = bmap->eq[a];
+ bmap->eq[a] = bmap->eq[b];
+ bmap->eq[b] = t;
+}
+
+static void swap_inequality(struct isl_basic_map *bmap, int a, int b)
+{
+ if (a != b) {
+ isl_int *t = bmap->ineq[a];
+ bmap->ineq[a] = bmap->ineq[b];
+ bmap->ineq[b] = t;
+ }
+}
+
+static void constraint_drop_vars(isl_int *c, unsigned n, unsigned rem)
+{
+ isl_seq_cpy(c, c + n, rem);
+ isl_seq_clr(c + rem, n);
+}
+
+/* Drop n dimensions starting at first.
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+struct isl_basic_set *isl_basic_set_drop_dims(
+ struct isl_basic_set *bset, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!bset)
+ goto error;
+
+ isl_assert(bset->ctx, first + n <= bset->dim->n_out, goto error);
+
+ if (n == 0 && !isl_space_get_tuple_name(bset->dim, isl_dim_set))
+ return bset;
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ return NULL;
+
+ for (i = 0; i < bset->n_eq; ++i)
+ constraint_drop_vars(bset->eq[i]+1+bset->dim->nparam+first, n,
+ (bset->dim->n_out-first-n)+bset->extra);
+
+ for (i = 0; i < bset->n_ineq; ++i)
+ constraint_drop_vars(bset->ineq[i]+1+bset->dim->nparam+first, n,
+ (bset->dim->n_out-first-n)+bset->extra);
+
+ for (i = 0; i < bset->n_div; ++i)
+ constraint_drop_vars(bset->div[i]+1+1+bset->dim->nparam+first, n,
+ (bset->dim->n_out-first-n)+bset->extra);
+
+ bset->dim = isl_space_drop_outputs(bset->dim, first, n);
+ if (!bset->dim)
+ goto error;
+
+ ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+ bset = isl_basic_set_simplify(bset);
+ return isl_basic_set_finalize(bset);
+error:
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+struct isl_set *isl_set_drop_dims(
+ struct isl_set *set, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!set)
+ goto error;
+
+ isl_assert(set->ctx, first + n <= set->dim->n_out, goto error);
+
+ if (n == 0 && !isl_space_get_tuple_name(set->dim, isl_dim_set))
+ return set;
+ set = isl_set_cow(set);
+ if (!set)
+ goto error;
+ set->dim = isl_space_drop_outputs(set->dim, first, n);
+ if (!set->dim)
+ goto error;
+
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_drop_dims(set->p[i], first, n);
+ if (!set->p[i])
+ goto error;
+ }
+
+ ISL_F_CLR(set, ISL_SET_NORMALIZED);
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+/* Move "n" divs starting at "first" to the end of the list of divs.
+ */
+static struct isl_basic_map *move_divs_last(struct isl_basic_map *bmap,
+ unsigned first, unsigned n)
+{
+ isl_int **div;
+ int i;
+
+ if (first + n == bmap->n_div)
+ return bmap;
+
+ div = isl_alloc_array(bmap->ctx, isl_int *, n);
+ if (!div)
+ goto error;
+ for (i = 0; i < n; ++i)
+ div[i] = bmap->div[first + i];
+ for (i = 0; i < bmap->n_div - first - n; ++i)
+ bmap->div[first + i] = bmap->div[first + n + i];
+ for (i = 0; i < n; ++i)
+ bmap->div[bmap->n_div - n + i] = div[i];
+ free(div);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+/* Drop "n" dimensions of type "type" starting at "first".
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+ unsigned dim;
+ unsigned offset;
+ unsigned left;
+
+ if (!bmap)
+ goto error;
+
+ dim = isl_basic_map_dim(bmap, type);
+ isl_assert(bmap->ctx, first + n <= dim, goto error);
+
+ if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+
+ offset = isl_basic_map_offset(bmap, type) + first;
+ left = isl_basic_map_total_dim(bmap) - (offset - 1) - n;
+ for (i = 0; i < bmap->n_eq; ++i)
+ constraint_drop_vars(bmap->eq[i]+offset, n, left);
+
+ for (i = 0; i < bmap->n_ineq; ++i)
+ constraint_drop_vars(bmap->ineq[i]+offset, n, left);
+
+ for (i = 0; i < bmap->n_div; ++i)
+ constraint_drop_vars(bmap->div[i]+1+offset, n, left);
+
+ if (type == isl_dim_div) {
+ bmap = move_divs_last(bmap, first, n);
+ if (!bmap)
+ goto error;
+ isl_basic_map_free_div(bmap, n);
+ } else
+ bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+ if (!bmap->dim)
+ goto error;
+
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ bmap = isl_basic_map_simplify(bmap);
+ return isl_basic_map_finalize(bmap);
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_basic_set *)isl_basic_map_drop((isl_basic_map *)bset,
+ type, first, n);
+}
+
+struct isl_basic_map *isl_basic_map_drop_inputs(
+ struct isl_basic_map *bmap, unsigned first, unsigned n)
+{
+ return isl_basic_map_drop(bmap, isl_dim_in, first, n);
+}
+
+struct isl_map *isl_map_drop(struct isl_map *map,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ int i;
+
+ if (!map)
+ goto error;
+
+ isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+ if (n == 0 && !isl_space_get_tuple_name(map->dim, type))
+ return map;
+ map = isl_map_cow(map);
+ if (!map)
+ goto error;
+ map->dim = isl_space_drop_dims(map->dim, type, first, n);
+ if (!map->dim)
+ goto error;
+
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_drop(map->p[i], type, first, n);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_set *isl_set_drop(struct isl_set *set,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return (isl_set *)isl_map_drop((isl_map *)set, type, first, n);
+}
+
+struct isl_map *isl_map_drop_inputs(
+ struct isl_map *map, unsigned first, unsigned n)
+{
+ return isl_map_drop(map, isl_dim_in, first, n);
+}
+
+/*
+ * We don't cow, as the div is assumed to be redundant.
+ */
+static struct isl_basic_map *isl_basic_map_drop_div(
+ struct isl_basic_map *bmap, unsigned div)
+{
+ int i;
+ unsigned pos;
+
+ if (!bmap)
+ goto error;
+
+ pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+ isl_assert(bmap->ctx, div < bmap->n_div, goto error);
+
+ for (i = 0; i < bmap->n_eq; ++i)
+ constraint_drop_vars(bmap->eq[i]+pos, 1, bmap->extra-div-1);
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ if (!isl_int_is_zero(bmap->ineq[i][pos])) {
+ isl_basic_map_drop_inequality(bmap, i);
+ --i;
+ continue;
+ }
+ constraint_drop_vars(bmap->ineq[i]+pos, 1, bmap->extra-div-1);
+ }
+
+ for (i = 0; i < bmap->n_div; ++i)
+ constraint_drop_vars(bmap->div[i]+1+pos, 1, bmap->extra-div-1);
+
+ if (div != bmap->n_div - 1) {
+ int j;
+ isl_int *t = bmap->div[div];
+
+ for (j = div; j < bmap->n_div - 1; ++j)
+ bmap->div[j] = bmap->div[j+1];
+
+ bmap->div[bmap->n_div - 1] = t;
+ }
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ isl_basic_map_free_div(bmap, 1);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+ struct isl_basic_map *bmap)
+{
+ int i;
+ isl_int gcd;
+ unsigned total = isl_basic_map_total_dim(bmap);
+
+ if (!bmap)
+ return NULL;
+
+ isl_int_init(gcd);
+ for (i = bmap->n_eq - 1; i >= 0; --i) {
+ isl_seq_gcd(bmap->eq[i]+1, total, &gcd);
+ if (isl_int_is_zero(gcd)) {
+ if (!isl_int_is_zero(bmap->eq[i][0])) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ break;
+ }
+ isl_basic_map_drop_equality(bmap, i);
+ continue;
+ }
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+ isl_int_gcd(gcd, gcd, bmap->eq[i][0]);
+ if (isl_int_is_one(gcd))
+ continue;
+ if (!isl_int_is_divisible_by(bmap->eq[i][0], gcd)) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ break;
+ }
+ isl_seq_scale_down(bmap->eq[i], bmap->eq[i], gcd, 1+total);
+ }
+
+ for (i = bmap->n_ineq - 1; i >= 0; --i) {
+ isl_seq_gcd(bmap->ineq[i]+1, total, &gcd);
+ if (isl_int_is_zero(gcd)) {
+ if (isl_int_is_neg(bmap->ineq[i][0])) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ break;
+ }
+ isl_basic_map_drop_inequality(bmap, i);
+ continue;
+ }
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+ isl_int_gcd(gcd, gcd, bmap->ineq[i][0]);
+ if (isl_int_is_one(gcd))
+ continue;
+ isl_int_fdiv_q(bmap->ineq[i][0], bmap->ineq[i][0], gcd);
+ isl_seq_scale_down(bmap->ineq[i]+1, bmap->ineq[i]+1, gcd, total);
+ }
+ isl_int_clear(gcd);
+
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+ struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)isl_basic_map_normalize_constraints(
+ (struct isl_basic_map *)bset);
+}
+
+/* Remove any common factor in numerator and denominator of the div expression,
+ * not taking into account the constant term.
+ * That is, if the div is of the form
+ *
+ * floor((a + m f(x))/(m d))
+ *
+ * then replace it by
+ *
+ * floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static void normalize_div_expression(__isl_keep isl_basic_map *bmap, int div)
+{
+ unsigned total = isl_basic_map_total_dim(bmap);
+ isl_ctx *ctx = bmap->ctx;
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return;
+ isl_seq_gcd(bmap->div[div] + 2, total, &ctx->normalize_gcd);
+ isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, bmap->div[div][0]);
+ if (isl_int_is_one(ctx->normalize_gcd))
+ return;
+ isl_int_fdiv_q(bmap->div[div][1], bmap->div[div][1],
+ ctx->normalize_gcd);
+ isl_int_divexact(bmap->div[div][0], bmap->div[div][0],
+ ctx->normalize_gcd);
+ isl_seq_scale_down(bmap->div[div] + 2, bmap->div[div] + 2,
+ ctx->normalize_gcd, total);
+}
+
+/* Remove any common factor in numerator and denominator of a div expression,
+ * not taking into account the constant term.
+ * That is, look for any div of the form
+ *
+ * floor((a + m f(x))/(m d))
+ *
+ * and replace it by
+ *
+ * floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static __isl_give isl_basic_map *normalize_div_expressions(
+ __isl_take isl_basic_map *bmap)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+ if (bmap->n_div == 0)
+ return bmap;
+
+ for (i = 0; i < bmap->n_div; ++i)
+ normalize_div_expression(bmap, i);
+
+ return bmap;
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static void eliminate_var_using_equality(struct isl_basic_map *bmap,
+ unsigned pos, isl_int *eq, int keep_divs, int *progress)
+{
+ unsigned total;
+ unsigned space_total;
+ int k;
+ int last_div;
+
+ total = isl_basic_map_total_dim(bmap);
+ space_total = isl_space_dim(bmap->dim, isl_dim_all);
+ last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+ for (k = 0; k < bmap->n_eq; ++k) {
+ if (bmap->eq[k] == eq)
+ continue;
+ if (isl_int_is_zero(bmap->eq[k][1+pos]))
+ continue;
+ if (progress)
+ *progress = 1;
+ isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL);
+ isl_seq_normalize(bmap->ctx, bmap->eq[k], 1 + total);
+ }
+
+ for (k = 0; k < bmap->n_ineq; ++k) {
+ if (isl_int_is_zero(bmap->ineq[k][1+pos]))
+ continue;
+ if (progress)
+ *progress = 1;
+ isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL);
+ isl_seq_normalize(bmap->ctx, bmap->ineq[k], 1 + total);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ }
+
+ for (k = 0; k < bmap->n_div; ++k) {
+ if (isl_int_is_zero(bmap->div[k][0]))
+ continue;
+ if (isl_int_is_zero(bmap->div[k][1+1+pos]))
+ continue;
+ if (progress)
+ *progress = 1;
+ /* We need to be careful about circular definitions,
+ * so for now we just remove the definition of div k
+ * if the equality contains any divs.
+ * If keep_divs is set, then the divs have been ordered
+ * and we can keep the definition as long as the result
+ * is still ordered.
+ */
+ if (last_div == -1 || (keep_divs && last_div < k)) {
+ isl_seq_elim(bmap->div[k]+1, eq,
+ 1+pos, 1+total, &bmap->div[k][0]);
+ normalize_div_expression(bmap, k);
+ } else
+ isl_seq_clr(bmap->div[k], 1 + total);
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ }
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static void eliminate_div(struct isl_basic_map *bmap, isl_int *eq,
+ unsigned div, int keep_divs)
+{
+ unsigned pos = isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+ eliminate_var_using_equality(bmap, pos, eq, keep_divs, NULL);
+
+ isl_basic_map_drop_div(bmap, div);
+}
+
+/* Check if elimination of div "div" using equality "eq" would not
+ * result in a div depending on a later div.
+ */
+static int ok_to_eliminate_div(struct isl_basic_map *bmap, isl_int *eq,
+ unsigned div)
+{
+ int k;
+ int last_div;
+ unsigned space_total = isl_space_dim(bmap->dim, isl_dim_all);
+ unsigned pos = space_total + div;
+
+ last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+ if (last_div < 0 || last_div <= div)
+ return 1;
+
+ for (k = 0; k <= last_div; ++k) {
+ if (isl_int_is_zero(bmap->div[k][0]))
+ return 1;
+ if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos]))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Elimininate divs based on equalities
+ */
+static struct isl_basic_map *eliminate_divs_eq(
+ struct isl_basic_map *bmap, int *progress)
+{
+ int d;
+ int i;
+ int modified = 0;
+ unsigned off;
+
+ bmap = isl_basic_map_order_divs(bmap);
+
+ if (!bmap)
+ return NULL;
+
+ off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (d = bmap->n_div - 1; d >= 0 ; --d) {
+ for (i = 0; i < bmap->n_eq; ++i) {
+ if (!isl_int_is_one(bmap->eq[i][off + d]) &&
+ !isl_int_is_negone(bmap->eq[i][off + d]))
+ continue;
+ if (!ok_to_eliminate_div(bmap, bmap->eq[i], d))
+ continue;
+ modified = 1;
+ *progress = 1;
+ eliminate_div(bmap, bmap->eq[i], d, 1);
+ isl_basic_map_drop_equality(bmap, i);
+ break;
+ }
+ }
+ if (modified)
+ return eliminate_divs_eq(bmap, progress);
+ return bmap;
+}
+
+/* Elimininate divs based on inequalities
+ */
+static struct isl_basic_map *eliminate_divs_ineq(
+ struct isl_basic_map *bmap, int *progress)
+{
+ int d;
+ int i;
+ unsigned off;
+ struct isl_ctx *ctx;
+
+ if (!bmap)
+ return NULL;
+
+ ctx = bmap->ctx;
+ off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (d = bmap->n_div - 1; d >= 0 ; --d) {
+ for (i = 0; i < bmap->n_eq; ++i)
+ if (!isl_int_is_zero(bmap->eq[i][off + d]))
+ break;
+ if (i < bmap->n_eq)
+ continue;
+ for (i = 0; i < bmap->n_ineq; ++i)
+ if (isl_int_abs_gt(bmap->ineq[i][off + d], ctx->one))
+ break;
+ if (i < bmap->n_ineq)
+ continue;
+ *progress = 1;
+ bmap = isl_basic_map_eliminate_vars(bmap, (off-1)+d, 1);
+ if (!bmap || ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+ break;
+ bmap = isl_basic_map_drop_div(bmap, d);
+ if (!bmap)
+ break;
+ }
+ return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_gauss(
+ struct isl_basic_map *bmap, int *progress)
+{
+ int k;
+ int done;
+ int last_var;
+ unsigned total_var;
+ unsigned total;
+
+ bmap = isl_basic_map_order_divs(bmap);
+
+ if (!bmap)
+ return NULL;
+
+ total = isl_basic_map_total_dim(bmap);
+ total_var = total - bmap->n_div;
+
+ last_var = total - 1;
+ for (done = 0; done < bmap->n_eq; ++done) {
+ for (; last_var >= 0; --last_var) {
+ for (k = done; k < bmap->n_eq; ++k)
+ if (!isl_int_is_zero(bmap->eq[k][1+last_var]))
+ break;
+ if (k < bmap->n_eq)
+ break;
+ }
+ if (last_var < 0)
+ break;
+ if (k != done)
+ swap_equality(bmap, k, done);
+ if (isl_int_is_neg(bmap->eq[done][1+last_var]))
+ isl_seq_neg(bmap->eq[done], bmap->eq[done], 1+total);
+
+ eliminate_var_using_equality(bmap, last_var, bmap->eq[done], 1,
+ progress);
+
+ if (last_var >= total_var &&
+ isl_int_is_zero(bmap->div[last_var - total_var][0])) {
+ unsigned div = last_var - total_var;
+ isl_seq_neg(bmap->div[div]+1, bmap->eq[done], 1+total);
+ isl_int_set_si(bmap->div[div][1+1+last_var], 0);
+ isl_int_set(bmap->div[div][0],
+ bmap->eq[done][1+last_var]);
+ if (progress)
+ *progress = 1;
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ }
+ }
+ if (done == bmap->n_eq)
+ return bmap;
+ for (k = done; k < bmap->n_eq; ++k) {
+ if (isl_int_is_zero(bmap->eq[k][0]))
+ continue;
+ return isl_basic_map_set_to_empty(bmap);
+ }
+ isl_basic_map_free_equality(bmap, bmap->n_eq-done);
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_gauss(
+ struct isl_basic_set *bset, int *progress)
+{
+ return (struct isl_basic_set*)isl_basic_map_gauss(
+ (struct isl_basic_map *)bset, progress);
+}
+
+
+static unsigned int round_up(unsigned int v)
+{
+ int old_v = v;
+
+ while (v) {
+ old_v = v;
+ v ^= v & -v;
+ }
+ return old_v << 1;
+}
+
+static int hash_index(isl_int ***index, unsigned int size, int bits,
+ struct isl_basic_map *bmap, int k)
+{
+ int h;
+ unsigned total = isl_basic_map_total_dim(bmap);
+ uint32_t hash = isl_seq_get_hash_bits(bmap->ineq[k]+1, total, bits);
+ for (h = hash; index[h]; h = (h+1) % size)
+ if (&bmap->ineq[k] != index[h] &&
+ isl_seq_eq(bmap->ineq[k]+1, index[h][0]+1, total))
+ break;
+ return h;
+}
+
+static int set_hash_index(isl_int ***index, unsigned int size, int bits,
+ struct isl_basic_set *bset, int k)
+{
+ return hash_index(index, size, bits, (struct isl_basic_map *)bset, k);
+}
+
+/* If we can eliminate more than one div, then we need to make
+ * sure we do it from last div to first div, in order not to
+ * change the position of the other divs that still need to
+ * be removed.
+ */
+static struct isl_basic_map *remove_duplicate_divs(
+ struct isl_basic_map *bmap, int *progress)
+{
+ unsigned int size;
+ int *index;
+ int *elim_for;
+ int k, l, h;
+ int bits;
+ struct isl_blk eq;
+ unsigned total_var;
+ unsigned total;
+ struct isl_ctx *ctx;
+
+ bmap = isl_basic_map_order_divs(bmap);
+ if (!bmap || bmap->n_div <= 1)
+ return bmap;
+
+ total_var = isl_space_dim(bmap->dim, isl_dim_all);
+ total = total_var + bmap->n_div;
+
+ ctx = bmap->ctx;
+ for (k = bmap->n_div - 1; k >= 0; --k)
+ if (!isl_int_is_zero(bmap->div[k][0]))
+ break;
+ if (k <= 0)
+ return bmap;
+
+ elim_for = isl_calloc_array(ctx, int, bmap->n_div);
+ size = round_up(4 * bmap->n_div / 3 - 1);
+ bits = ffs(size) - 1;
+ index = isl_calloc_array(ctx, int, size);
+ if (!index)
+ return bmap;
+ eq = isl_blk_alloc(ctx, 1+total);
+ if (isl_blk_is_error(eq))
+ goto out;
+
+ isl_seq_clr(eq.data, 1+total);
+ index[isl_seq_get_hash_bits(bmap->div[k], 2+total, bits)] = k + 1;
+ for (--k; k >= 0; --k) {
+ uint32_t hash;
+
+ if (isl_int_is_zero(bmap->div[k][0]))
+ continue;
+
+ hash = isl_seq_get_hash_bits(bmap->div[k], 2+total, bits);
+ for (h = hash; index[h]; h = (h+1) % size)
+ if (isl_seq_eq(bmap->div[k],
+ bmap->div[index[h]-1], 2+total))
+ break;
+ if (index[h]) {
+ *progress = 1;
+ l = index[h] - 1;
+ elim_for[l] = k + 1;
+ }
+ index[h] = k+1;
+ }
+ for (l = bmap->n_div - 1; l >= 0; --l) {
+ if (!elim_for[l])
+ continue;
+ k = elim_for[l] - 1;
+ isl_int_set_si(eq.data[1+total_var+k], -1);
+ isl_int_set_si(eq.data[1+total_var+l], 1);
+ eliminate_div(bmap, eq.data, l, 1);
+ isl_int_set_si(eq.data[1+total_var+k], 0);
+ isl_int_set_si(eq.data[1+total_var+l], 0);
+ }
+
+ isl_blk_free(ctx, eq);
+out:
+ free(index);
+ free(elim_for);
+ return bmap;
+}
+
+static int n_pure_div_eq(struct isl_basic_map *bmap)
+{
+ int i, j;
+ unsigned total;
+
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+ for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) {
+ while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+ --j;
+ if (j < 0)
+ break;
+ if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1)
+ return 0;
+ }
+ return i;
+}
+
+/* Normalize divs that appear in equalities.
+ *
+ * In particular, we assume that bmap contains some equalities
+ * of the form
+ *
+ * a x = m * e_i
+ *
+ * and we want to replace the set of e_i by a minimal set and
+ * such that the new e_i have a canonical representation in terms
+ * of the vector x.
+ * If any of the equalities involves more than one divs, then
+ * we currently simply bail out.
+ *
+ * Let us first additionally assume that all equalities involve
+ * a div. The equalities then express modulo constraints on the
+ * remaining variables and we can use "parameter compression"
+ * to find a minimal set of constraints. The result is a transformation
+ *
+ * x = T(x') = x_0 + G x'
+ *
+ * with G a lower-triangular matrix with all elements below the diagonal
+ * non-negative and smaller than the diagonal element on the same row.
+ * We first normalize x_0 by making the same property hold in the affine
+ * T matrix.
+ * The rows i of G with a 1 on the diagonal do not impose any modulo
+ * constraint and simply express x_i = x'_i.
+ * For each of the remaining rows i, we introduce a div and a corresponding
+ * equality. In particular
+ *
+ * g_ii e_j = x_i - g_i(x')
+ *
+ * where each x'_k is replaced either by x_k (if g_kk = 1) or the
+ * corresponding div (if g_kk != 1).
+ *
+ * If there are any equalities not involving any div, then we
+ * first apply a variable compression on the variables x:
+ *
+ * x = C x'' x'' = C_2 x
+ *
+ * and perform the above parameter compression on A C instead of on A.
+ * The resulting compression is then of the form
+ *
+ * x'' = T(x') = x_0 + G x'
+ *
+ * and in constructing the new divs and the corresponding equalities,
+ * we have to replace each x'', i.e., the x'_k with (g_kk = 1),
+ * by the corresponding row from C_2.
+ */
+static struct isl_basic_map *normalize_divs(
+ struct isl_basic_map *bmap, int *progress)
+{
+ int i, j, k;
+ int total;
+ int div_eq;
+ struct isl_mat *B;
+ struct isl_vec *d;
+ struct isl_mat *T = NULL;
+ struct isl_mat *C = NULL;
+ struct isl_mat *C2 = NULL;
+ isl_int v;
+ int *pos;
+ int dropped, needed;
+
+ if (!bmap)
+ return NULL;
+
+ if (bmap->n_div == 0)
+ return bmap;
+
+ if (bmap->n_eq == 0)
+ return bmap;
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS))
+ return bmap;
+
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+ div_eq = n_pure_div_eq(bmap);
+ if (div_eq == 0)
+ return bmap;
+
+ if (div_eq < bmap->n_eq) {
+ B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, div_eq,
+ bmap->n_eq - div_eq, 0, 1 + total);
+ C = isl_mat_variable_compression(B, &C2);
+ if (!C || !C2)
+ goto error;
+ if (C->n_col == 0) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ isl_mat_free(C);
+ isl_mat_free(C2);
+ goto done;
+ }
+ }
+
+ d = isl_vec_alloc(bmap->ctx, div_eq);
+ if (!d)
+ goto error;
+ for (i = 0, j = bmap->n_div-1; i < div_eq; ++i) {
+ while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+ --j;
+ isl_int_set(d->block.data[i], bmap->eq[i][1 + total + j]);
+ }
+ B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total);
+
+ if (C) {
+ B = isl_mat_product(B, C);
+ C = NULL;
+ }
+
+ T = isl_mat_parameter_compression(B, d);
+ if (!T)
+ goto error;
+ if (T->n_col == 0) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ isl_mat_free(C2);
+ isl_mat_free(T);
+ goto done;
+ }
+ isl_int_init(v);
+ for (i = 0; i < T->n_row - 1; ++i) {
+ isl_int_fdiv_q(v, T->row[1 + i][0], T->row[1 + i][1 + i]);
+ if (isl_int_is_zero(v))
+ continue;
+ isl_mat_col_submul(T, 0, v, 1 + i);
+ }
+ isl_int_clear(v);
+ pos = isl_alloc_array(bmap->ctx, int, T->n_row);
+ if (!pos)
+ goto error;
+ /* We have to be careful because dropping equalities may reorder them */
+ dropped = 0;
+ for (j = bmap->n_div - 1; j >= 0; --j) {
+ for (i = 0; i < bmap->n_eq; ++i)
+ if (!isl_int_is_zero(bmap->eq[i][1 + total + j]))
+ break;
+ if (i < bmap->n_eq) {
+ bmap = isl_basic_map_drop_div(bmap, j);
+ isl_basic_map_drop_equality(bmap, i);
+ ++dropped;
+ }
+ }
+ pos[0] = 0;
+ needed = 0;
+ for (i = 1; i < T->n_row; ++i) {
+ if (isl_int_is_one(T->row[i][i]))
+ pos[i] = i;
+ else
+ needed++;
+ }
+ if (needed > dropped) {
+ bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+ needed, needed, 0);
+ if (!bmap)
+ goto error;
+ }
+ for (i = 1; i < T->n_row; ++i) {
+ if (isl_int_is_one(T->row[i][i]))
+ continue;
+ k = isl_basic_map_alloc_div(bmap);
+ pos[i] = 1 + total + k;
+ isl_seq_clr(bmap->div[k] + 1, 1 + total + bmap->n_div);
+ isl_int_set(bmap->div[k][0], T->row[i][i]);
+ if (C2)
+ isl_seq_cpy(bmap->div[k] + 1, C2->row[i], 1 + total);
+ else
+ isl_int_set_si(bmap->div[k][1 + i], 1);
+ for (j = 0; j < i; ++j) {
+ if (isl_int_is_zero(T->row[i][j]))
+ continue;
+ if (pos[j] < T->n_row && C2)
+ isl_seq_submul(bmap->div[k] + 1, T->row[i][j],
+ C2->row[pos[j]], 1 + total);
+ else
+ isl_int_neg(bmap->div[k][1 + pos[j]],
+ T->row[i][j]);
+ }
+ j = isl_basic_map_alloc_equality(bmap);
+ isl_seq_neg(bmap->eq[j], bmap->div[k]+1, 1+total+bmap->n_div);
+ isl_int_set(bmap->eq[j][pos[i]], bmap->div[k][0]);
+ }
+ free(pos);
+ isl_mat_free(C2);
+ isl_mat_free(T);
+
+ if (progress)
+ *progress = 1;
+done:
+ ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+
+ return bmap;
+error:
+ isl_mat_free(C);
+ isl_mat_free(C2);
+ isl_mat_free(T);
+ return bmap;
+}
+
+static struct isl_basic_map *set_div_from_lower_bound(
+ struct isl_basic_map *bmap, int div, int ineq)
+{
+ unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div);
+ isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]);
+ isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]);
+ isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+ isl_int_set_si(bmap->div[div][1 + total + div], 0);
+
+ return bmap;
+}
+
+/* Check whether it is ok to define a div based on an inequality.
+ * To avoid the introduction of circular definitions of divs, we
+ * do not allow such a definition if the resulting expression would refer to
+ * any other undefined divs or if any known div is defined in
+ * terms of the unknown div.
+ */
+static int ok_to_set_div_from_bound(struct isl_basic_map *bmap,
+ int div, int ineq)
+{
+ int j;
+ unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ /* Not defined in terms of unknown divs */
+ for (j = 0; j < bmap->n_div; ++j) {
+ if (div == j)
+ continue;
+ if (isl_int_is_zero(bmap->ineq[ineq][total + j]))
+ continue;
+ if (isl_int_is_zero(bmap->div[j][0]))
+ return 0;
+ }
+
+ /* No other div defined in terms of this one => avoid loops */
+ for (j = 0; j < bmap->n_div; ++j) {
+ if (div == j)
+ continue;
+ if (isl_int_is_zero(bmap->div[j][0]))
+ continue;
+ if (!isl_int_is_zero(bmap->div[j][1 + total + div]))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Would an expression for div "div" based on inequality "ineq" of "bmap"
+ * be a better expression than the current one?
+ *
+ * If we do not have any expression yet, then any expression would be better.
+ * Otherwise we check if the last variable involved in the inequality
+ * (disregarding the div that it would define) is in an earlier position
+ * than the last variable involved in the current div expression.
+ */
+static int better_div_constraint(__isl_keep isl_basic_map *bmap,
+ int div, int ineq)
+{
+ unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+ int last_div;
+ int last_ineq;
+
+ if (isl_int_is_zero(bmap->div[div][0]))
+ return 1;
+
+ if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1,
+ bmap->n_div - (div + 1)) >= 0)
+ return 0;
+
+ last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div);
+ last_div = isl_seq_last_non_zero(bmap->div[div] + 1,
+ total + bmap->n_div);
+
+ return last_ineq < last_div;
+}
+
+/* Given two constraints "k" and "l" that are opposite to each other,
+ * except for the constant term, check if we can use them
+ * to obtain an expression for one of the hitherto unknown divs or
+ * a "better" expression for a div for which we already have an expression.
+ * "sum" is the sum of the constant terms of the constraints.
+ * If this sum is strictly smaller than the coefficient of one
+ * of the divs, then this pair can be used define the div.
+ * To avoid the introduction of circular definitions of divs, we
+ * do not use the pair if the resulting expression would refer to
+ * any other undefined divs or if any known div is defined in
+ * terms of the unknown div.
+ */
+static struct isl_basic_map *check_for_div_constraints(
+ struct isl_basic_map *bmap, int k, int l, isl_int sum, int *progress)
+{
+ int i;
+ unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->ineq[k][total + i]))
+ continue;
+ if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
+ continue;
+ if (!better_div_constraint(bmap, i, k))
+ continue;
+ if (!ok_to_set_div_from_bound(bmap, i, k))
+ break;
+ if (isl_int_is_pos(bmap->ineq[k][total + i]))
+ bmap = set_div_from_lower_bound(bmap, i, k);
+ else
+ bmap = set_div_from_lower_bound(bmap, i, l);
+ if (progress)
+ *progress = 1;
+ break;
+ }
+ return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+ __isl_take isl_basic_map *bmap, int *progress, int detect_divs)
+{
+ unsigned int size;
+ isl_int ***index;
+ int k, l, h;
+ int bits;
+ unsigned total = isl_basic_map_total_dim(bmap);
+ isl_int sum;
+ isl_ctx *ctx;
+
+ if (!bmap || bmap->n_ineq <= 1)
+ return bmap;
+
+ size = round_up(4 * (bmap->n_ineq+1) / 3 - 1);
+ bits = ffs(size) - 1;
+ ctx = isl_basic_map_get_ctx(bmap);
+ index = isl_calloc_array(ctx, isl_int **, size);
+ if (!index)
+ return bmap;
+
+ index[isl_seq_get_hash_bits(bmap->ineq[0]+1, total, bits)] = &bmap->ineq[0];
+ for (k = 1; k < bmap->n_ineq; ++k) {
+ h = hash_index(index, size, bits, bmap, k);
+ if (!index[h]) {
+ index[h] = &bmap->ineq[k];
+ continue;
+ }
+ if (progress)
+ *progress = 1;
+ l = index[h] - &bmap->ineq[0];
+ if (isl_int_lt(bmap->ineq[k][0], bmap->ineq[l][0]))
+ swap_inequality(bmap, k, l);
+ isl_basic_map_drop_inequality(bmap, k);
+ --k;
+ }
+ isl_int_init(sum);
+ for (k = 0; k < bmap->n_ineq-1; ++k) {
+ isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+ h = hash_index(index, size, bits, bmap, k);
+ isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+ if (!index[h])
+ continue;
+ l = index[h] - &bmap->ineq[0];
+ isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]);
+ if (isl_int_is_pos(sum)) {
+ if (detect_divs)
+ bmap = check_for_div_constraints(bmap, k, l,
+ sum, progress);
+ continue;
+ }
+ if (isl_int_is_zero(sum)) {
+ /* We need to break out of the loop after these
+ * changes since the contents of the hash
+ * will no longer be valid.
+ * Plus, we probably we want to regauss first.
+ */
+ if (progress)
+ *progress = 1;
+ isl_basic_map_drop_inequality(bmap, l);
+ isl_basic_map_inequality_to_equality(bmap, k);
+ } else
+ bmap = isl_basic_map_set_to_empty(bmap);
+ break;
+ }
+ isl_int_clear(sum);
+
+ free(index);
+ return bmap;
+}
+
+
+/* Eliminate knowns divs from constraints where they appear with
+ * a (positive or negative) unit coefficient.
+ *
+ * That is, replace
+ *
+ * floor(e/m) + f >= 0
+ *
+ * by
+ *
+ * e + m f >= 0
+ *
+ * and
+ *
+ * -floor(e/m) + f >= 0
+ *
+ * by
+ *
+ * -e + m f + m - 1 >= 0
+ *
+ * The first conversion is valid because floor(e/m) >= -f is equivalent
+ * to e/m >= -f because -f is an integral expression.
+ * The second conversion follows from the fact that
+ *
+ * -floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m)
+ *
+ *
+ * Note that one of the div constraints may have been eliminated
+ * due to being redundant with respect to the constraint that is
+ * being modified by this function. The modified constraint may
+ * no longer imply this div constraint, so we add it back to make
+ * sure we do not lose any information.
+ *
+ * We skip integral divs, i.e., those with denominator 1, as we would
+ * risk eliminating the div from the div constraints. We do not need
+ * to handle those divs here anyway since the div constraints will turn
+ * out to form an equality and this equality can then be use to eliminate
+ * the div from all constraints.
+ */
+static __isl_give isl_basic_map *eliminate_unit_divs(
+ __isl_take isl_basic_map *bmap, int *progress)
+{
+ int i, j;
+ isl_ctx *ctx;
+ unsigned total;
+
+ if (!bmap)
+ return NULL;
+
+ ctx = isl_basic_map_get_ctx(bmap);
+ total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (isl_int_is_one(bmap->div[i][0]))
+ continue;
+ for (j = 0; j < bmap->n_ineq; ++j) {
+ int s;
+
+ if (!isl_int_is_one(bmap->ineq[j][total + i]) &&
+ !isl_int_is_negone(bmap->ineq[j][total + i]))
+ continue;
+
+ *progress = 1;
+
+ s = isl_int_sgn(bmap->ineq[j][total + i]);
+ isl_int_set_si(bmap->ineq[j][total + i], 0);
+ if (s < 0)
+ isl_seq_combine(bmap->ineq[j],
+ ctx->negone, bmap->div[i] + 1,
+ bmap->div[i][0], bmap->ineq[j],
+ total + bmap->n_div);
+ else
+ isl_seq_combine(bmap->ineq[j],
+ ctx->one, bmap->div[i] + 1,
+ bmap->div[i][0], bmap->ineq[j],
+ total + bmap->n_div);
+ if (s < 0) {
+ isl_int_add(bmap->ineq[j][0],
+ bmap->ineq[j][0], bmap->div[i][0]);
+ isl_int_sub_ui(bmap->ineq[j][0],
+ bmap->ineq[j][0], 1);
+ }
+
+ bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+ if (isl_basic_map_add_div_constraint(bmap, i, s) < 0)
+ return isl_basic_map_free(bmap);
+ }
+ }
+
+ return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap)
+{
+ int progress = 1;
+ if (!bmap)
+ return NULL;
+ while (progress) {
+ progress = 0;
+ if (!bmap)
+ break;
+ if (isl_basic_map_plain_is_empty(bmap))
+ break;
+ bmap = isl_basic_map_normalize_constraints(bmap);
+ bmap = normalize_div_expressions(bmap);
+ bmap = remove_duplicate_divs(bmap, &progress);
+ bmap = eliminate_unit_divs(bmap, &progress);
+ bmap = eliminate_divs_eq(bmap, &progress);
+ bmap = eliminate_divs_ineq(bmap, &progress);
+ bmap = isl_basic_map_gauss(bmap, &progress);
+ /* requires equalities in normal form */
+ bmap = normalize_divs(bmap, &progress);
+ bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+ &progress, 1);
+ }
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_simplify((struct isl_basic_map *)bset);
+}
+
+
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+ isl_int *constraint, unsigned div)
+{
+ unsigned pos;
+
+ if (!bmap)
+ return -1;
+
+ pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+ if (isl_int_eq(constraint[pos], bmap->div[div][0])) {
+ int neg;
+ isl_int_sub(bmap->div[div][1],
+ bmap->div[div][1], bmap->div[div][0]);
+ isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1);
+ neg = isl_seq_is_neg(constraint, bmap->div[div]+1, pos);
+ isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+ isl_int_add(bmap->div[div][1],
+ bmap->div[div][1], bmap->div[div][0]);
+ if (!neg)
+ return 0;
+ if (isl_seq_first_non_zero(constraint+pos+1,
+ bmap->n_div-div-1) != -1)
+ return 0;
+ } else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) {
+ if (!isl_seq_eq(constraint, bmap->div[div]+1, pos))
+ return 0;
+ if (isl_seq_first_non_zero(constraint+pos+1,
+ bmap->n_div-div-1) != -1)
+ return 0;
+ } else
+ return 0;
+
+ return 1;
+}
+
+int isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+ isl_int *constraint, unsigned div)
+{
+ return isl_basic_map_is_div_constraint(bset, constraint, div);
+}
+
+
+/* If the only constraints a div d=floor(f/m)
+ * appears in are its two defining constraints
+ *
+ * f - m d >=0
+ * -(f - (m - 1)) + m d >= 0
+ *
+ * then it can safely be removed.
+ */
+static int div_is_redundant(struct isl_basic_map *bmap, int div)
+{
+ int i;
+ unsigned pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+ for (i = 0; i < bmap->n_eq; ++i)
+ if (!isl_int_is_zero(bmap->eq[i][pos]))
+ return 0;
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ if (isl_int_is_zero(bmap->ineq[i][pos]))
+ continue;
+ if (!isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div))
+ return 0;
+ }
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (!isl_int_is_zero(bmap->div[i][1+pos]))
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Remove divs that don't occur in any of the constraints or other divs.
+ * These can arise when dropping constraints from a basic map or
+ * when the divs of a basic map have been temporarily aligned
+ * with the divs of another basic map.
+ */
+static struct isl_basic_map *remove_redundant_divs(struct isl_basic_map *bmap)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+
+ for (i = bmap->n_div-1; i >= 0; --i) {
+ if (!div_is_redundant(bmap, i))
+ continue;
+ bmap = isl_basic_map_drop_div(bmap, i);
+ }
+ return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_finalize(struct isl_basic_map *bmap)
+{
+ bmap = remove_redundant_divs(bmap);
+ if (!bmap)
+ return NULL;
+ ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+ return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_finalize(struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_finalize((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_finalize(struct isl_set *set)
+{
+ int i;
+
+ if (!set)
+ return NULL;
+ for (i = 0; i < set->n; ++i) {
+ set->p[i] = isl_basic_set_finalize(set->p[i]);
+ if (!set->p[i])
+ goto error;
+ }
+ return set;
+error:
+ isl_set_free(set);
+ return NULL;
+}
+
+struct isl_map *isl_map_finalize(struct isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_finalize(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+
+/* Remove definition of any div that is defined in terms of the given variable.
+ * The div itself is not removed. Functions such as
+ * eliminate_divs_ineq depend on the other divs remaining in place.
+ */
+static struct isl_basic_map *remove_dependent_vars(struct isl_basic_map *bmap,
+ int pos)
+{
+ int i;
+
+ if (!bmap)
+ return NULL;
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (isl_int_is_zero(bmap->div[i][1+1+pos]))
+ continue;
+ isl_int_set_si(bmap->div[i][0], 0);
+ }
+ return bmap;
+}
+
+/* Eliminate the specified variables from the constraints using
+ * Fourier-Motzkin. The variables themselves are not removed.
+ */
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+ struct isl_basic_map *bmap, unsigned pos, unsigned n)
+{
+ int d;
+ int i, j, k;
+ unsigned total;
+ int need_gauss = 0;
+
+ if (n == 0)
+ return bmap;
+ if (!bmap)
+ return NULL;
+ total = isl_basic_map_total_dim(bmap);
+
+ bmap = isl_basic_map_cow(bmap);
+ for (d = pos + n - 1; d >= 0 && d >= pos; --d)
+ bmap = remove_dependent_vars(bmap, d);
+ if (!bmap)
+ return NULL;
+
+ for (d = pos + n - 1;
+ d >= 0 && d >= total - bmap->n_div && d >= pos; --d)
+ isl_seq_clr(bmap->div[d-(total-bmap->n_div)], 2+total);
+ for (d = pos + n - 1; d >= 0 && d >= pos; --d) {
+ int n_lower, n_upper;
+ if (!bmap)
+ return NULL;
+ for (i = 0; i < bmap->n_eq; ++i) {
+ if (isl_int_is_zero(bmap->eq[i][1+d]))
+ continue;
+ eliminate_var_using_equality(bmap, d, bmap->eq[i], 0, NULL);
+ isl_basic_map_drop_equality(bmap, i);
+ need_gauss = 1;
+ break;
+ }
+ if (i < bmap->n_eq)
+ continue;
+ n_lower = 0;
+ n_upper = 0;
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ if (isl_int_is_pos(bmap->ineq[i][1+d]))
+ n_lower++;
+ else if (isl_int_is_neg(bmap->ineq[i][1+d]))
+ n_upper++;
+ }
+ bmap = isl_basic_map_extend_constraints(bmap,
+ 0, n_lower * n_upper);
+ if (!bmap)
+ goto error;
+ for (i = bmap->n_ineq - 1; i >= 0; --i) {
+ int last;
+ if (isl_int_is_zero(bmap->ineq[i][1+d]))
+ continue;
+ last = -1;
+ for (j = 0; j < i; ++j) {
+ if (isl_int_is_zero(bmap->ineq[j][1+d]))
+ continue;
+ last = j;
+ if (isl_int_sgn(bmap->ineq[i][1+d]) ==
+ isl_int_sgn(bmap->ineq[j][1+d]))
+ continue;
+ k = isl_basic_map_alloc_inequality(bmap);
+ if (k < 0)
+ goto error;
+ isl_seq_cpy(bmap->ineq[k], bmap->ineq[i],
+ 1+total);
+ isl_seq_elim(bmap->ineq[k], bmap->ineq[j],
+ 1+d, 1+total, NULL);
+ }
+ isl_basic_map_drop_inequality(bmap, i);
+ i = last + 1;
+ }
+ if (n_lower > 0 && n_upper > 0) {
+ bmap = isl_basic_map_normalize_constraints(bmap);
+ bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+ NULL, 0);
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ bmap = isl_basic_map_remove_redundancies(bmap);
+ need_gauss = 0;
+ if (!bmap)
+ goto error;
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+ break;
+ }
+ }
+ ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+ if (need_gauss)
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+ struct isl_basic_set *bset, unsigned pos, unsigned n)
+{
+ return (struct isl_basic_set *)isl_basic_map_eliminate_vars(
+ (struct isl_basic_map *)bset, pos, n);
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ * Otherwise, they are projected out and the original space is restored.
+ */
+__isl_give isl_basic_map *isl_basic_map_eliminate(
+ __isl_take isl_basic_map *bmap,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ isl_space *space;
+
+ if (!bmap)
+ return NULL;
+ if (n == 0)
+ return bmap;
+
+ if (first + n > isl_basic_map_dim(bmap, type) || first + n < first)
+ isl_die(bmap->ctx, isl_error_invalid,
+ "index out of bounds", goto error);
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+ first += isl_basic_map_offset(bmap, type) - 1;
+ bmap = isl_basic_map_eliminate_vars(bmap, first, n);
+ return isl_basic_map_finalize(bmap);
+ }
+
+ space = isl_basic_map_get_space(bmap);
+ bmap = isl_basic_map_project_out(bmap, type, first, n);
+ bmap = isl_basic_map_insert_dims(bmap, type, first, n);
+ bmap = isl_basic_map_reset_space(bmap, space);
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_eliminate(
+ __isl_take isl_basic_set *bset,
+ enum isl_dim_type type, unsigned first, unsigned n)
+{
+ return isl_basic_map_eliminate(bset, type, first, n);
+}
+
+/* Don't assume equalities are in order, because align_divs
+ * may have changed the order of the divs.
+ */
+static void compute_elimination_index(struct isl_basic_map *bmap, int *elim)
+{
+ int d, i;
+ unsigned total;
+
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+ for (d = 0; d < total; ++d)
+ elim[d] = -1;
+ for (i = 0; i < bmap->n_eq; ++i) {
+ for (d = total - 1; d >= 0; --d) {
+ if (isl_int_is_zero(bmap->eq[i][1+d]))
+ continue;
+ elim[d] = i;
+ break;
+ }
+ }
+}
+
+static void set_compute_elimination_index(struct isl_basic_set *bset, int *elim)
+{
+ compute_elimination_index((struct isl_basic_map *)bset, elim);
+}
+
+static int reduced_using_equalities(isl_int *dst, isl_int *src,
+ struct isl_basic_map *bmap, int *elim)
+{
+ int d;
+ int copied = 0;
+ unsigned total;
+
+ total = isl_space_dim(bmap->dim, isl_dim_all);
+ for (d = total - 1; d >= 0; --d) {
+ if (isl_int_is_zero(src[1+d]))
+ continue;
+ if (elim[d] == -1)
+ continue;
+ if (!copied) {
+ isl_seq_cpy(dst, src, 1 + total);
+ copied = 1;
+ }
+ isl_seq_elim(dst, bmap->eq[elim[d]], 1 + d, 1 + total, NULL);
+ }
+ return copied;
+}
+
+static int set_reduced_using_equalities(isl_int *dst, isl_int *src,
+ struct isl_basic_set *bset, int *elim)
+{
+ return reduced_using_equalities(dst, src,
+ (struct isl_basic_map *)bset, elim);
+}
+
+static struct isl_basic_set *isl_basic_set_reduce_using_equalities(
+ struct isl_basic_set *bset, struct isl_basic_set *context)
+{
+ int i;
+ int *elim;
+
+ if (!bset || !context)
+ goto error;
+
+ if (context->n_eq == 0) {
+ isl_basic_set_free(context);
+ return bset;
+ }
+
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ goto error;
+
+ elim = isl_alloc_array(bset->ctx, int, isl_basic_set_n_dim(bset));
+ if (!elim)
+ goto error;
+ set_compute_elimination_index(context, elim);
+ for (i = 0; i < bset->n_eq; ++i)
+ set_reduced_using_equalities(bset->eq[i], bset->eq[i],
+ context, elim);
+ for (i = 0; i < bset->n_ineq; ++i)
+ set_reduced_using_equalities(bset->ineq[i], bset->ineq[i],
+ context, elim);
+ isl_basic_set_free(context);
+ free(elim);
+ bset = isl_basic_set_simplify(bset);
+ bset = isl_basic_set_finalize(bset);
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ isl_basic_set_free(context);
+ return NULL;
+}
+
+static struct isl_basic_set *remove_shifted_constraints(
+ struct isl_basic_set *bset, struct isl_basic_set *context)
+{
+ unsigned int size;
+ isl_int ***index;
+ int bits;
+ int k, h, l;
+ isl_ctx *ctx;
+
+ if (!bset)
+ return NULL;
+
+ size = round_up(4 * (context->n_ineq+1) / 3 - 1);
+ bits = ffs(size) - 1;
+ ctx = isl_basic_set_get_ctx(bset);
+ index = isl_calloc_array(ctx, isl_int **, size);
+ if (!index)
+ return bset;
+
+ for (k = 0; k < context->n_ineq; ++k) {
+ h = set_hash_index(index, size, bits, context, k);
+ index[h] = &context->ineq[k];
+ }
+ for (k = 0; k < bset->n_ineq; ++k) {
+ h = set_hash_index(index, size, bits, bset, k);
+ if (!index[h])
+ continue;
+ l = index[h] - &context->ineq[0];
+ if (isl_int_lt(bset->ineq[k][0], context->ineq[l][0]))
+ continue;
+ bset = isl_basic_set_cow(bset);
+ if (!bset)
+ goto error;
+ isl_basic_set_drop_inequality(bset, k);
+ --k;
+ }
+ free(index);
+ return bset;
+error:
+ free(index);
+ return bset;
+}
+
+/* Remove constraints from "bmap" that are identical to constraints
+ * in "context" or that are more relaxed (greater constant term).
+ *
+ * We perform the test for shifted copies on the pure constraints
+ * in remove_shifted_constraints.
+ */
+static __isl_give isl_basic_map *isl_basic_map_remove_shifted_constraints(
+ __isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context)
+{
+ isl_basic_set *bset, *bset_context;
+
+ if (!bmap || !context)
+ goto error;
+
+ if (bmap->n_ineq == 0 || context->n_ineq == 0) {
+ isl_basic_map_free(context);
+ return bmap;
+ }
+
+ context = isl_basic_map_align_divs(context, bmap);
+ bmap = isl_basic_map_align_divs(bmap, context);
+
+ bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+ bset_context = isl_basic_map_underlying_set(context);
+ bset = remove_shifted_constraints(bset, bset_context);
+ isl_basic_set_free(bset_context);
+
+ bmap = isl_basic_map_overlying_set(bset, bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_basic_map_free(context);
+ return NULL;
+}
+
+/* Does the (linear part of a) constraint "c" involve any of the "len"
+ * "relevant" dimensions?
+ */
+static int is_related(isl_int *c, int len, int *relevant)
+{
+ int i;
+
+ for (i = 0; i < len; ++i) {
+ if (!relevant[i])
+ continue;
+ if (!isl_int_is_zero(c[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Drop constraints from "bset" that do not involve any of
+ * the dimensions marked "relevant".
+ */
+static __isl_give isl_basic_set *drop_unrelated_constraints(
+ __isl_take isl_basic_set *bset, int *relevant)
+{
+ int i, dim;
+
+ dim = isl_basic_set_dim(bset, isl_dim_set);
+ for (i = 0; i < dim; ++i)
+ if (!relevant[i])
+ break;
+ if (i >= dim)
+ return bset;
+
+ for (i = bset->n_eq - 1; i >= 0; --i)
+ if (!is_related(bset->eq[i] + 1, dim, relevant))
+ isl_basic_set_drop_equality(bset, i);
+
+ for (i = bset->n_ineq - 1; i >= 0; --i)
+ if (!is_related(bset->ineq[i] + 1, dim, relevant))
+ isl_basic_set_drop_inequality(bset, i);
+
+ return bset;
+}
+
+/* Update the groups in "group" based on the (linear part of a) constraint "c".
+ *
+ * In particular, for any variable involved in the constraint,
+ * find the actual group id from before and replace the group
+ * of the corresponding variable by the minimal group of all
+ * the variables involved in the constraint considered so far
+ * (if this minimum is smaller) or replace the minimum by this group
+ * (if the minimum is larger).
+ *
+ * At the end, all the variables in "c" will (indirectly) point
+ * to the minimal of the groups that they referred to originally.
+ */
+static void update_groups(int dim, int *group, isl_int *c)
+{
+ int j;
+ int min = dim;
+
+ for (j = 0; j < dim; ++j) {
+ if (isl_int_is_zero(c[j]))
+ continue;
+ while (group[j] >= 0 && group[group[j]] != group[j])
+ group[j] = group[group[j]];
+ if (group[j] == min)
+ continue;
+ if (group[j] < min) {
+ if (min >= 0 && min < dim)
+ group[min] = group[j];
+ min = group[j];
+ } else
+ group[group[j]] = min;
+ }
+}
+
+/* Drop constraints from "context" that are irrelevant for computing
+ * the gist of "bset".
+ *
+ * In particular, drop constraints in variables that are not related
+ * to any of the variables involved in the constraints of "bset"
+ * in the sense that there is no sequence of constraints that connects them.
+ *
+ * We construct groups of variables that collect variables that
+ * (indirectly) appear in some common constraint of "context".
+ * Each group is identified by the first variable in the group,
+ * except for the special group of variables that appear in "bset"
+ * (or are related to those variables), which is identified by -1.
+ * If group[i] is equal to i (or -1), then the group of i is i (or -1),
+ * otherwise the group of i is the group of group[i].
+ *
+ * We first initialize the -1 group with the variables that appear in "bset".
+ * Then we initialize groups for the remaining variables.
+ * Then we iterate over the constraints of "context" and update the
+ * group of the variables in the constraint by the smallest group.
+ * Finally, we resolve indirect references to groups by running over
+ * the variables.
+ *
+ * After computing the groups, we drop constraints that do not involve
+ * any variables in the -1 group.
+ */
+static __isl_give isl_basic_set *drop_irrelevant_constraints(
+ __isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset)
+{
+ isl_ctx *ctx;
+ int *group;
+ int dim;
+ int i, j;
+ int last;
+
+ if (!context || !bset)
+ return isl_basic_set_free(context);
+
+ dim = isl_basic_set_dim(bset, isl_dim_set);
+ ctx = isl_basic_set_get_ctx(bset);
+ group = isl_calloc_array(ctx, int, dim);
+
+ if (!group)
+ goto error;
+
+ for (i = 0; i < dim; ++i) {
+ for (j = 0; j < bset->n_eq; ++j)
+ if (!isl_int_is_zero(bset->eq[j][1 + i]))
+ break;
+ if (j < bset->n_eq) {
+ group[i] = -1;
+ continue;
+ }
+ for (j = 0; j < bset->n_ineq; ++j)
+ if (!isl_int_is_zero(bset->ineq[j][1 + i]))
+ break;
+ if (j < bset->n_ineq)
+ group[i] = -1;
+ }
+
+ last = -1;
+ for (i = 0; i < dim; ++i)
+ if (group[i] >= 0)
+ last = group[i] = i;
+ if (last < 0) {
+ free(group);
+ return context;
+ }
+
+ for (i = 0; i < context->n_eq; ++i)
+ update_groups(dim, group, context->eq[i] + 1);
+ for (i = 0; i < context->n_ineq; ++i)
+ update_groups(dim, group, context->ineq[i] + 1);
+
+ for (i = 0; i < dim; ++i)
+ if (group[i] >= 0)
+ group[i] = group[group[i]];
+
+ for (i = 0; i < dim; ++i)
+ group[i] = group[i] == -1;
+
+ context = drop_unrelated_constraints(context, group);
+
+ free(group);
+ return context;
+error:
+ free(group);
+ return isl_basic_set_free(context);
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context. Both bset and context are assumed to be full-dimensional.
+ *
+ * We first remove the inequalities from "bset"
+ * that are obviously redundant with respect to some inequality in "context".
+ * Then we remove those constraints from "context" that have become
+ * irrelevant for computing the gist of "bset".
+ * Note that this removal of constraints cannot be replaced by
+ * a factorization because factors in "bset" may still be connected
+ * to each other through constraints in "context".
+ *
+ * If there are any inequalities left, we construct a tableau for
+ * the context and then add the inequalities of "bset".
+ * Before adding these inequalities, we freeze all constraints such that
+ * they won't be considered redundant in terms of the constraints of "bset".
+ * Then we detect all redundant constraints (among the
+ * constraints that weren't frozen), first by checking for redundancy in the
+ * the tableau and then by checking if replacing a constraint by its negation
+ * would lead to an empty set. This last step is fairly expensive
+ * and could be optimized by more reuse of the tableau.
+ * Finally, we update bset according to the results.
+ */
+static __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset,
+ __isl_take isl_basic_set *context)
+{
+ int i, k;
+ isl_basic_set *combined = NULL;
+ struct isl_tab *tab = NULL;
+ unsigned context_ineq;
+ unsigned total;
+
+ if (!bset || !context)
+ goto error;
+
+ if (isl_basic_set_is_universe(bset)) {
+ isl_basic_set_free(context);
+ return bset;
+ }
+
+ if (isl_basic_set_is_universe(context)) {
+ isl_basic_set_free(context);
+ return bset;
+ }
+
+ bset = remove_shifted_constraints(bset, context);
+ if (!bset)
+ goto error;
+ if (bset->n_ineq == 0)
+ goto done;
+
+ context = drop_irrelevant_constraints(context, bset);
+ if (!context)
+ goto error;
+ if (isl_basic_set_is_universe(context)) {
+ isl_basic_set_free(context);
+ return bset;
+ }
+
+ context_ineq = context->n_ineq;
+ combined = isl_basic_set_cow(isl_basic_set_copy(context));
+ combined = isl_basic_set_extend_constraints(combined, 0, bset->n_ineq);
+ tab = isl_tab_from_basic_set(combined, 0);
+ for (i = 0; i < context_ineq; ++i)
+ if (isl_tab_freeze_constraint(tab, i) < 0)
+ goto error;
+ if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+ goto error;
+ for (i = 0; i < bset->n_ineq; ++i)
+ if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0)
+ goto error;
+ bset = isl_basic_set_add_constraints(combined, bset, 0);
+ combined = NULL;
+ if (!bset)
+ goto error;
+ if (isl_tab_detect_redundant(tab) < 0)
+ goto error;
+ total = isl_basic_set_total_dim(bset);
+ for (i = context_ineq; i < bset->n_ineq; ++i) {
+ int is_empty;
+ if (tab->con[i].is_redundant)
+ continue;
+ tab->con[i].is_redundant = 1;
+ combined = isl_basic_set_dup(bset);
+ combined = isl_basic_set_update_from_tab(combined, tab);
+ combined = isl_basic_set_extend_constraints(combined, 0, 1);
+ k = isl_basic_set_alloc_inequality(combined);
+ if (k < 0)
+ goto error;
+ isl_seq_neg(combined->ineq[k], bset->ineq[i], 1 + total);
+ isl_int_sub_ui(combined->ineq[k][0], combined->ineq[k][0], 1);
+ is_empty = isl_basic_set_is_empty(combined);
+ if (is_empty < 0)
+ goto error;
+ isl_basic_set_free(combined);
+ combined = NULL;
+ if (!is_empty)
+ tab->con[i].is_redundant = 0;
+ }
+ for (i = 0; i < context_ineq; ++i)
+ tab->con[i].is_redundant = 1;
+ bset = isl_basic_set_update_from_tab(bset, tab);
+ if (bset) {
+ ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+ ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+ }
+
+ isl_tab_free(tab);
+done:
+ bset = isl_basic_set_simplify(bset);
+ bset = isl_basic_set_finalize(bset);
+ isl_basic_set_free(context);
+ return bset;
+error:
+ isl_tab_free(tab);
+ isl_basic_set_free(combined);
+ isl_basic_set_free(context);
+ isl_basic_set_free(bset);
+ return NULL;
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context. In particular, equalities that are linear combinations
+ * of those in context are removed. Then the inequalities that are
+ * redundant in the context of the equalities and inequalities of
+ * context are removed.
+ *
+ * First of all, we drop those constraints from "context"
+ * that are irrelevant for computing the gist of "bset".
+ * Alternatively, we could factorize the intersection of "context" and "bset".
+ *
+ * We first compute the integer affine hull of the intersection,
+ * compute the gist inside this affine hull and then add back
+ * those equalities that are not implied by the context.
+ *
+ * If two constraints are mutually redundant, then uset_gist_full
+ * will remove the second of those constraints. We therefore first
+ * sort the constraints so that constraints not involving existentially
+ * quantified variables are given precedence over those that do.
+ * We have to perform this sorting before the variable compression,
+ * because that may effect the order of the variables.
+ */
+static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
+ __isl_take isl_basic_set *context)
+{
+ isl_mat *eq;
+ isl_mat *T, *T2;
+ isl_basic_set *aff;
+ isl_basic_set *aff_context;
+ unsigned total;
+
+ if (!bset || !context)
+ goto error;
+
+ context = drop_irrelevant_constraints(context, bset);
+
+ aff = isl_basic_set_copy(bset);
+ aff = isl_basic_set_intersect(aff, isl_basic_set_copy(context));
+ aff = isl_basic_set_affine_hull(aff);
+ if (!aff)
+ goto error;
+ if (isl_basic_set_plain_is_empty(aff)) {
+ isl_basic_set_free(bset);
+ isl_basic_set_free(context);
+ return aff;
+ }
+ bset = isl_basic_set_sort_constraints(bset);
+ if (aff->n_eq == 0) {
+ isl_basic_set_free(aff);
+ return uset_gist_full(bset, context);
+ }
+ total = isl_basic_set_total_dim(bset);
+ eq = isl_mat_sub_alloc6(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total);
+ eq = isl_mat_cow(eq);
+ T = isl_mat_variable_compression(eq, &T2);
+ if (T && T->n_col == 0) {
+ isl_mat_free(T);
+ isl_mat_free(T2);
+ isl_basic_set_free(context);
+ isl_basic_set_free(aff);
+ return isl_basic_set_set_to_empty(bset);
+ }
+
+ aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context));
+
+ bset = isl_basic_set_preimage(bset, isl_mat_copy(T));
+ context = isl_basic_set_preimage(context, T);
+
+ bset = uset_gist_full(bset, context);
+ bset = isl_basic_set_preimage(bset, T2);
+ bset = isl_basic_set_intersect(bset, aff);
+ bset = isl_basic_set_reduce_using_equalities(bset, aff_context);
+
+ if (bset) {
+ ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+ ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+ }
+
+ return bset;
+error:
+ isl_basic_set_free(bset);
+ isl_basic_set_free(context);
+ return NULL;
+}
+
+/* Normalize the divs in "bmap" in the context of the equalities in "context".
+ * We simply add the equalities in context to bmap and then do a regular
+ * div normalizations. Better results can be obtained by normalizing
+ * only the divs in bmap than do not also appear in context.
+ * We need to be careful to reduce the divs using the equalities
+ * so that later calls to isl_basic_map_overlying_set wouldn't introduce
+ * spurious constraints.
+ */
+static struct isl_basic_map *normalize_divs_in_context(
+ struct isl_basic_map *bmap, struct isl_basic_map *context)
+{
+ int i;
+ unsigned total_context;
+ int div_eq;
+
+ div_eq = n_pure_div_eq(bmap);
+ if (div_eq == 0)
+ return bmap;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (context->n_div > 0)
+ bmap = isl_basic_map_align_divs(bmap, context);
+
+ total_context = isl_basic_map_total_dim(context);
+ bmap = isl_basic_map_extend_constraints(bmap, context->n_eq, 0);
+ for (i = 0; i < context->n_eq; ++i) {
+ int k;
+ k = isl_basic_map_alloc_equality(bmap);
+ if (k < 0)
+ return isl_basic_map_free(bmap);
+ isl_seq_cpy(bmap->eq[k], context->eq[i], 1 + total_context);
+ isl_seq_clr(bmap->eq[k] + 1 + total_context,
+ isl_basic_map_total_dim(bmap) - total_context);
+ }
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ bmap = normalize_divs(bmap, NULL);
+ bmap = isl_basic_map_gauss(bmap, NULL);
+ return bmap;
+}
+
+/* Return a basic map that has the same intersection with "context" as "bmap"
+ * and that is as "simple" as possible.
+ *
+ * The core computation is performed on the pure constraints.
+ * When we add back the meaning of the integer divisions, we need
+ * to (re)introduce the div constraints. If we happen to have
+ * discovered that some of these integer divisions are equal to
+ * some affine combination of other variables, then these div
+ * constraints may end up getting simplified in terms of the equalities,
+ * resulting in extra inequalities on the other variables that
+ * may have been removed already or that may not even have been
+ * part of the input. We try and remove those constraints of
+ * this form that are most obviously redundant with respect to
+ * the context. We also remove those div constraints that are
+ * redundant with respect to the other constraints in the result.
+ */
+struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap,
+ struct isl_basic_map *context)
+{
+ isl_basic_set *bset, *eq;
+ isl_basic_map *eq_bmap;
+ unsigned n_div, n_eq, n_ineq;
+
+ if (!bmap || !context)
+ goto error;
+
+ if (isl_basic_map_is_universe(bmap)) {
+ isl_basic_map_free(context);
+ return bmap;
+ }
+ if (isl_basic_map_plain_is_empty(context)) {
+ isl_space *space = isl_basic_map_get_space(bmap);
+ isl_basic_map_free(bmap);
+ isl_basic_map_free(context);
+ return isl_basic_map_universe(space);
+ }
+ if (isl_basic_map_plain_is_empty(bmap)) {
+ isl_basic_map_free(context);
+ return bmap;
+ }
+
+ bmap = isl_basic_map_remove_redundancies(bmap);
+ context = isl_basic_map_remove_redundancies(context);
+ if (!context)
+ goto error;
+
+ if (context->n_eq)
+ bmap = normalize_divs_in_context(bmap, context);
+
+ context = isl_basic_map_align_divs(context, bmap);
+ bmap = isl_basic_map_align_divs(bmap, context);
+ n_div = isl_basic_map_dim(bmap, isl_dim_div);
+
+ bset = uset_gist(isl_basic_map_underlying_set(isl_basic_map_copy(bmap)),
+ isl_basic_map_underlying_set(isl_basic_map_copy(context)));
+
+ if (!bset || bset->n_eq == 0 || n_div == 0 ||
+ isl_basic_set_plain_is_empty(bset)) {
+ isl_basic_map_free(context);
+ return isl_basic_map_overlying_set(bset, bmap);
+ }
+
+ n_eq = bset->n_eq;
+ n_ineq = bset->n_ineq;
+ eq = isl_basic_set_copy(bset);
+ eq = isl_basic_set_cow(bset);
+ if (isl_basic_set_free_inequality(eq, n_ineq) < 0)
+ eq = isl_basic_set_free(eq);
+ if (isl_basic_set_free_equality(bset, n_eq) < 0)
+ bset = isl_basic_set_free(bset);
+
+ eq_bmap = isl_basic_map_overlying_set(eq, isl_basic_map_copy(bmap));
+ eq_bmap = isl_basic_map_remove_shifted_constraints(eq_bmap, context);
+ bmap = isl_basic_map_overlying_set(bset, bmap);
+ bmap = isl_basic_map_intersect(bmap, eq_bmap);
+ bmap = isl_basic_map_remove_redundancies(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ isl_basic_map_free(context);
+ return NULL;
+}
+
+/*
+ * Assumes context has no implicit divs.
+ */
+__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
+ __isl_take isl_basic_map *context)
+{
+ int i;
+
+ if (!map || !context)
+ goto error;
+
+ if (isl_basic_map_plain_is_empty(context)) {
+ isl_space *space = isl_map_get_space(map);
+ isl_map_free(map);
+ isl_basic_map_free(context);
+ return isl_map_universe(space);
+ }
+
+ context = isl_basic_map_remove_redundancies(context);
+ map = isl_map_cow(map);
+ if (!map || !context)
+ goto error;
+ isl_assert(map->ctx, isl_space_is_equal(map->dim, context->dim), goto error);
+ map = isl_map_compute_divs(map);
+ if (!map)
+ goto error;
+ for (i = map->n - 1; i >= 0; --i) {
+ map->p[i] = isl_basic_map_gist(map->p[i],
+ isl_basic_map_copy(context));
+ if (!map->p[i])
+ goto error;
+ if (isl_basic_map_plain_is_empty(map->p[i])) {
+ isl_basic_map_free(map->p[i]);
+ if (i != map->n - 1)
+ map->p[i] = map->p[map->n - 1];
+ map->n--;
+ }
+ }
+ isl_basic_map_free(context);
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ isl_basic_map_free(context);
+ return NULL;
+}
+
+/* Return a map that has the same intersection with "context" as "map"
+ * and that is as "simple" as possible.
+ *
+ * If "map" is already the universe, then we cannot make it any simpler.
+ * Similarly, if "context" is the universe, then we cannot exploit it
+ * to simplify "map"
+ * If "map" and "context" are identical to each other, then we can
+ * return the corresponding universe.
+ *
+ * If none of these cases apply, we have to work a bit harder.
+ */
+static __isl_give isl_map *map_gist(__isl_take isl_map *map,
+ __isl_take isl_map *context)
+{
+ int equal;
+ int is_universe;
+
+ is_universe = isl_map_plain_is_universe(map);
+ if (is_universe >= 0 && !is_universe)
+ is_universe = isl_map_plain_is_universe(context);
+ if (is_universe < 0)
+ goto error;
+ if (is_universe) {
+ isl_map_free(context);
+ return map;
+ }
+
+ equal = isl_map_plain_is_equal(map, context);
+ if (equal < 0)
+ goto error;
+ if (equal) {
+ isl_map *res = isl_map_universe(isl_map_get_space(map));
+ isl_map_free(map);
+ isl_map_free(context);
+ return res;
+ }
+
+ context = isl_map_compute_divs(context);
+ return isl_map_gist_basic_map(map, isl_map_simple_hull(context));
+error:
+ isl_map_free(map);
+ isl_map_free(context);
+ return NULL;
+}
+
+__isl_give isl_map *isl_map_gist(__isl_take isl_map *map,
+ __isl_take isl_map *context)
+{
+ return isl_map_align_params_map_map_and(map, context, &map_gist);
+}
+
+struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset,
+ struct isl_basic_set *context)
+{
+ return (struct isl_basic_set *)isl_basic_map_gist(
+ (struct isl_basic_map *)bset, (struct isl_basic_map *)context);
+}
+
+__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set,
+ __isl_take isl_basic_set *context)
+{
+ return (struct isl_set *)isl_map_gist_basic_map((struct isl_map *)set,
+ (struct isl_basic_map *)context);
+}
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+ __isl_take isl_basic_set *context)
+{
+ isl_space *space = isl_set_get_space(set);
+ isl_basic_set *dom_context = isl_basic_set_universe(space);
+ dom_context = isl_basic_set_intersect_params(dom_context, context);
+ return isl_set_gist_basic_set(set, dom_context);
+}
+
+__isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
+ __isl_take isl_set *context)
+{
+ return (struct isl_set *)isl_map_gist((struct isl_map *)set,
+ (struct isl_map *)context);
+}
+
+__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map,
+ __isl_take isl_set *context)
+{
+ isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+ map_context = isl_map_intersect_domain(map_context, context);
+ return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map,
+ __isl_take isl_set *context)
+{
+ isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+ map_context = isl_map_intersect_range(map_context, context);
+ return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map,
+ __isl_take isl_set *context)
+{
+ isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+ map_context = isl_map_intersect_params(map_context, context);
+ return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set,
+ __isl_take isl_set *context)
+{
+ return isl_map_gist_params(set, context);
+}
+
+/* Quick check to see if two basic maps are disjoint.
+ * In particular, we reduce the equalities and inequalities of
+ * one basic map in the context of the equalities of the other
+ * basic map and check if we get a contradiction.
+ */
+int isl_basic_map_plain_is_disjoint(__isl_keep isl_basic_map *bmap1,
+ __isl_keep isl_basic_map *bmap2)
+{
+ struct isl_vec *v = NULL;
+ int *elim = NULL;
+ unsigned total;
+ int i;
+
+ if (!bmap1 || !bmap2)
+ return -1;
+ isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+ return -1);
+ if (bmap1->n_div || bmap2->n_div)
+ return 0;
+ if (!bmap1->n_eq && !bmap2->n_eq)
+ return 0;
+
+ total = isl_space_dim(bmap1->dim, isl_dim_all);
+ if (total == 0)
+ return 0;
+ v = isl_vec_alloc(bmap1->ctx, 1 + total);
+ if (!v)
+ goto error;
+ elim = isl_alloc_array(bmap1->ctx, int, total);
+ if (!elim)
+ goto error;
+ compute_elimination_index(bmap1, elim);
+ for (i = 0; i < bmap2->n_eq; ++i) {
+ int reduced;
+ reduced = reduced_using_equalities(v->block.data, bmap2->eq[i],
+ bmap1, elim);
+ if (reduced && !isl_int_is_zero(v->block.data[0]) &&
+ isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+ goto disjoint;
+ }
+ for (i = 0; i < bmap2->n_ineq; ++i) {
+ int reduced;
+ reduced = reduced_using_equalities(v->block.data,
+ bmap2->ineq[i], bmap1, elim);
+ if (reduced && isl_int_is_neg(v->block.data[0]) &&
+ isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+ goto disjoint;
+ }
+ compute_elimination_index(bmap2, elim);
+ for (i = 0; i < bmap1->n_ineq; ++i) {
+ int reduced;
+ reduced = reduced_using_equalities(v->block.data,
+ bmap1->ineq[i], bmap2, elim);
+ if (reduced && isl_int_is_neg(v->block.data[0]) &&
+ isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+ goto disjoint;
+ }
+ isl_vec_free(v);
+ free(elim);
+ return 0;
+disjoint:
+ isl_vec_free(v);
+ free(elim);
+ return 1;
+error:
+ isl_vec_free(v);
+ free(elim);
+ return -1;
+}
+
+int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1,
+ __isl_keep isl_basic_set *bset2)
+{
+ return isl_basic_map_plain_is_disjoint((struct isl_basic_map *)bset1,
+ (struct isl_basic_map *)bset2);
+}
+
+/* Are "map1" and "map2" obviously disjoint?
+ *
+ * If one of them is empty or if they live in different spaces (ignoring
+ * parameters), then they are clearly disjoint.
+ *
+ * If they have different parameters, then we skip any further tests.
+ *
+ * If they are obviously equal, but not obviously empty, then we will
+ * not be able to detect if they are disjoint.
+ *
+ * Otherwise we check if each basic map in "map1" is obviously disjoint
+ * from each basic map in "map2".
+ */
+int isl_map_plain_is_disjoint(__isl_keep isl_map *map1,
+ __isl_keep isl_map *map2)
+{
+ int i, j;
+ int disjoint;
+ int intersect;
+ int match;
+
+ if (!map1 || !map2)
+ return -1;
+
+ disjoint = isl_map_plain_is_empty(map1);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ disjoint = isl_map_plain_is_empty(map2);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ match = isl_space_tuple_is_equal(map1->dim, isl_dim_in,
+ map2->dim, isl_dim_in);
+ if (match < 0 || !match)
+ return match < 0 ? -1 : 1;
+
+ match = isl_space_tuple_is_equal(map1->dim, isl_dim_out,
+ map2->dim, isl_dim_out);
+ if (match < 0 || !match)
+ return match < 0 ? -1 : 1;
+
+ match = isl_space_match(map1->dim, isl_dim_param,
+ map2->dim, isl_dim_param);
+ if (match < 0 || !match)
+ return match < 0 ? -1 : 0;
+
+ intersect = isl_map_plain_is_equal(map1, map2);
+ if (intersect < 0 || intersect)
+ return intersect < 0 ? -1 : 0;
+
+ for (i = 0; i < map1->n; ++i) {
+ for (j = 0; j < map2->n; ++j) {
+ int d = isl_basic_map_plain_is_disjoint(map1->p[i],
+ map2->p[j]);
+ if (d != 1)
+ return d;
+ }
+ }
+ return 1;
+}
+
+/* Are "map1" and "map2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty. Otherwise, they are not disjoint if one of them is universal.
+ * If none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+int isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+ int disjoint;
+ int intersect;
+ isl_map *test;
+
+ disjoint = isl_map_plain_is_disjoint(map1, map2);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ disjoint = isl_map_is_empty(map1);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ disjoint = isl_map_is_empty(map2);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ intersect = isl_map_plain_is_universe(map1);
+ if (intersect < 0 || intersect)
+ return intersect < 0 ? -1 : 0;
+
+ intersect = isl_map_plain_is_universe(map2);
+ if (intersect < 0 || intersect)
+ return intersect < 0 ? -1 : 0;
+
+ test = isl_map_intersect(isl_map_copy(map1), isl_map_copy(map2));
+ disjoint = isl_map_is_empty(test);
+ isl_map_free(test);
+
+ return disjoint;
+}
+
+/* Are "bmap1" and "bmap2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty. Otherwise, they are not disjoint if one of them is universal.
+ * If none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+int isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1,
+ __isl_keep isl_basic_map *bmap2)
+{
+ int disjoint;
+ int intersect;
+ isl_basic_map *test;
+
+ disjoint = isl_basic_map_plain_is_disjoint(bmap1, bmap2);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ disjoint = isl_basic_map_is_empty(bmap1);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ disjoint = isl_basic_map_is_empty(bmap2);
+ if (disjoint < 0 || disjoint)
+ return disjoint;
+
+ intersect = isl_basic_map_is_universe(bmap1);
+ if (intersect < 0 || intersect)
+ return intersect < 0 ? -1 : 0;
+
+ intersect = isl_basic_map_is_universe(bmap2);
+ if (intersect < 0 || intersect)
+ return intersect < 0 ? -1 : 0;
+
+ test = isl_basic_map_intersect(isl_basic_map_copy(bmap1),
+ isl_basic_map_copy(bmap2));
+ disjoint = isl_basic_map_is_empty(test);
+ isl_basic_map_free(test);
+
+ return disjoint;
+}
+
+/* Are "bset1" and "bset2" disjoint?
+ */
+int isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1,
+ __isl_keep isl_basic_set *bset2)
+{
+ return isl_basic_map_is_disjoint(bset1, bset2);
+}
+
+int isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+ __isl_keep isl_set *set2)
+{
+ return isl_map_plain_is_disjoint((struct isl_map *)set1,
+ (struct isl_map *)set2);
+}
+
+/* Are "set1" and "set2" disjoint?
+ */
+int isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ return isl_map_is_disjoint(set1, set2);
+}
+
+int isl_set_fast_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+ return isl_set_plain_is_disjoint(set1, set2);
+}
+
+/* Check if we can combine a given div with lower bound l and upper
+ * bound u with some other div and if so return that other div.
+ * Otherwise return -1.
+ *
+ * We first check that
+ * - the bounds are opposites of each other (except for the constant
+ * term)
+ * - the bounds do not reference any other div
+ * - no div is defined in terms of this div
+ *
+ * Let m be the size of the range allowed on the div by the bounds.
+ * That is, the bounds are of the form
+ *
+ * e <= a <= e + m - 1
+ *
+ * with e some expression in the other variables.
+ * We look for another div b such that no third div is defined in terms
+ * of this second div b and such that in any constraint that contains
+ * a (except for the given lower and upper bound), also contains b
+ * with a coefficient that is m times that of b.
+ * That is, all constraints (execpt for the lower and upper bound)
+ * are of the form
+ *
+ * e + f (a + m b) >= 0
+ *
+ * If so, we return b so that "a + m b" can be replaced by
+ * a single div "c = a + m b".
+ */
+static int div_find_coalesce(struct isl_basic_map *bmap, int *pairs,
+ unsigned div, unsigned l, unsigned u)
+{
+ int i, j;
+ unsigned dim;
+ int coalesce = -1;
+
+ if (bmap->n_div <= 1)
+ return -1;
+ dim = isl_space_dim(bmap->dim, isl_dim_all);
+ if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim, div) != -1)
+ return -1;
+ if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim + div + 1,
+ bmap->n_div - div - 1) != -1)
+ return -1;
+ if (!isl_seq_is_neg(bmap->ineq[l] + 1, bmap->ineq[u] + 1,
+ dim + bmap->n_div))
+ return -1;
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (isl_int_is_zero(bmap->div[i][0]))
+ continue;
+ if (!isl_int_is_zero(bmap->div[i][1 + 1 + dim + div]))
+ return -1;
+ }
+
+ isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+ if (isl_int_is_neg(bmap->ineq[l][0])) {
+ isl_int_sub(bmap->ineq[l][0],
+ bmap->ineq[l][0], bmap->ineq[u][0]);
+ bmap = isl_basic_map_copy(bmap);
+ bmap = isl_basic_map_set_to_empty(bmap);
+ isl_basic_map_free(bmap);
+ return -1;
+ }
+ isl_int_add_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (i == div)
+ continue;
+ if (!pairs[i])
+ continue;
+ for (j = 0; j < bmap->n_div; ++j) {
+ if (isl_int_is_zero(bmap->div[j][0]))
+ continue;
+ if (!isl_int_is_zero(bmap->div[j][1 + 1 + dim + i]))
+ break;
+ }
+ if (j < bmap->n_div)
+ continue;
+ for (j = 0; j < bmap->n_ineq; ++j) {
+ int valid;
+ if (j == l || j == u)
+ continue;
+ if (isl_int_is_zero(bmap->ineq[j][1 + dim + div]))
+ continue;
+ if (isl_int_is_zero(bmap->ineq[j][1 + dim + i]))
+ break;
+ isl_int_mul(bmap->ineq[j][1 + dim + div],
+ bmap->ineq[j][1 + dim + div],
+ bmap->ineq[l][0]);
+ valid = isl_int_eq(bmap->ineq[j][1 + dim + div],
+ bmap->ineq[j][1 + dim + i]);
+ isl_int_divexact(bmap->ineq[j][1 + dim + div],
+ bmap->ineq[j][1 + dim + div],
+ bmap->ineq[l][0]);
+ if (!valid)
+ break;
+ }
+ if (j < bmap->n_ineq)
+ continue;
+ coalesce = i;
+ break;
+ }
+ isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+ isl_int_sub(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+ return coalesce;
+}
+
+/* Given a lower and an upper bound on div i, construct an inequality
+ * that when nonnegative ensures that this pair of bounds always allows
+ * for an integer value of the given div.
+ * The lower bound is inequality l, while the upper bound is inequality u.
+ * The constructed inequality is stored in ineq.
+ * g, fl, fu are temporary scalars.
+ *
+ * Let the upper bound be
+ *
+ * -n_u a + e_u >= 0
+ *
+ * and the lower bound
+ *
+ * n_l a + e_l >= 0
+ *
+ * Let n_u = f_u g and n_l = f_l g, with g = gcd(n_u, n_l).
+ * We have
+ *
+ * - f_u e_l <= f_u f_l g a <= f_l e_u
+ *
+ * Since all variables are integer valued, this is equivalent to
+ *
+ * - f_u e_l - (f_u - 1) <= f_u f_l g a <= f_l e_u + (f_l - 1)
+ *
+ * If this interval is at least f_u f_l g, then it contains at least
+ * one integer value for a.
+ * That is, the test constraint is
+ *
+ * f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 >= f_u f_l g
+ */
+static void construct_test_ineq(struct isl_basic_map *bmap, int i,
+ int l, int u, isl_int *ineq, isl_int g, isl_int fl, isl_int fu)
+{
+ unsigned dim;
+ dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+ isl_int_gcd(g, bmap->ineq[l][1 + dim + i], bmap->ineq[u][1 + dim + i]);
+ isl_int_divexact(fl, bmap->ineq[l][1 + dim + i], g);
+ isl_int_divexact(fu, bmap->ineq[u][1 + dim + i], g);
+ isl_int_neg(fu, fu);
+ isl_seq_combine(ineq, fl, bmap->ineq[u], fu, bmap->ineq[l],
+ 1 + dim + bmap->n_div);
+ isl_int_add(ineq[0], ineq[0], fl);
+ isl_int_add(ineq[0], ineq[0], fu);
+ isl_int_sub_ui(ineq[0], ineq[0], 1);
+ isl_int_mul(g, g, fl);
+ isl_int_mul(g, g, fu);
+ isl_int_sub(ineq[0], ineq[0], g);
+}
+
+/* Remove more kinds of divs that are not strictly needed.
+ * In particular, if all pairs of lower and upper bounds on a div
+ * are such that they allow at least one integer value of the div,
+ * the we can eliminate the div using Fourier-Motzkin without
+ * introducing any spurious solutions.
+ */
+static struct isl_basic_map *drop_more_redundant_divs(
+ struct isl_basic_map *bmap, int *pairs, int n)
+{
+ struct isl_tab *tab = NULL;
+ struct isl_vec *vec = NULL;
+ unsigned dim;
+ int remove = -1;
+ isl_int g, fl, fu;
+
+ isl_int_init(g);
+ isl_int_init(fl);
+ isl_int_init(fu);
+
+ if (!bmap)
+ goto error;
+
+ dim = isl_space_dim(bmap->dim, isl_dim_all);
+ vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div);
+ if (!vec)
+ goto error;
+
+ tab = isl_tab_from_basic_map(bmap, 0);
+
+ while (n > 0) {
+ int i, l, u;
+ int best = -1;
+ enum isl_lp_result res;
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (!pairs[i])
+ continue;
+ if (best >= 0 && pairs[best] <= pairs[i])
+ continue;
+ best = i;
+ }
+
+ i = best;
+ for (l = 0; l < bmap->n_ineq; ++l) {
+ if (!isl_int_is_pos(bmap->ineq[l][1 + dim + i]))
+ continue;
+ for (u = 0; u < bmap->n_ineq; ++u) {
+ if (!isl_int_is_neg(bmap->ineq[u][1 + dim + i]))
+ continue;
+ construct_test_ineq(bmap, i, l, u,
+ vec->el, g, fl, fu);
+ res = isl_tab_min(tab, vec->el,
+ bmap->ctx->one, &g, NULL, 0);
+ if (res == isl_lp_error)
+ goto error;
+ if (res == isl_lp_empty) {
+ bmap = isl_basic_map_set_to_empty(bmap);
+ break;
+ }
+ if (res != isl_lp_ok || isl_int_is_neg(g))
+ break;
+ }
+ if (u < bmap->n_ineq)
+ break;
+ }
+ if (l == bmap->n_ineq) {
+ remove = i;
+ break;
+ }
+ pairs[i] = 0;
+ --n;
+ }
+
+ isl_tab_free(tab);
+ isl_vec_free(vec);
+
+ isl_int_clear(g);
+ isl_int_clear(fl);
+ isl_int_clear(fu);
+
+ free(pairs);
+
+ if (remove < 0)
+ return bmap;
+
+ bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, remove, 1);
+ return isl_basic_map_drop_redundant_divs(bmap);
+error:
+ free(pairs);
+ isl_basic_map_free(bmap);
+ isl_tab_free(tab);
+ isl_vec_free(vec);
+ isl_int_clear(g);
+ isl_int_clear(fl);
+ isl_int_clear(fu);
+ return NULL;
+}
+
+/* Given a pair of divs div1 and div2 such that, expect for the lower bound l
+ * and the upper bound u, div1 always occurs together with div2 in the form
+ * (div1 + m div2), where m is the constant range on the variable div1
+ * allowed by l and u, replace the pair div1 and div2 by a single
+ * div that is equal to div1 + m div2.
+ *
+ * The new div will appear in the location that contains div2.
+ * We need to modify all constraints that contain
+ * div2 = (div - div1) / m
+ * (If a constraint does not contain div2, it will also not contain div1.)
+ * If the constraint also contains div1, then we know they appear
+ * as f (div1 + m div2) and we can simply replace (div1 + m div2) by div,
+ * i.e., the coefficient of div is f.
+ *
+ * Otherwise, we first need to introduce div1 into the constraint.
+ * Let the l be
+ *
+ * div1 + f >=0
+ *
+ * and u
+ *
+ * -div1 + f' >= 0
+ *
+ * A lower bound on div2
+ *
+ * n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ * (n * (m div 2 + div1) + m t + n f)/g >= 0
+ *
+ * with g = gcd(m,n).
+ * An upper bound
+ *
+ * -n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ * (-n * (m div2 + div1) + m t + n f')/g >= 0
+ *
+ * These constraint are those that we would obtain from eliminating
+ * div1 using Fourier-Motzkin.
+ *
+ * After all constraints have been modified, we drop the lower and upper
+ * bound and then drop div1.
+ */
+static struct isl_basic_map *coalesce_divs(struct isl_basic_map *bmap,
+ unsigned div1, unsigned div2, unsigned l, unsigned u)
+{
+ isl_int a;
+ isl_int b;
+ isl_int m;
+ unsigned dim, total;
+ int i;
+
+ dim = isl_space_dim(bmap->dim, isl_dim_all);
+ total = 1 + dim + bmap->n_div;
+
+ isl_int_init(a);
+ isl_int_init(b);
+ isl_int_init(m);
+ isl_int_add(m, bmap->ineq[l][0], bmap->ineq[u][0]);
+ isl_int_add_ui(m, m, 1);
+
+ for (i = 0; i < bmap->n_ineq; ++i) {
+ if (i == l || i == u)
+ continue;
+ if (isl_int_is_zero(bmap->ineq[i][1 + dim + div2]))
+ continue;
+ if (isl_int_is_zero(bmap->ineq[i][1 + dim + div1])) {
+ isl_int_gcd(b, m, bmap->ineq[i][1 + dim + div2]);
+ isl_int_divexact(a, m, b);
+ isl_int_divexact(b, bmap->ineq[i][1 + dim + div2], b);
+ if (isl_int_is_pos(b)) {
+ isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+ b, bmap->ineq[l], total);
+ } else {
+ isl_int_neg(b, b);
+ isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+ b, bmap->ineq[u], total);
+ }
+ }
+ isl_int_set(bmap->ineq[i][1 + dim + div2],
+ bmap->ineq[i][1 + dim + div1]);
+ isl_int_set_si(bmap->ineq[i][1 + dim + div1], 0);
+ }
+
+ isl_int_clear(a);
+ isl_int_clear(b);
+ isl_int_clear(m);
+ if (l > u) {
+ isl_basic_map_drop_inequality(bmap, l);
+ isl_basic_map_drop_inequality(bmap, u);
+ } else {
+ isl_basic_map_drop_inequality(bmap, u);
+ isl_basic_map_drop_inequality(bmap, l);
+ }
+ bmap = isl_basic_map_drop_div(bmap, div1);
+ return bmap;
+}
+
+/* First check if we can coalesce any pair of divs and
+ * then continue with dropping more redundant divs.
+ *
+ * We loop over all pairs of lower and upper bounds on a div
+ * with coefficient 1 and -1, respectively, check if there
+ * is any other div "c" with which we can coalesce the div
+ * and if so, perform the coalescing.
+ */
+static struct isl_basic_map *coalesce_or_drop_more_redundant_divs(
+ struct isl_basic_map *bmap, int *pairs, int n)
+{
+ int i, l, u;
+ unsigned dim;
+
+ dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ if (!pairs[i])
+ continue;
+ for (l = 0; l < bmap->n_ineq; ++l) {
+ if (!isl_int_is_one(bmap->ineq[l][1 + dim + i]))
+ continue;
+ for (u = 0; u < bmap->n_ineq; ++u) {
+ int c;
+
+ if (!isl_int_is_negone(bmap->ineq[u][1+dim+i]))
+ continue;
+ c = div_find_coalesce(bmap, pairs, i, l, u);
+ if (c < 0)
+ continue;
+ free(pairs);
+ bmap = coalesce_divs(bmap, i, c, l, u);
+ return isl_basic_map_drop_redundant_divs(bmap);
+ }
+ }
+ }
+
+ if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+ return bmap;
+
+ return drop_more_redundant_divs(bmap, pairs, n);
+}
+
+/* Remove divs that are not strictly needed.
+ * In particular, if a div only occurs positively (or negatively)
+ * in constraints, then it can simply be dropped.
+ * Also, if a div occurs in only two constraints and if moreover
+ * those two constraints are opposite to each other, except for the constant
+ * term and if the sum of the constant terms is such that for any value
+ * of the other values, there is always at least one integer value of the
+ * div, i.e., if one plus this sum is greater than or equal to
+ * the (absolute value) of the coefficent of the div in the constraints,
+ * then we can also simply drop the div.
+ *
+ * We skip divs that appear in equalities or in the definition of other divs.
+ * Divs that appear in the definition of other divs usually occur in at least
+ * 4 constraints, but the constraints may have been simplified.
+ *
+ * If any divs are left after these simple checks then we move on
+ * to more complicated cases in drop_more_redundant_divs.
+ */
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+ struct isl_basic_map *bmap)
+{
+ int i, j;
+ unsigned off;
+ int *pairs = NULL;
+ int n = 0;
+
+ if (!bmap)
+ goto error;
+ if (bmap->n_div == 0)
+ return bmap;
+
+ off = isl_space_dim(bmap->dim, isl_dim_all);
+ pairs = isl_calloc_array(bmap->ctx, int, bmap->n_div);
+ if (!pairs)
+ goto error;
+
+ for (i = 0; i < bmap->n_div; ++i) {
+ int pos, neg;
+ int last_pos, last_neg;
+ int redundant;
+ int defined;
+
+ defined = !isl_int_is_zero(bmap->div[i][0]);
+ for (j = i; j < bmap->n_div; ++j)
+ if (!isl_int_is_zero(bmap->div[j][1 + 1 + off + i]))
+ break;
+ if (j < bmap->n_div)
+ continue;
+ for (j = 0; j < bmap->n_eq; ++j)
+ if (!isl_int_is_zero(bmap->eq[j][1 + off + i]))
+ break;
+ if (j < bmap->n_eq)
+ continue;
+ ++n;
+ pos = neg = 0;
+ for (j = 0; j < bmap->n_ineq; ++j) {
+ if (isl_int_is_pos(bmap->ineq[j][1 + off + i])) {
+ last_pos = j;
+ ++pos;
+ }
+ if (isl_int_is_neg(bmap->ineq[j][1 + off + i])) {
+ last_neg = j;
+ ++neg;
+ }
+ }
+ pairs[i] = pos * neg;
+ if (pairs[i] == 0) {
+ for (j = bmap->n_ineq - 1; j >= 0; --j)
+ if (!isl_int_is_zero(bmap->ineq[j][1+off+i]))
+ isl_basic_map_drop_inequality(bmap, j);
+ bmap = isl_basic_map_drop_div(bmap, i);
+ free(pairs);
+ return isl_basic_map_drop_redundant_divs(bmap);
+ }
+ if (pairs[i] != 1)
+ continue;
+ if (!isl_seq_is_neg(bmap->ineq[last_pos] + 1,
+ bmap->ineq[last_neg] + 1,
+ off + bmap->n_div))
+ continue;
+
+ isl_int_add(bmap->ineq[last_pos][0],
+ bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+ isl_int_add_ui(bmap->ineq[last_pos][0],
+ bmap->ineq[last_pos][0], 1);
+ redundant = isl_int_ge(bmap->ineq[last_pos][0],
+ bmap->ineq[last_pos][1+off+i]);
+ isl_int_sub_ui(bmap->ineq[last_pos][0],
+ bmap->ineq[last_pos][0], 1);
+ isl_int_sub(bmap->ineq[last_pos][0],
+ bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+ if (!redundant) {
+ if (defined ||
+ !ok_to_set_div_from_bound(bmap, i, last_pos)) {
+ pairs[i] = 0;
+ --n;
+ continue;
+ }
+ bmap = set_div_from_lower_bound(bmap, i, last_pos);
+ bmap = isl_basic_map_simplify(bmap);
+ free(pairs);
+ return isl_basic_map_drop_redundant_divs(bmap);
+ }
+ if (last_pos > last_neg) {
+ isl_basic_map_drop_inequality(bmap, last_pos);
+ isl_basic_map_drop_inequality(bmap, last_neg);
+ } else {
+ isl_basic_map_drop_inequality(bmap, last_neg);
+ isl_basic_map_drop_inequality(bmap, last_pos);
+ }
+ bmap = isl_basic_map_drop_div(bmap, i);
+ free(pairs);
+ return isl_basic_map_drop_redundant_divs(bmap);
+ }
+
+ if (n > 0)
+ return coalesce_or_drop_more_redundant_divs(bmap, pairs, n);
+
+ free(pairs);
+ return bmap;
+error:
+ free(pairs);
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+ struct isl_basic_set *bset)
+{
+ return (struct isl_basic_set *)
+ isl_basic_map_drop_redundant_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_map_drop_redundant_divs(struct isl_map *map)
+{
+ int i;
+
+ if (!map)
+ return NULL;
+ for (i = 0; i < map->n; ++i) {
+ map->p[i] = isl_basic_map_drop_redundant_divs(map->p[i]);
+ if (!map->p[i])
+ goto error;
+ }
+ ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+ return map;
+error:
+ isl_map_free(map);
+ return NULL;
+}
+
+struct isl_set *isl_set_drop_redundant_divs(struct isl_set *set)
+{
+ return (struct isl_set *)
+ isl_map_drop_redundant_divs((struct isl_map *)set);
+}
More information about the llvm-commits
mailing list