isl_basic_set_opt: avoid invalid access on error path
[platform/upstream/isl.git] / isl_test.c
index 485d8b4..fb6a5f4 100644 (file)
@@ -1185,6 +1185,19 @@ int test_coalesce(struct isl_ctx *ctx)
        if (test_coalesce_set(ctx, "{ [i,j] : exists a,b : i = 2a and j = 3b; "
                                     "[i,j] : exists a : j = 3a }", 1) < 0)
                return -1;
+       if (test_coalesce_set(ctx,
+               "{ [a, b, c] : (c <= 7 - b and b <= 1 and b >= 0 and "
+                       "c >= 3 + b and b <= 3 + 8a and b >= -26 + 8a and "
+                       "a >= 3) or "
+                   "(b <= 1 and c <= 7 and b >= 0 and c >= 4 + b and "
+                       "b <= 3 + 8a and b >= -26 + 8a and a >= 3) }", 1) < 0)
+               return -1;
+       if (test_coalesce_set(ctx,
+               "{ [a, 0, c] : c >= 1 and c <= 29 and c >= -1 + 8a and "
+                               "c <= 6 + 8a and a >= 3; "
+                   "[a, -1, c] : c >= 1 and c <= 30 and c >= 8a and "
+                               "c <= 7 + 8a and a >= 3 and a <= 4 }", 1) < 0)
+               return -1;
        return 0;
 }
 
@@ -1521,6 +1534,20 @@ void test_lexmin(struct isl_ctx *ctx)
        assert(isl_map_is_equal(map, map2));
        isl_map_free(map);
        isl_map_free(map2);
+
+       /* Check that empty pieces are properly combined. */
+       str = "[K, N] -> { [x, y] -> [a, b] : K+2<=N<=K+4 and x>=4 and "
+               "2N-6<=x<K+N and N-1<=a<=K+N-1 and N+b-6<=a<=2N-4 and "
+               "b<=2N-3K+a and 3b<=4N-K+1 and b>=N and a>=x+1 }";
+       map = isl_map_read_from_str(ctx, str);
+       map = isl_map_lexmin(map);
+       str = "[K, N] -> { [x, y] -> [1 + x, N] : x >= -6 + 2N and "
+               "x <= -5 + 2N and x >= -1 + 3K - N and x <= -2 + K + N and "
+               "x >= 4 }";
+       map2 = isl_map_read_from_str(ctx, str);
+       assert(isl_map_is_equal(map, map2));
+       isl_map_free(map);
+       isl_map_free(map2);
 }
 
 struct must_may {
@@ -2335,6 +2362,43 @@ int test_special_schedule(isl_ctx *ctx, const char *domain,
        return 0;
 }
 
+/* Check that the schedule map is properly padded, even after being
+ * reconstructed from the band forest.
+ */
+static int test_padded_schedule(isl_ctx *ctx)
+{
+       const char *str;
+       isl_union_set *D;
+       isl_union_map *validity, *proximity;
+       isl_schedule *sched;
+       isl_union_map *map1, *map2;
+       isl_band_list *list;
+       int equal;
+
+       str = "[N] -> { S0[i] : 0 <= i <= N; S1[i, j] : 0 <= i, j <= N }";
+       D = isl_union_set_read_from_str(ctx, str);
+       validity = isl_union_map_empty(isl_union_set_get_space(D));
+       proximity = isl_union_map_copy(validity);
+       sched = isl_union_set_compute_schedule(D, validity, proximity);
+       map1 = isl_schedule_get_map(sched);
+       list = isl_schedule_get_band_forest(sched);
+       isl_band_list_free(list);
+       map2 = isl_schedule_get_map(sched);
+       isl_schedule_free(sched);
+       equal = isl_union_map_is_equal(map1, map2);
+       isl_union_map_free(map1);
+       isl_union_map_free(map2);
+
+       if (equal < 0)
+               return -1;
+       if (!equal)
+               isl_die(ctx, isl_error_unknown,
+                       "reconstructed schedule map not the same as original",
+                       return -1);
+
+       return 0;
+}
+
 int test_schedule(isl_ctx *ctx)
 {
        const char *D, *W, *R, *V, *P, *S;
@@ -2595,6 +2659,23 @@ int test_schedule(isl_ctx *ctx)
        if (test_has_schedule(ctx, D, V, P) < 0)
                return -1;
 
+       if (test_padded_schedule(ctx) < 0)
+               return -1;
+
+       /* Check that check for progress is not confused by rational
+        * solution.
+        */
+       D = "[N] -> { S0[i, j] : i >= 0 and i <= N and j >= 0 and j <= N }";
+       V = "[N] -> { S0[i0, -1 + N] -> S0[2 + i0, 0] : i0 >= 0 and "
+                                                       "i0 <= -2 + N; "
+                       "S0[i0, i1] -> S0[i0, 1 + i1] : i0 >= 0 and "
+                               "i0 <= N and i1 >= 0 and i1 <= -1 + N }";
+       P = "{}";
+       ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+       if (test_has_schedule(ctx, D, V, P) < 0)
+               return -1;
+       ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+
        return 0;
 }
 
@@ -2802,6 +2883,24 @@ int test_dim_max(isl_ctx *ctx)
        if (!equal)
                isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
 
+       /* Check that solutions are properly merged. */
+       str = "[n] -> { [a, b, c] : c >= -4a - 2b and "
+                               "c <= -1 + n - 4a - 2b and c >= -2b and "
+                               "4a >= -4 + n and c >= 0 }";
+       set = isl_set_read_from_str(ctx, str);
+       pwaff = isl_set_dim_min(set, 2);
+       set1 = isl_set_from_pw_aff(pwaff);
+       str = "[n] -> { [(0)] : n >= 1 }";
+       set2 = isl_set_read_from_str(ctx, str);
+       equal = isl_set_is_equal(set1, set2);
+       isl_set_free(set1);
+       isl_set_free(set2);
+
+       if (equal < 0)
+               return -1;
+       if (!equal)
+               isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
        return 0;
 }
 
