Merge branch 'maint'
[platform/upstream/isl.git] / isl_dim.c
index 656839b..6aa67f0 100644 (file)
--- a/isl_dim.c
+++ b/isl_dim.c
@@ -13,6 +13,7 @@
 #include <stdlib.h>
 #include <isl_dim_private.h>
 #include "isl_name.h"
+#include <isl_reordering.h>
 
 isl_ctx *isl_dim_get_ctx(__isl_keep isl_dim *dim)
 {
@@ -118,7 +119,8 @@ static struct isl_dim *set_name(struct isl_dim *dim,
                goto error;
 
        pos = global_pos(dim, type, pos);
-       isl_assert(ctx, pos != isl_dim_total(dim), goto error);
+       if (pos == isl_dim_total(dim))
+               goto error;
 
        if (pos >= dim->n_name) {
                if (!name)
@@ -167,6 +169,7 @@ static unsigned n(struct isl_dim *dim, enum isl_dim_type 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;
        }
 }
@@ -344,6 +347,7 @@ struct isl_dim *isl_dim_set_name(struct isl_dim *dim,
                return NULL;
        if (!name_ok(dim->ctx, s))
                goto error;
+       isl_name_free(dim->ctx, get_name(dim, type, pos));
        name = isl_name_get(dim->ctx, s);
        if (!name)
                goto error;
@@ -489,16 +493,42 @@ struct isl_dim *isl_dim_add(struct isl_dim *dim, enum isl_dim_type type,
        dim = isl_dim_reset(dim, type);
        switch (type) {
        case isl_dim_param:
-               return isl_dim_extend(dim,
+               dim = isl_dim_extend(dim,
                                        dim->nparam + n, dim->n_in, dim->n_out);
+               if (dim && dim->nested[0] &&
+                   !(dim->nested[0] = isl_dim_add(dim->nested[0],
+                                                   isl_dim_param, n)))
+                       goto error;
+               if (dim && dim->nested[1] &&
+                   !(dim->nested[1] = isl_dim_add(dim->nested[1],
+                                                   isl_dim_param, n)))
+                       goto error;
+               return dim;
        case isl_dim_in:
                return isl_dim_extend(dim,
                                        dim->nparam, dim->n_in + n, dim->n_out);
        case isl_dim_out:
                return isl_dim_extend(dim,
                                        dim->nparam, dim->n_in, dim->n_out + n);
+       default:
+               isl_die(dim->ctx, isl_error_invalid,
+                       "cannot add dimensions of specified type", goto error);
+       }
+error:
+       isl_dim_free(dim);
+       return NULL;
+}
+
+static int valid_dim_type(enum isl_dim_type type)
+{
+       switch (type) {
+       case isl_dim_param:
+       case isl_dim_in:
+       case isl_dim_out:
+               return 1;
+       default:
+               return 0;
        }
-       return dim;
 }
 
 __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
@@ -511,6 +541,11 @@ __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
        if (n == 0)
                return isl_dim_reset(dim, type);
 
+       if (!valid_dim_type(type))
+               isl_die(dim->ctx, isl_error_invalid,
+                       "cannot insert dimensions of specified type",
+                       goto error);
+
        isl_assert(dim->ctx, pos <= isl_dim_size(dim, type), goto error);
 
        dim = isl_dim_cow(dim);
@@ -520,7 +555,8 @@ __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
        if (dim->names) {
                enum isl_dim_type t;
                int off;
-               int size[3];
+               int s[3];
+               int *size = s - isl_dim_param;
                names = isl_calloc_array(dim->ctx, struct isl_name *,
                                     dim->nparam + dim->n_in + dim->n_out + n);
                if (!names)
@@ -548,6 +584,7 @@ __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
        case isl_dim_param:     dim->nparam += n; break;
        case isl_dim_in:        dim->n_in += n; break;
        case isl_dim_out:       dim->n_out += n; break;
+       default:                ;
        }
        dim = isl_dim_reset(dim, type);
 
@@ -561,6 +598,8 @@ __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
        enum isl_dim_type dst_type, unsigned dst_pos,
        enum isl_dim_type src_type, unsigned src_pos, unsigned n)
 {
+       int i;
+
        if (!dim)
                return NULL;
        if (n == 0)
@@ -585,7 +624,8 @@ __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
                struct isl_name **names;
                enum isl_dim_type t;
                int off;
-               int size[3];
+               int s[3];
+               int *size = s - isl_dim_param;
                names = isl_calloc_array(dim->ctx, struct isl_name *,
                                         dim->nparam + dim->n_in + dim->n_out);
                if (!names)
@@ -623,12 +663,26 @@ __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
        case isl_dim_param:     dim->nparam += n; break;
        case isl_dim_in:        dim->n_in += n; break;
        case isl_dim_out:       dim->n_out += n; break;
+       default:                ;
        }
 
        switch (src_type) {
        case isl_dim_param:     dim->nparam -= n; break;
        case isl_dim_in:        dim->n_in -= n; break;
        case isl_dim_out:       dim->n_out -= n; break;
+       default:                ;
+       }
+
+       if (dst_type != isl_dim_param && src_type != isl_dim_param)
+               return dim;
+
+       for (i = 0; i < 2; ++i) {
+               if (!dim->nested[i])
+                       continue;
+               dim->nested[i] = isl_dim_replace(dim->nested[i],
+                                                isl_dim_param, dim);
+               if (!dim->nested[i])
+                       goto error;
        }
 
        return dim;
@@ -706,7 +760,34 @@ error:
        return NULL;
 }
 
-struct isl_dim *isl_dim_map(struct isl_dim *dim)
+__isl_give isl_dim *isl_dim_range_product(__isl_take isl_dim *left,
+       __isl_take isl_dim *right)
+{
+       isl_dim *dom, *ran1, *ran2, *nest;
+
+       if (!left || !right)
+               goto error;
+
+       isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+                       goto error);
+       if (!isl_dim_match(left, isl_dim_in, right, isl_dim_in))
+               isl_die(left->ctx, isl_error_invalid,
+                       "domains need to match", goto error);
+
+       dom = isl_dim_domain(isl_dim_copy(left));
+
+       ran1 = isl_dim_range(left);
+       ran2 = isl_dim_range(right);
+       nest = isl_dim_wrap(isl_dim_join(isl_dim_reverse(ran1), ran2));
+
+       return isl_dim_join(isl_dim_reverse(dom), nest);
+error:
+       isl_dim_free(left);
+       isl_dim_free(right);
+       return NULL;
+}
+
+__isl_give isl_dim *isl_dim_map_from_set(__isl_take isl_dim *dim)
 {
        struct isl_name **names = NULL;
 
@@ -812,9 +893,13 @@ struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
        if (!dim)
                return NULL;
 
-       if (n == 0)
+       if (num == 0)
                return isl_dim_reset(dim, type);
 
+       if (!valid_dim_type(type))
+               isl_die(dim->ctx, isl_error_invalid,
+                       "cannot drop dimensions of specified type", goto error);
+
        isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
        dim = isl_dim_cow(dim);
        if (!dim)
@@ -834,7 +919,7 @@ struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
                case isl_dim_in:
                        get_names(dim, isl_dim_out, 0, dim->n_out,
                                dim->names + offset(dim, isl_dim_out) - num);
-               case isl_dim_out:
+               default:
                        ;
                }
                dim->n_name -= num;
@@ -843,8 +928,19 @@ struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
        case isl_dim_param:     dim->nparam -= num; break;
        case isl_dim_in:        dim->n_in -= num; break;
        case isl_dim_out:       dim->n_out -= num; break;
+       default:                ;
        }
        dim = isl_dim_reset(dim, type);
