Merge branch 'maint'
[platform/upstream/isl.git] / isl_aff.c
index 07c6236..b7d510f 100644 (file)
--- a/isl_aff.c
+++ b/isl_aff.c
@@ -12,7 +12,9 @@
  */
 
 #include <isl_ctx_private.h>
+#define ISL_DIM_H
 #include <isl_map_private.h>
+#include <isl_union_map_private.h>
 #include <isl_aff_private.h>
 #include <isl_space_private.h>
 #include <isl_local_space_private.h>
@@ -616,11 +618,13 @@ __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)
        aff->v = isl_vec_normalize(aff->v);
        if (!aff->v)
                return isl_aff_free(aff);
+       aff = isl_aff_remove_unused_divs(aff);
        return aff;
 }
 
 /* Given f, return floor(f).
  * If f is an integer expression, then just return f.
+ * If f is a constant, then return the constant floor(f).
  * Otherwise, if f = g/m, write g = q m + r,
  * create a new div d = [r/m] and return the expression q + d.
  * The coefficients in r are taken to lie between -m/2 and m/2.
@@ -643,6 +647,15 @@ __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
                return NULL;
 
        aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       if (isl_aff_is_cst(aff)) {
+               isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
+               isl_int_set_si(aff->v->el[0], 1);
+               return aff;
+       }
+
        div = isl_vec_copy(aff->v);
        div = isl_vec_cow(div);
        if (!div)
@@ -1878,20 +1891,34 @@ __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff)
        return pwaff;
 }
 
+/* Assuming that "cond1" and "cond2" are disjoint,
+ * return an affine expression that is equal to pwaff1 on cond1
+ * and to pwaff2 on cond2.
+ */
+static __isl_give isl_pw_aff *isl_pw_aff_select(
+       __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1,
+       __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2)
+{
+       pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1);
+       pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2);
+
+       return isl_pw_aff_add_disjoint(pwaff1, pwaff2);
+}
+
 /* Return an affine expression that is equal to pwaff_true for elements
- * in "cond" and to pwaff_false for elements not in "cond".
+ * where "cond" is non-zero and to pwaff_false for elements where "cond"
+ * is zero.
  * That is, return cond ? pwaff_true : pwaff_false;
  */
-__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_set *cond,
+__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond,
        __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false)
 {
-       isl_set *comp;
-
-       comp = isl_set_complement(isl_set_copy(cond));
-       pwaff_true = isl_pw_aff_intersect_domain(pwaff_true, cond);
-       pwaff_false = isl_pw_aff_intersect_domain(pwaff_false, comp);
+       isl_set *cond_true, *cond_false;
 
-       return isl_pw_aff_add_disjoint(pwaff_true, pwaff_false);
+       cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond));
+       cond_false = isl_pw_aff_zero_set(cond);
+       return isl_pw_aff_select(cond_true, pwaff_true,
+                                cond_false, pwaff_false);
 }
 
 int isl_aff_is_cst(__isl_keep isl_aff *aff)
@@ -1980,10 +2007,14 @@ static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1,
        __isl_take isl_pw_aff *pwaff2)
 {
        isl_set *le;
+       isl_set *dom;
 
+       dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
+                               isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
        le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1),
                                isl_pw_aff_copy(pwaff2));
-       return isl_pw_aff_cond(le, pwaff1, pwaff2);
+       dom = isl_set_subtract(dom, isl_set_copy(le));
+       return isl_pw_aff_select(le, pwaff1, dom, pwaff2);
 }
 
 __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,
@@ -1995,11 +2026,15 @@ __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,
 static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1,
        __isl_take isl_pw_aff *pwaff2)
 {
-       isl_set *le;
+       isl_set *ge;
+       isl_set *dom;
 
-       le = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1),
+       dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
+                               isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
+       ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1),
                                isl_pw_aff_copy(pwaff2));
-       return isl_pw_aff_cond(le, pwaff1, pwaff2);
+       dom = isl_set_subtract(dom, isl_set_copy(ge));
+       return isl_pw_aff_select(ge, pwaff1, dom, pwaff2);
 }
 
 __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1,