@@ -3303,6 +3402,31 @@ static int test_conversion(isl_ctx *ctx)
        return 0;
 }
 
+/* Check that isl_basic_map_curry does not modify input.
+ */
+static int test_curry(isl_ctx *ctx)
+{
+       const char *str;
+       isl_basic_map *bmap1, *bmap2;
+       int equal;
+
+       str = "{ [A[] -> B[]] -> C[] }";
+       bmap1 = isl_basic_map_read_from_str(ctx, str);
+       bmap2 = isl_basic_map_curry(isl_basic_map_copy(bmap1));
+       equal = isl_basic_map_is_equal(bmap1, bmap2);
+       isl_basic_map_free(bmap1);
+       isl_basic_map_free(bmap2);
+
+       if (equal < 0)
+               return -1;
+       if (equal)
+               isl_die(ctx, isl_error_unknown,
+                       "curried map should not be equal to original",
+                       return -1);
+
+       return 0;
+}
+
 struct {
        const char *set;
        const char *ma;
@@ -3418,10 +3542,12 @@ static int test_ast(isl_ctx *ctx)
        expr = isl_ast_expr_add(expr1, expr2);
        expr = isl_ast_expr_neg(expr);
        str = isl_ast_expr_to_str(expr);
-       ok = !strcmp(str, "-(A + B)");
+       ok = str ? !strcmp(str, "-(A + B)") : -1;
        free(str);
        isl_ast_expr_free(expr);
 
+       if (ok < 0)
+               return -1;
        if (!ok)
                isl_die(ctx, isl_error_unknown,
                        "isl_ast_expr printed incorrectly", return -1);
@@ -3432,10 +3558,12 @@ static int test_ast(isl_ctx *ctx)
        expr3 = isl_ast_expr_from_id(isl_id_alloc(ctx, "C", NULL));
        expr = isl_ast_expr_sub(expr3, expr);
        str = isl_ast_expr_to_str(expr);
-       ok = !strcmp(str, "C - (A + B)");
+       ok = str ? !strcmp(str, "C - (A + B)") : -1;
        free(str);
        isl_ast_expr_free(expr);
 
+       if (ok < 0)
+               return -1;
        if (!ok)
                isl_die(ctx, isl_error_unknown,
                        "isl_ast_expr printed incorrectly", return -1);
@@ -3746,10 +3874,100 @@ static int test_ast_gen(isl_ctx *ctx)
        return 0;
 }
 
