isl_basic_set_opt: avoid invalid access on error path
[platform/upstream/isl.git] / isl_map.c
index a0ab7e3..c4636c1 100644 (file)
--- a/isl_map.c
+++ b/isl_map.c
@@ -1145,6 +1145,13 @@ 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)
 {
@@ -1620,6 +1627,9 @@ static __isl_give isl_basic_set *isl_basic_set_swap_vars(
        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);
@@ -2858,7 +2868,7 @@ static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        unsigned flags = 0;
-       struct isl_map *result;
+       isl_map *result;
        int i, j;
 
        if (!map1 || !map2)
@@ -2904,7 +2914,7 @@ static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
                                    isl_basic_map_copy(map1->p[i]),
                                    isl_basic_map_copy(map2->p[j]));
                        if (isl_basic_map_is_empty(part) < 0)
-                               goto error;
+                               part = isl_basic_map_free(part);
                        result = isl_map_add_basic_map(result, part);
                        if (!result)
                                goto error;
@@ -2990,6 +3000,8 @@ static __isl_give isl_basic_map *basic_map_space_reset(
 {
        isl_space *space;
 
+       if (!bmap)
+               return NULL;
        if (!isl_space_is_named_or_nested(bmap->dim, type))
                return bmap;
 
@@ -3040,6 +3052,7 @@ __isl_give isl_basic_map *isl_basic_map_insert_dims(
                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);
@@ -3062,7 +3075,7 @@ __isl_give isl_basic_map *isl_basic_map_add(__isl_take isl_basic_map *bmap,
                                        isl_basic_map_dim(bmap, type), n);
 }
 
-__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset,
+__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)
@@ -3215,6 +3228,8 @@ __isl_give isl_basic_map *isl_basic_map_move_dims(
        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);
@@ -4286,6 +4301,7 @@ struct isl_basic_set *isl_basic_map_underlying_set(
        bmap = isl_basic_map_finalize(bmap);
        return (struct isl_basic_set *)bmap;
 error:
+       isl_basic_map_free(bmap);
        return NULL;
 }
 
@@ -4348,10 +4364,12 @@ struct isl_basic_map *isl_basic_map_overlying_set(
                bmap = isl_basic_map_extend_constraints(bmap, 
                                                        0, 2 * like->n_div);
                for (i = 0; i < like->n_div; ++i) {
+                       if (!bmap)
+                               break;
                        if (isl_int_is_zero(bmap->div[i][0]))
                                continue;
                        if (isl_basic_map_add_div_constraints(bmap, i) < 0)
-                               goto error;
+                               bmap = isl_basic_map_free(bmap);
                }
        }
        isl_basic_map_free(like);
@@ -4519,6 +4537,18 @@ __isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset)
        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)
@@ -6026,6 +6056,8 @@ static int update_dim_opt(__isl_take isl_basic_set *dom,
        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);
@@ -6309,7 +6341,11 @@ static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
        if (bset->n_eq == 0)
                return isl_basic_set_lexmin(bset);
 
-       isl_basic_set_gauss(bset, NULL);
+       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);
 
        nparam = isl_basic_set_dim(bset, isl_dim_param);
        n_div = isl_basic_set_dim(bset, isl_dim_div);
@@ -6805,8 +6841,10 @@ struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
        for (i = 0; i < dim; ++i) {
                int j = isl_basic_map_alloc_equality(
                                            (struct isl_basic_map *)bset);
-               if (j < 0)
-                       goto error;
+               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);
@@ -7399,7 +7437,7 @@ int isl_basic_map_is_empty(struct isl_basic_map *bmap)
        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_F_ISSET(copy, ISL_BASIC_MAP_EMPTY);
+               empty = isl_basic_map_plain_is_empty(copy);
                isl_basic_map_free(copy);
                return empty;
        }
@@ -7555,11 +7593,11 @@ __isl_give isl_basic_set *isl_basic_set_expand_divs(
                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 - bset->n_div, 0,
-                                       2 * (div->n_row - bset->n_div));
+                                           div->n_row - n_div, 0,
+                                           2 * (div->n_row - n_div));
 
-       n_div = bset->n_div;
        for (i = n_div; i < div->n_row; ++i)
                if (isl_basic_set_alloc_div(bset) < 0)
                        goto error;
@@ -7611,7 +7649,7 @@ struct isl_basic_map *isl_basic_map_align_divs(
                struct isl_basic_map *dst, struct isl_basic_map *src)
 {
        int i;
-       unsigned total = isl_space_dim(src->dim, isl_dim_all);
+       unsigned total;
 
        if (!dst || !src)
                goto error;
@@ -7628,6 +7666,7 @@ struct isl_basic_map *isl_basic_map_align_divs(
                        src->n_div, 0, 2 * src->n_div);
        if (!dst)
                return NULL;
+       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) {
@@ -7815,19 +7854,20 @@ static enum isl_lp_result basic_set_maximal_difference_at(
        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);
-       if (!obj)
-               goto error;
        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(bmap1);
        isl_basic_map_free(bmap2);
+error2:
+       isl_basic_map_free(bmap1);
        return isl_lp_error;
 }
 
@@ -8165,13 +8205,13 @@ static int qsort_constraint_cmp(const void *p1, const void *p2)
        int l1, l2;
        unsigned size = isl_min(c1->size, c2->size);
 
-       l1 = isl_seq_last_non_zero(c1->c, size);
-       l2 = isl_seq_last_non_zero(c2->c, size);
+       l1 = isl_seq_last_non_zero(c1->c + 1, size);
+       l2 = isl_seq_last_non_zero(c2->c + 1, size);
 
        if (l1 != l2)
                return l1 - l2;
 
