add isl_printer_print_double
[platform/upstream/isl.git] / isl_aff.c
index becf73b..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>
@@ -622,6 +624,7 @@ __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *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.
@@ -644,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)
@@ -2080,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)
 {
@@ -2206,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])
@@ -2272,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)
 {
@@ -2292,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.
  */
@@ -2834,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);
+}