@@ -2057,6 +2092,50 @@ __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list)
 
 #include <isl_multi_templ.c>
 
+/* Construct an isl_multi_aff in the given space with value zero in
+ * each of the output dimensions.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_zero(__isl_take isl_space *space)
+{
+       int n;
+       isl_multi_aff *ma;
+
+       if (!space)
+               return NULL;
+
+       n = isl_space_dim(space , isl_dim_out);
+       ma = isl_multi_aff_alloc(isl_space_copy(space));
+
+       if (!n)
+               isl_space_free(space);
+       else {
+               int i;
+               isl_local_space *ls;
+               isl_aff *aff;
+
+               space = isl_space_domain(space);
+               ls = isl_local_space_from_space(space);
+               aff = isl_aff_zero_on_domain(ls);
+
+               for (i = 0; i < n; ++i)
+                       ma = isl_multi_aff_set_aff(ma, i, isl_aff_copy(aff));
+
+               isl_aff_free(aff);
+       }
+
+       return ma;
+}
+
+/* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe
+ * domain.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
+       __isl_take isl_multi_aff *ma)
+{
+       isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma));
+       return isl_pw_multi_aff_alloc(dom, ma);
+}
+
 __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *maff1,
        __isl_take isl_multi_aff *maff2)
 {
@@ -2183,6 +2262,9 @@ __isl_give isl_multi_aff *isl_multi_aff_set_dim_name(
        maff->space = isl_space_set_dim_name(maff->space, type, pos, s);
        if (!maff->space)
                return isl_multi_aff_free(maff);
+
+       if (type == isl_dim_out)
+               return maff;
        for (i = 0; i < maff->n; ++i) {
                maff->p[i] = isl_aff_set_dim_name(maff->p[i], type, pos, s);
                if (!maff->p[i])
@@ -2249,6 +2331,18 @@ __isl_give isl_multi_aff *isl_multi_aff_drop_dims(__isl_take isl_multi_aff *maff
 
 #include <isl_pw_templ.c>
 
+#undef UNION
+#define UNION isl_union_pw_multi_aff
+#undef PART
+#define PART isl_pw_multi_aff
+#undef PARTS
+#define PARTS pw_multi_aff
+#define ALIGN_DOMAIN
+
+#define NO_EVAL
+
+#include <isl_union_templ.c>
+
 static __isl_give isl_pw_multi_aff *pw_multi_aff_add(
        __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
 {
@@ -2269,7 +2363,7 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
        return isl_pw_multi_aff_union_add_(pma1, pma2);
 }
 
-/* Construct a map mapping the domain the piecewise multi-affine expression
+/* Construct a map mapping the domain of the piecewise multi-affine expression
  * to its range, with each dimension in the range equated to the
  * corresponding affine expression on its cell.
  */
@@ -2481,6 +2575,24 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)
        return isl_pw_multi_aff_from_map(set);
 }
 
