proper implementation of isl_union_map_from_range
[platform/upstream/isl.git] / isl_local_space.c
index c13b73b..e051465 100644 (file)
@@ -8,9 +8,10 @@
  * 91893 Orsay, France
  */
 
+#include <isl_ctx_private.h>
 #include <isl_map_private.h>
 #include <isl_local_space_private.h>
-#include <isl_dim_private.h>
+#include <isl_space_private.h>
 #include <isl_mat_private.h>
 #include <isl/seq.h>
 
@@ -19,7 +20,7 @@ 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_dim *dim,
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
        __isl_take isl_mat *div)
 {
        isl_ctx *ctx;
@@ -28,7 +29,7 @@ __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_dim *dim,
        if (!dim)
                goto error;
 
-       ctx = isl_dim_get_ctx(dim);
+       ctx = isl_space_get_ctx(dim);
        ls = isl_calloc_type(ctx, struct isl_local_space);
        if (!ls)
                goto error;
@@ -39,12 +40,12 @@ __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_dim *dim,
 
        return ls;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_local_space_free(ls);
        return NULL;
 }
 
-__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_dim *dim,
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
        unsigned n_div)
 {
        isl_ctx *ctx;
@@ -54,14 +55,14 @@ __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_dim *dim,
        if (!dim)
                return NULL;
 
-       total = isl_dim_total(dim);
+       total = isl_space_dim(dim, isl_dim_all);
 
-       ctx = isl_dim_get_ctx(dim);
+       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_dim(__isl_take isl_dim *dim)
+__isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
 {
        return isl_local_space_alloc(dim, 0);
 }
@@ -80,7 +81,7 @@ __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_dim_copy(ls->dim),
+       return isl_local_space_alloc_div(isl_space_copy(ls->dim),
                                         isl_mat_copy(ls->div));
 
 }
@@ -104,7 +105,7 @@ void *isl_local_space_free(__isl_take isl_local_space *ls)
        if (--ls->ref > 0)
                return NULL;
 
-       isl_dim_free(ls->dim);
+       isl_space_free(ls->dim);
        isl_mat_free(ls->div);
 
        free(ls);
@@ -123,10 +124,15 @@ int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
        if (!ls1 || !ls2)
                return -1;
 
-       equal = isl_dim_equal(ls1->dim, ls2->dim);
+       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);
 }
 
@@ -138,14 +144,14 @@ int isl_local_space_dim(__isl_keep isl_local_space *ls,
        if (type == isl_dim_div)
                return ls->div->n_row;
        if (type == isl_dim_all)
-               return isl_dim_size(ls->dim, isl_dim_all) + ls->div->n_row;
-       return isl_dim_size(ls->dim, type);
+               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_dim *dim;
+       isl_space *dim;
 
        if (!ls)
                return 0;
@@ -164,7 +170,7 @@ unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
        enum isl_dim_type type, unsigned pos)
 {
-       return ls ? isl_dim_get_name(ls->dim, type, pos) : NULL;
+       return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
 }
 
 __isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
@@ -179,16 +185,20 @@ __isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
                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);
+
        bmap = isl_basic_map_from_local_space(isl_local_space_copy(ls));
        return isl_basic_map_div(bmap, pos);
 }
 
-__isl_give isl_dim *isl_local_space_get_dim(__isl_keep isl_local_space *ls)
+__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
 {
        if (!ls)
                return NULL;
 
-       return isl_dim_copy(ls->dim);
+       return isl_space_copy(ls->dim);
 }
 
 __isl_give isl_local_space *isl_local_space_set_dim_name(
@@ -198,13 +208,91 @@ __isl_give isl_local_space *isl_local_space_set_dim_name(
        ls = isl_local_space_cow(ls);
        if (!ls)
                return NULL;
-       ls->dim = isl_dim_set_name(ls->dim, type, pos, s);
+       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_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)
 {
@@ -361,39 +449,212 @@ __isl_give isl_local_space *isl_local_space_from_domain(
        ls = isl_local_space_cow(ls);
        if (!ls)
                return NULL;
-       ls->dim = isl_dim_from_domain(ls->dim);
+       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_dim(
+__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 (n == 0)
+       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;
+
+       ls = isl_local_space_cow(ls);
+       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,
+                       "dimensions 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;
+                       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;
+}
+
+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;
 
-       pos = isl_local_space_offset(ls, type);
-       pos += isl_local_space_dim(ls, type);
+       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->div = isl_mat_insert_zero_cols(ls->div, 1 + pos, n);
+       ls = isl_local_space_cow(ls);
+       if (!ls)
+               return NULL;
 
        if (type == isl_dim_div) {
-               ls->div = isl_mat_add_zero_rows(ls->div, n);
+               ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
        } else {
-               ls->dim = isl_dim_add(ls->dim, type, n);
+               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;
+}