+/* Check if dropping output dimensions from an isl_pw_multi_aff
+ * works properly.
+ */
+static int test_pw_multi_aff(isl_ctx *ctx)
+{
+       const char *str;
+       isl_pw_multi_aff *pma1, *pma2;
+       int equal;
+
+       str = "{ [i,j] -> [i+j, 4i-j] }";
+       pma1 = isl_pw_multi_aff_read_from_str(ctx, str);
+       str = "{ [i,j] -> [4i-j] }";
+       pma2 = isl_pw_multi_aff_read_from_str(ctx, str);
+
+       pma1 = isl_pw_multi_aff_drop_dims(pma1, isl_dim_out, 0, 1);
+
+       equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2);
+
+       isl_pw_multi_aff_free(pma1);
+       isl_pw_multi_aff_free(pma2);
+       if (equal < 0)
+               return -1;
+       if (!equal)
+               isl_die(ctx, isl_error_unknown,
+                       "expressions not equal", return -1);
+
+       return 0;
+}
+
+/* This is a regression test for a bug where isl_basic_map_simplify
+ * would end up in an infinite loop.  In particular, we construct
+ * an empty basic set that is not obviously empty.
+ * isl_basic_set_is_empty marks the basic set as empty.
+ * After projecting out i3, the variable can be dropped completely,
+ * but isl_basic_map_simplify refrains from doing so if the basic set
+ * is empty and would end up in an infinite loop if it didn't test
+ * explicitly for empty basic maps in the outer loop.
+ */
+static int test_simplify(isl_ctx *ctx)
+{
+       const char *str;
+       isl_basic_set *bset;
+       int empty;
+
+       str = "{ [i0, i1, i2, i3] : i0 >= -2 and 6i2 <= 4 + i0 + 5i1 and "
+               "i2 <= 22 and 75i2 <= 111 + 13i0 + 60i1 and "
+               "25i2 >= 38 + 6i0 + 20i1 and i0 <= -1 and i2 >= 20 and "
+               "i3 >= i2 }";
+       bset = isl_basic_set_read_from_str(ctx, str);
+       empty = isl_basic_set_is_empty(bset);
+       bset = isl_basic_set_project_out(bset, isl_dim_set, 3, 1);
+       isl_basic_set_free(bset);
+       if (!bset)
+               return -1;
+       if (!empty)
+               isl_die(ctx, isl_error_unknown,
+                       "basic set should be empty", return -1);
+
+       return 0;
+}
+
+/* This is a regression test for a bug where isl_tab_basic_map_partial_lexopt
+ * with gbr context would fail to disable the use of the shifted tableau
+ * when transferring equalities for the input to the context, resulting
+ * in invalid sample values.
+ */
+static int test_partial_lexmin(isl_ctx *ctx)
+{
+       const char *str;
+       isl_basic_set *bset;
+       isl_basic_map *bmap;
+       isl_map *map;
+
+       str = "{ [1, b, c, 1 - c] -> [e] : 2e <= -c and 2e >= -3 + c }";
+       bmap = isl_basic_map_read_from_str(ctx, str);
+       str = "{ [a, b, c, d] : c <= 1 and 2d >= 6 - 4b - c }";
+       bset = isl_basic_set_read_from_str(ctx, str);
+       map = isl_basic_map_partial_lexmin(bmap, bset, NULL);
+       isl_map_free(map);
+
+       if (!map)
+               return -1;
+
+       return 0;
+}
+
 struct {
        const char *name;
        int (*fn)(isl_ctx *ctx);
 } tests [] = {
+       { "partial lexmin", &test_partial_lexmin },
+       { "simplify", &test_simplify },
+       { "curry", &test_curry },
+       { "piecewise multi affine expressions", &test_pw_multi_aff },
        { "conversion", &test_conversion },
        { "list", &test_list },
        { "align parameters", &test_align_parameters },