isl_stream_read_map: properly read nested divs
[platform/upstream/isl.git] / isl_input.c
index 247c00a..607732e 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
+#include <isl_ctx_private.h>
 #include <isl_map_private.h>
 #include <isl/set.h>
 #include <isl/seq.h>
@@ -160,11 +161,40 @@ static __isl_give isl_basic_map *set_name(__isl_take isl_basic_map *bmap,
        return bmap;
 }
 
+/* Obtain next token, with some preprocessing.
+ * In particular, evaluate expressions of the form x^y,
+ * with x and y values.
+ */
+static struct isl_token *next_token(struct isl_stream *s)
+{
+       struct isl_token *tok, *tok2;
+
+       tok = isl_stream_next_token(s);
+       if (!tok || tok->type != ISL_TOKEN_VALUE)
+               return tok;
+       if (!isl_stream_eat_if_available(s, '^'))
+               return tok;
+       tok2 = isl_stream_next_token(s);
+       if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+               isl_stream_error(s, tok2, "expecting constant value");
+               goto error;
+       }
+
+       isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
+
+       isl_token_free(tok2);
+       return tok;
+error:
+       isl_token_free(tok);
+       isl_token_free(tok2);
+       return NULL;
+}
+
 static int accept_cst_factor(struct isl_stream *s, isl_int *f)
 {
        struct isl_token *tok;
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok || tok->type != ISL_TOKEN_VALUE) {
                isl_stream_error(s, tok, "expecting constant value");
                goto error;
@@ -197,7 +227,7 @@ static __isl_give isl_vec *affine_mod(struct isl_stream *s,
        struct variable *var;
        isl_vec *mod;
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok || tok->type != ISL_TOKEN_VALUE) {
                isl_stream_error(s, tok, "expecting constant value");
                goto error;
@@ -240,7 +270,7 @@ static __isl_give isl_vec *accept_affine_factor(struct isl_stream *s,
        struct isl_token *tok = NULL;
        isl_vec *aff = NULL;
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok) {
                isl_stream_error(s, NULL, "unexpected EOF");
                goto error;
@@ -293,6 +323,7 @@ static __isl_give isl_vec *accept_affine_factor(struct isl_stream *s,
                tok = NULL;
                if (read_div_definition(s, v) < 0)
                        goto error;
+               aff = isl_vec_zero_extend(aff, 1 + v->n);
        } else {
                isl_stream_error(s, tok, "expecting factor");
                goto error;
@@ -331,7 +362,7 @@ static struct isl_vec *accept_affine(struct isl_stream *s, struct vars *v)
        isl_seq_clr(aff->el, aff->size);
 
        for (;;) {
-               tok = isl_stream_next_token(s);
+               tok = next_token(s);
                if (!tok) {
                        isl_stream_error(s, NULL, "unexpected EOF");
                        goto error;
@@ -378,7 +409,7 @@ static struct isl_vec *accept_affine(struct isl_stream *s, struct vars *v)
                }
                isl_token_free(tok);
 
-               tok = isl_stream_next_token(s);
+               tok = next_token(s);
                if (tok && tok->type == '-') {
                        sign = -sign;
                        isl_token_free(tok);
@@ -489,7 +520,7 @@ static __isl_give isl_basic_map *read_var_list(struct isl_stream *s,
        int i = 0;
        struct isl_token *tok;
 
-       while ((tok = isl_stream_next_token(s)) != NULL) {
+       while ((tok = next_token(s)) != NULL) {
                int new_name = 0;
 
                if (tok->type == ISL_TOKEN_IDENT) {
@@ -614,7 +645,7 @@ static int read_div_definition(struct isl_stream *s, struct vars *v)
        if (isl_stream_eat(s, '/'))
                return -1;
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok)
                return -1;
        if (tok->type != ISL_TOKEN_VALUE) {
@@ -632,16 +663,16 @@ static int read_div_definition(struct isl_stream *s, struct vars *v)
 }
 
 static struct isl_basic_map *add_div_definition(struct isl_stream *s,
-       struct vars *v, struct isl_basic_map *bmap, int k)
+       struct vars *v, struct isl_basic_map *bmap, int pos)
 {
        struct variable *var = v->v;
+       unsigned o_out = isl_basic_map_offset(bmap, isl_dim_out) - 1;
 
        if (read_div_definition(s, v) < 0)
                goto error;
 
-       isl_seq_cpy(bmap->div[k], var->def->el, 2 + v->n);
-
-       if (isl_basic_map_add_div_constraints(bmap, k) < 0)
+       if (isl_basic_map_add_div_constraints_var(bmap, o_out + pos,
+                                                 var->def->el) < 0)
                goto error;
 
        return bmap;
@@ -656,10 +687,9 @@ static struct isl_basic_map *read_defined_var_list(struct isl_stream *s,
        struct isl_token *tok;
 
        while ((tok = isl_stream_next_token(s)) != NULL) {
-               int k;
                int p;
                int n = v->n;
-               unsigned total = isl_basic_map_total_dim(bmap);
+               unsigned n_out = isl_basic_map_dim(bmap, isl_dim_out);
 
                if (tok->type != ISL_TOKEN_IDENT)
                        break;
@@ -673,18 +703,15 @@ static struct isl_basic_map *read_defined_var_list(struct isl_stream *s,
                }
 
                bmap = isl_basic_map_cow(bmap);
+               bmap = isl_basic_map_add(bmap, isl_dim_out, 1);
                bmap = isl_basic_map_extend_dim(bmap, isl_dim_copy(bmap->dim),
-                                               1, 0, 2);
-
-               if ((k = isl_basic_map_alloc_div(bmap)) < 0)
-                       goto error;
-               isl_seq_clr(bmap->div[k], 1 + 1 + total);
+                                               0, 0, 2);
 
                isl_token_free(tok);
                tok = isl_stream_next_token(s);
                if (tok && tok->type == '=') {
                        isl_token_free(tok);
-                       bmap = add_div_definition(s, v, bmap, k);
+                       bmap = add_div_definition(s, v, bmap, n_out);
                        tok = isl_stream_next_token(s);
                }
 
@@ -807,43 +834,6 @@ error:
        return NULL;
 }
 
-static struct isl_basic_map *add_constraints(struct isl_stream *s,
-       struct vars *v, struct isl_basic_map *bmap);
-
-static struct isl_basic_map *add_exists(struct isl_stream *s,
-       struct vars *v, struct isl_basic_map *bmap)
-{
-       struct isl_token *tok;
-       int n = v->n;
-       int extra;
-       int seen_paren = 0;
-       int i;
-       unsigned total;
-
-       tok = isl_stream_next_token(s);
-       if (!tok)
-               goto error;
-       if (tok->type == '(') {
-               seen_paren = 1;
-               isl_token_free(tok);
-       } else
-               isl_stream_push_token(s, tok);
-
-       bmap = read_defined_var_list(s, v, bmap);
-       if (!bmap)
-               goto error;
-
-       if (isl_stream_eat(s, ':'))
-               goto error;
-       bmap = add_constraints(s, v, bmap);
-       if (seen_paren && isl_stream_eat(s, ')'))
-               goto error;
-       return bmap;
-error:
-       isl_basic_map_free(bmap);
-       return NULL;
-}
-
 static __isl_give isl_basic_map *construct_constraint(
        __isl_take isl_basic_map *bmap, enum isl_token_type type,
        isl_int *left, isl_int *right)
@@ -908,6 +898,40 @@ static int is_comparator(struct isl_token *tok)
        }
 }
 
+/* Add any variables in the variable list "v" that are not already in "bmap"
+ * as output variables in "bmap".
+ */
+static __isl_give isl_basic_map *add_lifted_divs(__isl_take isl_basic_map *bmap,
+       struct vars *v)
+{
+       int i;
+       int extra;
+       struct variable *var;
+
+       extra = v->n - isl_basic_map_total_dim(bmap);
+
+       if (extra == 0)
+               return bmap;
+
+       bmap = isl_basic_map_add(bmap, isl_dim_out, extra);
+       bmap = isl_basic_map_extend_dim(bmap, isl_basic_map_get_dim(bmap),
+                                       0, 0, 2 * extra);
+
+       for (i = 0, var = v->v; i < extra; ++i, var = var->next) {
+               var->def = isl_vec_zero_extend(var->def, 2 + v->n);
+               if (!var->def)
+                       goto error;
+               if (isl_basic_map_add_div_constraints_var(bmap, var->pos,
+                                                         var->def->el) < 0)
+                       goto error;
+       }
+
+       return bmap;
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
 static struct isl_basic_map *add_constraint(struct isl_stream *s,
        struct vars *v, struct isl_basic_map *bmap)
 {
@@ -915,16 +939,6 @@ static struct isl_basic_map *add_constraint(struct isl_stream *s,
        struct isl_token *tok = NULL;
        struct isl_mat *aff1 = NULL, *aff2 = NULL;
 
-       tok = isl_stream_next_token(s);
-       if (!tok)
-               goto error;
-       if (tok->type == ISL_TOKEN_EXISTS) {
-               isl_token_free(tok);
-               return add_exists(s, v, bmap);
-       }
-       isl_stream_push_token(s, tok);
-       tok = NULL;
-
        bmap = isl_basic_map_cow(bmap);
 
        aff1 = accept_affine_list(s, v);
@@ -946,7 +960,7 @@ static struct isl_basic_map *add_constraint(struct isl_stream *s,
                aff1 = isl_mat_add_zero_cols(aff1, aff2->n_col - aff1->n_col);
                if (!aff1)
                        goto error;
-               bmap = add_divs(bmap, v);
+               bmap = add_lifted_divs(bmap, v);
                bmap = isl_basic_map_extend_constraints(bmap, 0,
                                                aff1->n_row * aff2->n_row);
                for (i = 0; i < aff1->n_row; ++i)
@@ -976,107 +990,138 @@ error:
        return NULL;
 }
 
-static struct isl_basic_map *add_constraints(struct isl_stream *s,
-       struct vars *v, struct isl_basic_map *bmap)
+static isl_map *read_constraint(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap)
 {
-       struct isl_token *tok;
+       int n = v->n;
 
-       for (;;) {
-               bmap = add_constraint(s, v, bmap);
-               if (!bmap)
-                       return NULL;
-               tok = isl_stream_next_token(s);
-               if (!tok) {
-                       isl_stream_error(s, NULL, "unexpected EOF");
-                       goto error;
-               }
-               if (tok->type != ISL_TOKEN_AND)
-                       break;
-               isl_token_free(tok);
-       }
-       isl_stream_push_token(s, tok);
+       if (!bmap)
+               return NULL;
 
-       return bmap;
-error:
-       if (tok)
-               isl_token_free(tok);
-       isl_basic_map_free(bmap);
-       return NULL;
+       bmap = isl_basic_set_unwrap(isl_basic_set_lift(isl_basic_map_wrap(bmap)));
+
+       bmap = add_constraint(s, v, bmap);
+       bmap = isl_basic_map_simplify(bmap);
+       bmap = isl_basic_map_finalize(bmap);
+
+       bmap = isl_basic_set_unwrap(isl_basic_map_domain(bmap));
+
+       vars_drop(v, v->n - n);
+
+       return isl_map_from_basic_map(bmap);
 }
 
-static struct isl_basic_map *read_disjunct(struct isl_stream *s,
-       struct vars *v, __isl_take isl_dim *dim)
+static struct isl_map *read_disjuncts(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap);
+
+static __isl_give isl_map *read_exists(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap)
 {
-       int seen_paren = 0;
-       struct isl_token *tok;
-       struct isl_basic_map *bmap;
+       int n = v->n;
+       int seen_paren = isl_stream_eat_if_available(s, '(');
+       isl_map *map = NULL;
 
-       bmap = isl_basic_map_alloc_dim(dim, 0, 0, 0);
-       if (!bmap)
-               return NULL;
+       bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+       bmap = read_defined_var_list(s, v, bmap);
 
-       tok = isl_stream_next_token(s);
-       if (!tok)
+       if (isl_stream_eat(s, ':'))
                goto error;
-       if (tok->type == '(') {
-               seen_paren = 1;
-               isl_token_free(tok);
-       } else
-               isl_stream_push_token(s, tok);
 
-       bmap = add_constraints(s, v, bmap);
-       bmap = isl_basic_map_simplify(bmap);
-       bmap = isl_basic_map_finalize(bmap);
+       map = read_disjuncts(s, v, bmap);
+       map = isl_set_unwrap(isl_map_domain(map));
+       bmap = NULL;
 
+       vars_drop(v, v->n - n);
        if (seen_paren && isl_stream_eat(s, ')'))
                goto error;
 
-       return bmap;
+       return map;
 error:
        isl_basic_map_free(bmap);
+       isl_map_free(map);
        return NULL;
 }
 
-static struct isl_map *read_disjuncts(struct isl_stream *s,
-       struct vars *v, __isl_take isl_dim *dim)
+static __isl_give isl_map *read_conjunct(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap)
 {
-       struct isl_token *tok;
-       struct isl_map *map;
+       isl_map *map;
 
-       tok = isl_stream_next_token(s);
-       if (!tok) {
-               isl_stream_error(s, NULL, "unexpected EOF");
-               goto error;
+       if (isl_stream_eat_if_available(s, '(')) {
+               map = read_disjuncts(s, v, bmap);
+               if (isl_stream_eat(s, ')'))
+                       goto error;
+               return map;
        }
-       if (tok->type == '}') {
-               isl_stream_push_token(s, tok);
-               return isl_map_universe(dim);
+
+       if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
+               return read_exists(s, v, bmap);
+
+       if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
+               return isl_map_from_basic_map(bmap);
+
+       if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
+               isl_dim *dim = isl_basic_map_get_dim(bmap);
+               isl_basic_map_free(bmap);
+               return isl_map_empty(dim);
        }
-       isl_stream_push_token(s, tok);
+               
+       return read_constraint(s, v, bmap);
+error:
+       isl_map_free(map);
+       return NULL;
+}
 
-       map = isl_map_empty(isl_dim_copy(dim));
-       for (;;) {
-               struct isl_basic_map *bmap;
-               int n = v->n;
+static __isl_give isl_map *read_conjuncts(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap)
+{
+       isl_map *map;
+       int negate;
 
-               bmap = read_disjunct(s, v, isl_dim_copy(dim));
-               map = isl_map_union(map, isl_map_from_basic_map(bmap));
+       negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+       map = read_conjunct(s, v, isl_basic_map_copy(bmap));
+       if (negate) {
+               isl_map *t;
+               t = isl_map_from_basic_map(isl_basic_map_copy(bmap));
+               map = isl_map_subtract(t, map);
+       }
 
-               vars_drop(v, v->n - n);
+       while (isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
+               isl_map *map_i;
 
-               tok = isl_stream_next_token(s);
-               if (!tok || tok->type != ISL_TOKEN_OR)
-                       break;
-               isl_token_free(tok);
+               negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+               map_i = read_conjunct(s, v, isl_basic_map_copy(bmap));
+               if (negate)
+                       map = isl_map_subtract(map, map_i);
+               else
+                       map = isl_map_intersect(map, map_i);
        }
-       if (tok)
-               isl_stream_push_token(s, tok);
 
-       isl_dim_free(dim);
+       isl_basic_map_free(bmap);
+       return map;
+}
+
+static struct isl_map *read_disjuncts(struct isl_stream *s,
+       struct vars *v, __isl_take isl_basic_map *bmap)
+{
+       struct isl_map *map;
+
+       if (isl_stream_next_token_is(s, '}')) {
+               isl_dim *dim = isl_basic_map_get_dim(bmap);
+               isl_basic_map_free(bmap);
+               return isl_map_universe(dim);
+       }
+
+       map = read_conjuncts(s, v, isl_basic_map_copy(bmap));
+       while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
+               isl_map *map_i;
+
+               map_i = read_conjuncts(s, v, isl_basic_map_copy(bmap));
+               map = isl_map_union(map, map_i);
+       }
+
+       isl_basic_map_free(bmap);
        return map;
-error:
-       isl_dim_free(dim);
-       return NULL;
 }
 
 static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
@@ -1388,7 +1433,7 @@ static __isl_give isl_qpolynomial *read_factor(struct isl_stream *s,
        struct isl_qpolynomial *qp;
        struct isl_token *tok;
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok) {
                isl_stream_error(s, NULL, "unexpected EOF");
                return NULL;
@@ -1409,7 +1454,7 @@ static __isl_give isl_qpolynomial *read_factor(struct isl_stream *s,
                tok2 = isl_stream_next_token(s);
                if (tok2 && tok2->type == '/') {
                        isl_token_free(tok2);
-                       tok2 = isl_stream_next_token(s);
+                       tok2 = next_token(s);
                        if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
                                isl_stream_error(s, tok2, "expected denominator");
                                isl_token_free(tok);
@@ -1493,7 +1538,7 @@ static __isl_give isl_qpolynomial *read_term(struct isl_stream *s,
        qp = read_factor(s, bmap, v);
 
        for (;;) {
-               tok = isl_stream_next_token(s);
+               tok = next_token(s);
                if (!tok)
                        return qp;
 
@@ -1537,10 +1582,11 @@ static __isl_give isl_map *read_optional_disjuncts(struct isl_stream *s,
                goto error;
        }
        map = isl_map_from_basic_map(isl_basic_map_copy(bmap));
-       if (tok->type == ':') {
+       if (tok->type == ':' ||
+           (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
                isl_token_free(tok);
                map = isl_map_intersect(map,
-                           read_disjuncts(s, v, isl_basic_map_get_dim(bmap)));
+                           read_disjuncts(s, v, isl_basic_map_copy(bmap)));
        } else
                isl_stream_push_token(s, tok);
 
@@ -1618,6 +1664,24 @@ error:
        return obj;
 }
 
+static int is_rational(struct isl_stream *s)
+{
+       struct isl_token *tok;
+
+       tok = isl_stream_next_token(s);
+       if (!tok)
+               return 0;
+       if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
+               isl_token_free(tok);
+               isl_stream_eat(s, ':');
+               return 1;
+       }
+
+       isl_stream_push_token(s, tok);
+
+       return 0;
+}
+
 static struct isl_obj obj_read_body(struct isl_stream *s,
        __isl_take isl_basic_map *bmap, struct vars *v)
 {
@@ -1626,6 +1690,9 @@ static struct isl_obj obj_read_body(struct isl_stream *s,
        struct isl_obj obj = { isl_obj_set, NULL };
        int n = v->n;
 
+       if (is_rational(s))
+               bmap = isl_basic_map_set_rational(bmap);
+
        if (!next_is_tuple(s))
                return obj_read_poly_or_fold(s, bmap, v, n);
 
@@ -1743,7 +1810,7 @@ static struct isl_obj obj_read(struct isl_stream *s, int nparam)
        struct vars *v = NULL;
        struct isl_obj obj = { isl_obj_set, NULL };
 
-       tok = isl_stream_next_token(s);
+       tok = next_token(s);
        if (!tok) {
                isl_stream_error(s, NULL, "unexpected EOF");
                goto error;
@@ -1841,6 +1908,10 @@ static struct isl_obj obj_read(struct isl_stream *s, int nparam)
                if (!tok || tok->type != ';')
                        break;
                isl_token_free(tok);
+               if (isl_stream_next_token_is(s, '}')) {
+                       tok = isl_stream_next_token(s);
+                       break;
+               }
        }
 
        if (tok && tok->type == '}') {
@@ -2074,6 +2145,18 @@ error:
        return NULL;
 }
 
+__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
+       FILE *input)
+{
+       isl_union_map *umap;
+       struct isl_stream *s = isl_stream_new_file(ctx, input);
+       if (!s)
+               return NULL;
+       umap = isl_stream_read_union_map(s);
+       isl_stream_free(s);
+       return umap;
+}
+
 __isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
                const char *str)
 {
@@ -2086,6 +2169,18 @@ __isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
        return umap;
 }
 
+__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
+       FILE *input)
+{
+       isl_union_set *uset;
+       struct isl_stream *s = isl_stream_new_file(ctx, input);
+       if (!s)
+               return NULL;
+       uset = isl_stream_read_union_set(s);
+       isl_stream_free(s);
+       return uset;
+}
+
 __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
                const char *str)
 {
@@ -2133,22 +2228,18 @@ error:
        return NULL;
 }
 
-static __isl_give isl_vec *vec_read(struct isl_stream *s,
-       unsigned input_format)
+static __isl_give isl_vec *vec_read(struct isl_stream *s)
 {
-       if (input_format == ISL_FORMAT_POLYLIB)
-               return isl_vec_read_polylib(s);
-       isl_assert(s->ctx, 0, return NULL);
+       return isl_vec_read_polylib(s);
 }
 
-struct isl_vec *isl_vec_read_from_file(struct isl_ctx *ctx,
-               FILE *input, unsigned input_format)
+__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
 {
        isl_vec *v;
        struct isl_stream *s = isl_stream_new_file(ctx, input);
        if (!s)
                return NULL;
-       v = vec_read(s, input_format);
+       v = vec_read(s);
        isl_stream_free(s);
        return v;
 }