+       if (type == isl_dim_param) {
+               if (dim && dim->nested[0] &&
+                   !(dim->nested[0] = isl_dim_drop(dim->nested[0],
+                                                   isl_dim_param, first, num)))
+                       goto error;
+               if (dim && dim->nested[1] &&
+                   !(dim->nested[1] = isl_dim_drop(dim->nested[1],
+                                                   isl_dim_param, first, num)))
+                       goto error;
+       }
        return dim;
 error:
        isl_dim_free(dim);
@@ -875,6 +971,11 @@ struct isl_dim *isl_dim_domain(struct isl_dim *dim)
        return isl_dim_reverse(dim);
 }
 
+__isl_give isl_dim *isl_dim_from_domain(__isl_take isl_dim *dim)
+{
+       return isl_dim_reverse(dim);
+}
+
 struct isl_dim *isl_dim_range(struct isl_dim *dim)
 {
        if (!dim)
@@ -882,6 +983,11 @@ struct isl_dim *isl_dim_range(struct isl_dim *dim)
        return isl_dim_drop_inputs(dim, 0, dim->n_in);
 }
 
+__isl_give isl_dim *isl_dim_from_range(__isl_take isl_dim *dim)
+{
+       return dim;
+}
+
 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
 {
        dim = isl_dim_cow(dim);
@@ -923,7 +1029,7 @@ struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
 
 unsigned isl_dim_total(struct isl_dim *dim)
 {
-       return dim->nparam + dim->n_in + dim->n_out;
+       return dim ? dim->nparam + dim->n_in + dim->n_out : 0;
 }
 
 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
@@ -953,13 +1059,13 @@ static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
 
        for (i = 0; i < dim->nparam; ++i) {
                name = get_name(dim, isl_dim_param, i);
-               hash = isl_hash_builtin(hash, name);
+               hash = isl_hash_name(hash, name);
        }
 
        name = tuple_name(dim, isl_dim_in);
-       hash = isl_hash_builtin(hash, name);
+       hash = isl_hash_name(hash, name);
        name = tuple_name(dim, isl_dim_out);
-       hash = isl_hash_builtin(hash, name);
+       hash = isl_hash_name(hash, name);
 
        hash = isl_hash_dim(hash, dim->nested[0]);
        hash = isl_hash_dim(hash, dim->nested[1]);
@@ -1048,6 +1154,17 @@ int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
        return 0;
 }
 