+/* Return the piecewise affine expression "set ? 1 : 0".
+ */
+__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
+{
+       isl_pw_aff *pa;
+       isl_space *space = isl_set_get_space(set);
+       isl_local_space *ls = isl_local_space_from_space(space);
+       isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls));
+       isl_aff *one = isl_aff_zero_on_domain(ls);
+
+       one = isl_aff_add_constant_si(one, 1);
+       pa = isl_pw_aff_alloc(isl_set_copy(set), one);
+       set = isl_set_complement(set);
+       pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero));
+
+       return pa;
+}
+
 /* Plug in "subs" for dimension "type", "pos" of "aff".
  *
  * Let i be the dimension to replace and let "subs" be of the form
@@ -2793,3 +2905,260 @@ __isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(
 
        return pa;
 }
+
+/* Return an isl_pw_multi_aff with the given "set" as domain and
+ * an unnamed zero-dimensional range.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(
+       __isl_take isl_set *set)
+{
+       isl_multi_aff *ma;
+       isl_space *space;
+
+       space = isl_set_get_space(set);
+       space = isl_space_from_domain(space);
+       ma = isl_multi_aff_zero(space);
+       return isl_pw_multi_aff_alloc(set, ma);
+}
+
+/* Add an isl_pw_multi_aff with the given "set" as domain and
+ * an unnamed zero-dimensional range to *user.
+ */
+static int add_pw_multi_aff_from_domain(__isl_take isl_set *set, void *user)
+{
+       isl_union_pw_multi_aff **upma = user;
+       isl_pw_multi_aff *pma;
+
+       pma = isl_pw_multi_aff_from_domain(set);
+       *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+       return 0;
+}
+
+/* Return an isl_union_pw_multi_aff with the given "uset" as domain and
+ * an unnamed zero-dimensional range.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain(
+       __isl_take isl_union_set *uset)
+{
+       isl_space *space;
+       isl_union_pw_multi_aff *upma;
+
+       if (!uset)
+               return NULL;
+
+       space = isl_union_set_get_space(uset);
+       upma = isl_union_pw_multi_aff_empty(space);
+
+       if (isl_union_set_foreach_set(uset,
+                                   &add_pw_multi_aff_from_domain, &upma) < 0)
+               goto error;
+
+       isl_union_set_free(uset);
+       return upma;
+error:
+       isl_union_set_free(uset);
+       isl_union_pw_multi_aff_free(upma);
+       return NULL;
+}
+
+/* Convert "pma" to an isl_map and add it to *umap.
+ */
+static int map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+       isl_union_map **umap = user;
+       isl_map *map;
+
+       map = isl_map_from_pw_multi_aff(pma);
+       *umap = isl_union_map_add_map(*umap, map);
+
+       return 0;
+}
+
+/* Construct a union map mapping the domain of the union
+ * piecewise multi-affine expression to its range, with each dimension
+ * in the range equated to the corresponding affine expression on its cell.
+ */
+__isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff(
+       __isl_take isl_union_pw_multi_aff *upma)
+{
+       isl_space *space;
+       isl_union_map *umap;
+
+       if (!upma)
+               return NULL;
+
+       space = isl_union_pw_multi_aff_get_space(upma);
+       umap = isl_union_map_empty(space);
+
+       if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+                                       &map_from_pw_multi_aff, &umap) < 0)
+               goto error;
+
+       isl_union_pw_multi_aff_free(upma);
+       return umap;
+error:
+       isl_union_pw_multi_aff_free(upma);
+       isl_union_map_free(umap);
+       return NULL;
+}
+
+/* Local data for bin_entry and the callback "fn".
+ */
+struct isl_union_pw_multi_aff_bin_data {
+       isl_union_pw_multi_aff *upma2;
+       isl_union_pw_multi_aff *res;
+       isl_pw_multi_aff *pma;
+       int (*fn)(void **entry, void *user);
+};
+
+/* Given an isl_pw_multi_aff from upma1, store it in data->pma
+ * and call data->fn for each isl_pw_multi_aff in data->upma2.
+ */
+static int bin_entry(void **entry, void *user)
+{
+       struct isl_union_pw_multi_aff_bin_data *data = user;
+       isl_pw_multi_aff *pma = *entry;
+
+       data->pma = pma;
+       if (isl_hash_table_foreach(data->upma2->dim->ctx, &data->upma2->table,
+                                  data->fn, data) < 0)
+               return -1;
+
+       return 0;
+}
+
+/* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2".
+ * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is
+ * passed as user field) and the isl_pw_multi_aff from upma2 is available
+ * as *entry.  The callback should adjust data->res if desired.
+ */
+static __isl_give isl_union_pw_multi_aff *bin_op(
+       __isl_take isl_union_pw_multi_aff *upma1,
+       __isl_take isl_union_pw_multi_aff *upma2,
+       int (*fn)(void **entry, void *user))
+{
+       isl_space *space;
+       struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn };
+
+       space = isl_union_pw_multi_aff_get_space(upma2);
+       upma1 = isl_union_pw_multi_aff_align_params(upma1, space);
+       space = isl_union_pw_multi_aff_get_space(upma1);
+       upma2 = isl_union_pw_multi_aff_align_params(upma2, space);
+
+       if (!upma1 || !upma2)
+               goto error;
+
+       data.upma2 = upma2;
+       data.res = isl_union_pw_multi_aff_alloc(isl_space_copy(upma1->dim),
+                                      upma1->table.n);
+       if (isl_hash_table_foreach(upma1->dim->ctx, &upma1->table,
+                                  &bin_entry, &data) < 0)
+               goto error;
+
+       isl_union_pw_multi_aff_free(upma1);
+       isl_union_pw_multi_aff_free(upma2);
+       return data.res;
+error:
+       isl_union_pw_multi_aff_free(upma1);
+       isl_union_pw_multi_aff_free(upma2);
+       isl_union_pw_multi_aff_free(data.res);
+       return NULL;
+}
+
+/* Given two isl_multi_affs A -> B and C -> D,
+ * construct an isl_multi_aff (A * C) -> (B, D).
+ */
+__isl_give isl_multi_aff *isl_multi_aff_flat_range_product(
+       __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
+{
+       int i, n1, n2;
+       isl_aff *aff;
+       isl_space *space;
+       isl_multi_aff *res;
+
+       if (!ma1 || !ma2)
+               goto error;
+
+       space = isl_space_range_product(isl_multi_aff_get_space(ma1),
+                                       isl_multi_aff_get_space(ma2));
+       space = isl_space_flatten_range(space);
+       res = isl_multi_aff_alloc(space);
+
+       n1 = isl_multi_aff_dim(ma1, isl_dim_out);
+       n2 = isl_multi_aff_dim(ma2, isl_dim_out);
+
+       for (i = 0; i < n1; ++i) {
+               aff = isl_multi_aff_get_aff(ma1, i);
+               res = isl_multi_aff_set_aff(res, i, aff);
+       }
+
+       for (i = 0; i < n2; ++i) {
+               aff = isl_multi_aff_get_aff(ma2, i);
+               res = isl_multi_aff_set_aff(res, n1 + i, aff);
+       }
+
+       isl_multi_aff_free(ma1);
+       isl_multi_aff_free(ma2);
+       return res;
+error:
+       isl_multi_aff_free(ma1);
+       isl_multi_aff_free(ma2);
+       return NULL;
+}
+
+/* Given two aligned isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> (B, D).
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_flat_range_product(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       isl_space *space;
+
+       space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),
+                                       isl_pw_multi_aff_get_space(pma2));
+       space = isl_space_flatten_range(space);
+       return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,
+                                           &isl_multi_aff_flat_range_product);
+}
+
+/* Given two isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> (B, D).
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product(
+       __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+       return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+                                           &pw_multi_aff_flat_range_product);
+}
+
+/* If data->pma and *entry have the same domain space, then compute
+ * their flat range product and the result to data->res.
+ */
+static int flat_range_product_entry(void **entry, void *user)
+{
+       struct isl_union_pw_multi_aff_bin_data *data = user;
+       isl_pw_multi_aff *pma2 = *entry;
+
+       if (!isl_space_tuple_match(data->pma->dim, isl_dim_in,
+                                pma2->dim, isl_dim_in))
+               return 0;
+
+       pma2 = isl_pw_multi_aff_flat_range_product(
+                                       isl_pw_multi_aff_copy(data->pma),
+                                       isl_pw_multi_aff_copy(pma2));
+
+       data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);
+
+       return 0;
+}
+
+/* Given two isl_union_pw_multi_affs A -> B and C -> D,
+ * construct an isl_union_pw_multi_aff (A * C) -> (B, D).
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(
+       __isl_take isl_union_pw_multi_aff *upma1,
+       __isl_take isl_union_pw_multi_aff *upma2)
+{
+       return bin_op(upma1, upma2, &flat_range_product_entry);
+}