isl_basic_set_opt: avoid invalid access on error path
[platform/upstream/isl.git] / isl_aff.c
index 79fd8d5..e9d7286 100644 (file)
--- a/isl_aff.c
+++ b/isl_aff.c
@@ -758,7 +758,7 @@ static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff)
                        continue;
                ls = isl_local_space_copy(aff->ls);
                ls = isl_local_space_substitute_seq(ls, isl_dim_div, i,
-                                           aff->ls->div->row[i], len, i + 1);
+                               aff->ls->div->row[i], len, i + 1, n - (i + 1));
                vec = isl_vec_copy(aff->v);
                vec = isl_vec_cow(vec);
                if (!ls || !vec)
@@ -785,6 +785,50 @@ error:
        return isl_aff_free(aff);
 }
 
+/* Look for any divs j that appear with a unit coefficient inside
+ * the definitions of other divs i and plug them into the definitions
+ * of the divs i.
+ *
+ * In particular, an expression of the form
+ *
+ *     floor((f(..) + floor(g(..)/n))/m)
+ *
+ * is simplified to
+ *
+ *     floor((n * f(..) + g(..))/(n * m))
+ *
+ * This simplification is correct because we can move the expression
+ * f(..) into the inner floor in the original expression to obtain
+ *
+ *     floor(floor((n * f(..) + g(..))/n)/m)
+ *
+ * from which we can derive the simplified expression.
+ */
+static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff)
+{
+       int i, j, n;
+       int off;
+
+       if (!aff)
+               return NULL;
+
+       n = isl_local_space_dim(aff->ls, isl_dim_div);
+       off = isl_local_space_offset(aff->ls, isl_dim_div);
+       for (i = 1; i < n; ++i) {
+               for (j = 0; j < i; ++j) {
+                       if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j]))
+                               continue;
+                       aff->ls = isl_local_space_substitute_seq(aff->ls,
+                               isl_dim_div, j, aff->ls->div->row[j],
+                               aff->v->size, i, 1);
+                       if (!aff->ls)
+                               return isl_aff_free(aff);
+               }
+       }
+
+       return aff;
+}
+
 /* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL.
  *
  * Even though this function is only called on isl_affs with a single
@@ -889,6 +933,7 @@ __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)
        if (!aff->v)
                return isl_aff_free(aff);
        aff = plug_in_integral_divs(aff);
+       aff = plug_in_unit_divs(aff);
        aff = sort_divs(aff);
        aff = isl_aff_remove_unused_divs(aff);
        return aff;
@@ -955,6 +1000,8 @@ __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
        isl_int_set_si(aff->v->el[0], 1);
        isl_int_set_si(aff->v->el[size], 1);
 
+       aff = isl_aff_normalize(aff);
+
        return aff;
 }
 
@@ -994,7 +1041,13 @@ __isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m)
 
 /* Given f, return ceil(f).
  * If f is an integer expression, then just return f.
- * Otherwise, create a new div d = [-f] and return the expression -d.
+ * Otherwise, let f be the expression
+ *
+ *     e/m
+ *
+ * then return
+ *
+ *     floor((e + m - 1)/m)
  */
 __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
 {
@@ -1004,9 +1057,16 @@ __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
        if (isl_int_is_one(aff->v->el[0]))
                return aff;
 
-       aff = isl_aff_neg(aff);
+       aff = isl_aff_cow(aff);
+       if (!aff)
+               return NULL;
+       aff->v = isl_vec_cow(aff->v);
+       if (!aff->v)
+               return isl_aff_free(aff);
+
+       isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
+       isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1);
        aff = isl_aff_floor(aff);
-       aff = isl_aff_neg(aff);
 
        return aff;
 }
@@ -1312,7 +1372,7 @@ static __isl_give isl_aff *isl_aff_substitute_equalities(
                goto error;
        n_div = isl_local_space_dim(aff->ls, isl_dim_div);
        if (n_div > 0)
-               eq = isl_basic_set_add(eq, isl_dim_set, n_div);
+               eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div);
        return isl_aff_substitute_equalities_lifted(aff, eq);
 error:
        isl_basic_set_free(eq);
@@ -2566,14 +2626,15 @@ __isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff)
 __isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational(
        __isl_take isl_pw_aff_list *list)
 {
-       int i;
+       int i, n;
 
        if (!list)
                return NULL;
        if (list->n == 0)
                return list;
 
-       for (i = 0; i < list->n; ++i) {
+       n = list->n;
+       for (i = 0; i < n; ++i) {
                isl_pw_aff *pa;
 
                pa = isl_pw_aff_list_get_pw_aff(list, i);