+int isl_dim_may_be_set(__isl_keep isl_dim *dim)
+{
+       if (!dim)
+               return -1;
+       if (isl_dim_size(dim, isl_dim_in) != 0)
+               return 0;
+       if (isl_dim_is_named_or_nested(dim, isl_dim_in))
+               return 0;
+       return 1;
+}
+
 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
        enum isl_dim_type type)
 {
@@ -1073,10 +1190,156 @@ __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim)
        if (!dim->nested[0] && !dim->nested[1])
                return dim;
 
-       isl_dim_free(dim->nested[0]);
-       dim->nested[0] = NULL;
-       isl_dim_free(dim->nested[1]);
-       dim->nested[1] = NULL;
+       if (dim->nested[0])
+               dim = isl_dim_reset(dim, isl_dim_in);
+       if (dim && dim->nested[1])
+               dim = isl_dim_reset(dim, isl_dim_out);
+
+       return dim;
+}
+
+__isl_give isl_dim *isl_dim_flatten_range(__isl_take isl_dim *dim)
+{
+       if (!dim)
+               return NULL;
+       if (!dim->nested[1])
+               return dim;
+
+       return isl_dim_reset(dim, isl_dim_out);
+}
+
+/* Replace the dimensions of the given type of dst by those of src.
+ */
+__isl_give isl_dim *isl_dim_replace(__isl_take isl_dim *dst,
+       enum isl_dim_type type, __isl_keep isl_dim *src)
+{
+       dst = isl_dim_cow(dst);
+
+       if (!dst || !src)
+               goto error;
+
+       dst = isl_dim_drop(dst, type, 0, isl_dim_size(dst, type));
+       dst = isl_dim_add(dst, type, isl_dim_size(src, type));
+       dst = copy_names(dst, type, 0, src, type);
+
+       if (dst && type == isl_dim_param) {
+               int i;
+               for (i = 0; i <= 1; ++i) {
+                       if (!dst->nested[i])
+                               continue;
+                       dst->nested[i] = isl_dim_replace(dst->nested[i],
+                                                        type, src);
+                       if (!dst->nested[i])
+                               goto error;
+               }
+       }
+
+       return dst;
+error:
+       isl_dim_free(dst);
+       return NULL;
+}
+
+/* Given a dimension specification "dim" of a set, create a dimension
+ * specification for the lift of the set.  In particular, the result
+ * is of the form [dim -> local[..]], with n_local variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_dim *isl_dim_lift(__isl_take isl_dim *dim, unsigned n_local)
+{
+       isl_dim *local_dim;
+
+       if (!dim)
+               return NULL;
+
+       local_dim = isl_dim_dup(dim);
+       local_dim = isl_dim_drop(local_dim, isl_dim_set, 0, dim->n_out);
+       local_dim = isl_dim_add(local_dim, isl_dim_set, n_local);
+       local_dim = isl_dim_set_tuple_name(local_dim, isl_dim_set, "local");
+       dim = isl_dim_join(isl_dim_from_domain(dim),
+                           isl_dim_from_range(local_dim));
+       dim = isl_dim_wrap(dim);
+       dim = isl_dim_set_tuple_name(dim, isl_dim_set, "lifted");
 
        return dim;
 }
+
+int isl_dim_can_zip(__isl_keep isl_dim *dim)
+{
+       if (!dim)
+               return -1;
+
+       return dim->nested[0] && dim->nested[1];
+}
+
+__isl_give isl_dim *isl_dim_zip(__isl_take isl_dim *dim)
+{
+       isl_dim *dom, *ran;
+       isl_dim *dom_dom, *dom_ran, *ran_dom, *ran_ran;
+
+       if (!isl_dim_can_zip(dim))
+               isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
+                       goto error);
+
+       if (!dim)
+               return 0;
+       dom = isl_dim_unwrap(isl_dim_domain(isl_dim_copy(dim)));
+       ran = isl_dim_unwrap(isl_dim_range(dim));
+       dom_dom = isl_dim_domain(isl_dim_copy(dom));
+       dom_ran = isl_dim_range(dom);
+       ran_dom = isl_dim_domain(isl_dim_copy(ran));
+       ran_ran = isl_dim_range(ran);
+       dom = isl_dim_join(isl_dim_from_domain(dom_dom),
+                          isl_dim_from_range(ran_dom));
+       ran = isl_dim_join(isl_dim_from_domain(dom_ran),
+                          isl_dim_from_range(ran_ran));
+       return isl_dim_join(isl_dim_from_domain(isl_dim_wrap(dom)),
+                           isl_dim_from_range(isl_dim_wrap(ran)));
+error:
+       isl_dim_free(dim);
+       return NULL;
+}
+
+int isl_dim_has_named_params(__isl_keep isl_dim *dim)
+{
+       int i;
+       unsigned off;
+
+       if (!dim)
+               return -1;
+       if (dim->nparam == 0)
+               return 1;
+       off = isl_dim_offset(dim, isl_dim_param);
+       if (off + dim->nparam > dim->n_name)
+               return 0;
+       for (i = 0; i < dim->nparam; ++i)
+               if (!dim->names[off + i])
+                       return 0;
+       return 1;
+}
+
+/* Align the initial parameters of dim1 to match the order in dim2.
+ */
+__isl_give isl_dim *isl_dim_align_params(__isl_take isl_dim *dim1,
+       __isl_take isl_dim *dim2)
+{
+       isl_reordering *exp;
+
+       if (!isl_dim_has_named_params(dim1) || !isl_dim_has_named_params(dim2))
+               isl_die(isl_dim_get_ctx(dim1), isl_error_invalid,
+                       "parameter alignment requires named parameters",
+                       goto error);
+
+       exp = isl_parameter_alignment_reordering(dim1, dim2);
+       isl_dim_free(dim1);
+       isl_dim_free(dim2);
+       if (!exp)
+               return NULL;
+       dim1 = isl_dim_copy(exp->dim);
+       isl_reordering_free(exp);
+       return dim1;
+error:
+       isl_dim_free(dim1);
+       isl_dim_free(dim2);
+       return NULL;
+}