-       return isl_seq_cmp(c1->c, c2->c, size);
+       return isl_seq_cmp(c1->c + 1, c2->c + 1, size);
 }
 
 static struct isl_basic_map *isl_basic_map_sort_constraints(
@@ -8216,7 +8256,8 @@ struct isl_basic_map *isl_basic_map_normalize(struct isl_basic_map *bmap)
                return bmap;
        bmap = isl_basic_map_remove_redundancies(bmap);
        bmap = isl_basic_map_sort_constraints(bmap);
-       ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED);
+       if (bmap)
+               ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED);
        return bmap;
 }
 
@@ -9186,6 +9227,8 @@ int isl_set_dim_is_bounded(__isl_keep isl_set *set,
        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,
@@ -9224,6 +9267,44 @@ int isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set,
                                &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".
@@ -10320,6 +10401,9 @@ __isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap)
        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;
@@ -10398,6 +10482,9 @@ __isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *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);
@@ -10808,6 +10895,10 @@ __isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
  * 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,
@@ -10831,6 +10922,9 @@ __isl_give isl_basic_set *isl_basic_set_substitute(
        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);
 
@@ -11140,3 +11234,137 @@ error:
        isl_basic_set_free(res);
        return NULL;
 }
+
+/* Check if the range of "ma" is compatible with "set".
+ * Return -1 if anything is wrong.
+ */
+static int check_set_compatible_range_multi_aff(
+       __isl_keep isl_set *set, __isl_keep isl_multi_aff *ma)
+{
+       return check_space_compatible_range_multi_aff(set->dim, ma);
+}
+
+/* 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".
+ */
+static __isl_give isl_set *set_preimage_multi_aff(__isl_take isl_set *set,
+       __isl_take isl_multi_aff *ma)
+{
+       int i;
+
+       set = isl_set_cow(set);
+       ma = isl_multi_aff_align_divs(ma);
+       if (!set || !ma)
+               goto error;
+       if (check_set_compatible_range_multi_aff(set, ma) < 0)
+               goto error;
+
+       for (i = 0; i < set->n; ++i) {
+               set->p[i] = isl_basic_set_preimage_multi_aff(set->p[i],
+                                                       isl_multi_aff_copy(ma));
+               if (!set->p[i])
+                       goto error;
+       }
+
+       isl_space_free(set->dim);
+       set->dim = isl_multi_aff_get_domain_space(ma);
+       if (!set->dim)
+               goto error;
+
+       isl_multi_aff_free(ma);
+       if (set->n > 1)
+               ISL_F_CLR(set, ISL_MAP_DISJOINT);
+       ISL_F_CLR(set, ISL_SET_NORMALIZED);
+       return set;
+error:
+       isl_multi_aff_free(ma);
+       isl_set_free(set);
+       return NULL;
+}
+
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+       __isl_take isl_multi_aff *ma)
+{
+       if (!set || !ma)
+               goto error;
+
+       if (isl_space_match(set->dim, isl_dim_param, ma->space, isl_dim_param))
+               return set_preimage_multi_aff(set, ma);
+
+       if (!isl_space_has_named_params(set->dim) ||
+           !isl_space_has_named_params(ma->space))
+               isl_die(set->ctx, isl_error_invalid,
+                       "unaligned unnamed parameters", goto error);
+       set = isl_set_align_params(set, isl_multi_aff_get_space(ma));
+       ma = isl_multi_aff_align_params(ma, isl_set_get_space(set));
+
+       return set_preimage_multi_aff(set, ma);
+error:
+       isl_multi_aff_free(ma);
+       return isl_set_free(set);
+}
+
+/* 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".
+ */
+static __isl_give isl_set *set_preimage_pw_multi_aff(__isl_take isl_set *set,
+       __isl_take isl_pw_multi_aff *pma)
+{
+       int i;
+       isl_set *res;
+
+       if (!pma)
+               goto error;
+
+       if (pma->n == 0) {
+               isl_pw_multi_aff_free(pma);
+               res = isl_set_empty(isl_set_get_space(set));
+               isl_set_free(set);
+               return res;
+       }
+
+       res = isl_set_preimage_multi_aff(isl_set_copy(set),
+                                       isl_multi_aff_copy(pma->p[0].maff));
+       res = isl_set_intersect(res, isl_set_copy(pma->p[0].set));
+
+       for (i = 1; i < pma->n; ++i) {
+               isl_set *res_i;
+
+               res_i = isl_set_preimage_multi_aff(isl_set_copy(set),
+                                       isl_multi_aff_copy(pma->p[i].maff));
+               res_i = isl_set_intersect(res_i, isl_set_copy(pma->p[i].set));
+               res = isl_set_union(res, res_i);
+       }
+
+       isl_pw_multi_aff_free(pma);
+       isl_set_free(set);
+       return res;
+error:
+       isl_pw_multi_aff_free(pma);
+       isl_set_free(set);
+       return NULL;
+}
+
+__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set,
+       __isl_take isl_pw_multi_aff *pma)
+{
+       if (!set || !pma)
+               goto error;
+
+       if (isl_space_match(set->dim, isl_dim_param, pma->dim, isl_dim_param))
+               return set_preimage_pw_multi_aff(set, pma);
+
+       if (!isl_space_has_named_params(set->dim) ||
+           !isl_space_has_named_params(pma->dim))
+               isl_die(set->ctx, isl_error_invalid,
+                       "unaligned unnamed parameters", goto error);
+       set = isl_set_align_params(set, isl_pw_multi_aff_get_space(pma));
+       pma = isl_pw_multi_aff_align_params(pma, isl_set_get_space(set));
+
+       return set_preimage_pw_multi_aff(set, pma);
+error:
+       isl_pw_multi_aff_free(pma);
+       return isl_set_free(set);
+}