1 /*
2 * Copyright 2008-2009 Katholieke Universiteit Leuven
3 * Copyright 2010 INRIA Saclay
4 * Copyright 2012-2013 Ecole Normale Superieure
5 * Copyright 2019 Cerebras Systems
6 *
7 * Use of this software is governed by the MIT license
8 *
9 * Written by Sven Verdoolaege, K.U.Leuven, Departement
10 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
11 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
12 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
13 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14 * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
15 */
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <isl_ctx_private.h>
21 #include <isl_map_private.h>
22 #include <isl_id_private.h>
23 #include <isl/set.h>
24 #include <isl_seq.h>
25 #include <isl_stream_private.h>
26 #include <isl/obj.h>
27 #include "isl_polynomial_private.h"
28 #include <isl/union_set.h>
29 #include <isl/union_map.h>
30 #include <isl_mat_private.h>
31 #include <isl_aff_private.h>
32 #include <isl_vec_private.h>
33 #include <isl/list.h>
34 #include <isl_val_private.h>
35
36 struct variable {
37 char *name;
38 int pos;
39 struct variable *next;
40 };
41
42 struct vars {
43 struct isl_ctx *ctx;
44 int n;
45 struct variable *v;
46 };
47
vars_new(struct isl_ctx * ctx)48 static struct vars *vars_new(struct isl_ctx *ctx)
49 {
50 struct vars *v;
51 v = isl_alloc_type(ctx, struct vars);
52 if (!v)
53 return NULL;
54 v->ctx = ctx;
55 v->n = 0;
56 v->v = NULL;
57 return v;
58 }
59
variable_free(struct variable * var)60 static void variable_free(struct variable *var)
61 {
62 while (var) {
63 struct variable *next = var->next;
64 free(var->name);
65 free(var);
66 var = next;
67 }
68 }
69
vars_free(struct vars * v)70 static void vars_free(struct vars *v)
71 {
72 if (!v)
73 return;
74 variable_free(v->v);
75 free(v);
76 }
77
vars_drop(struct vars * v,int n)78 static void vars_drop(struct vars *v, int n)
79 {
80 struct variable *var;
81
82 if (!v || !v->v)
83 return;
84
85 v->n -= n;
86
87 var = v->v;
88 while (--n >= 0) {
89 struct variable *next = var->next;
90 free(var->name);
91 free(var);
92 var = next;
93 }
94 v->v = var;
95 }
96
variable_new(struct vars * v,const char * name,int len,int pos)97 static struct variable *variable_new(struct vars *v, const char *name, int len,
98 int pos)
99 {
100 struct variable *var;
101 var = isl_calloc_type(v->ctx, struct variable);
102 if (!var)
103 goto error;
104 var->name = strdup(name);
105 var->name[len] = '\0';
106 var->pos = pos;
107 var->next = v->v;
108 return var;
109 error:
110 variable_free(v->v);
111 return NULL;
112 }
113
vars_pos(struct vars * v,const char * s,int len)114 static int vars_pos(struct vars *v, const char *s, int len)
115 {
116 int pos;
117 struct variable *q;
118
119 if (len == -1)
120 len = strlen(s);
121 for (q = v->v; q; q = q->next) {
122 if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0')
123 break;
124 }
125 if (q)
126 pos = q->pos;
127 else {
128 pos = v->n;
129 v->v = variable_new(v, s, len, v->n);
130 if (!v->v)
131 return -1;
132 v->n++;
133 }
134 return pos;
135 }
136
vars_add_anon(struct vars * v)137 static int vars_add_anon(struct vars *v)
138 {
139 v->v = variable_new(v, "", 0, v->n);
140
141 if (!v->v)
142 return -1;
143 v->n++;
144
145 return 0;
146 }
147
148 /* Obtain next token, with some preprocessing.
149 * In particular, evaluate expressions of the form x^y,
150 * with x and y values.
151 */
next_token(__isl_keep isl_stream * s)152 static struct isl_token *next_token(__isl_keep isl_stream *s)
153 {
154 struct isl_token *tok, *tok2;
155
156 tok = isl_stream_next_token(s);
157 if (!tok || tok->type != ISL_TOKEN_VALUE)
158 return tok;
159 if (!isl_stream_eat_if_available(s, '^'))
160 return tok;
161 tok2 = isl_stream_next_token(s);
162 if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
163 isl_stream_error(s, tok2, "expecting constant value");
164 goto error;
165 }
166
167 isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
168
169 isl_token_free(tok2);
170 return tok;
171 error:
172 isl_token_free(tok);
173 isl_token_free(tok2);
174 return NULL;
175 }
176
177 /* Read an isl_val from "s".
178 *
179 * The following token sequences are recognized
180 *
181 * "infty" -> infty
182 * "-" "infty" -> -infty
183 * "NaN" -> NaN
184 * n "/" d -> n/d
185 * v -> v
186 *
187 * where n, d and v are integer constants.
188 */
isl_stream_read_val(__isl_keep isl_stream * s)189 __isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s)
190 {
191 struct isl_token *tok = NULL;
192 struct isl_token *tok2 = NULL;
193 isl_val *val;
194
195 tok = next_token(s);
196 if (!tok) {
197 isl_stream_error(s, NULL, "unexpected EOF");
198 goto error;
199 }
200 if (tok->type == ISL_TOKEN_INFTY) {
201 isl_token_free(tok);
202 return isl_val_infty(s->ctx);
203 }
204 if (tok->type == '-' &&
205 isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) {
206 isl_token_free(tok);
207 return isl_val_neginfty(s->ctx);
208 }
209 if (tok->type == ISL_TOKEN_NAN) {
210 isl_token_free(tok);
211 return isl_val_nan(s->ctx);
212 }
213 if (tok->type != ISL_TOKEN_VALUE) {
214 isl_stream_error(s, tok, "expecting value");
215 goto error;
216 }
217
218 if (isl_stream_eat_if_available(s, '/')) {
219 tok2 = next_token(s);
220 if (!tok2) {
221 isl_stream_error(s, NULL, "unexpected EOF");
222 goto error;
223 }
224 if (tok2->type != ISL_TOKEN_VALUE) {
225 isl_stream_error(s, tok2, "expecting value");
226 goto error;
227 }
228 val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v);
229 val = isl_val_normalize(val);
230 } else {
231 val = isl_val_int_from_isl_int(s->ctx, tok->u.v);
232 }
233
234 isl_token_free(tok);
235 isl_token_free(tok2);
236 return val;
237 error:
238 isl_token_free(tok);
239 isl_token_free(tok2);
240 return NULL;
241 }
242
243 /* Read an isl_val from "str".
244 */
isl_val_read_from_str(isl_ctx * ctx,const char * str)245 __isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str)
246 {
247 isl_val *val;
248 isl_stream *s = isl_stream_new_str(ctx, str);
249 if (!s)
250 return NULL;
251 val = isl_stream_read_val(s);
252 isl_stream_free(s);
253 return val;
254 }
255
256 /* Perform an integer division on *f and
257 * an integer value read from the stream.
258 */
int_div_by_cst(__isl_keep isl_stream * s,isl_int * f)259 static isl_stat int_div_by_cst(__isl_keep isl_stream *s, isl_int *f)
260 {
261 struct isl_token *tok;
262
263 tok = next_token(s);
264 if (!tok || tok->type != ISL_TOKEN_VALUE) {
265 isl_stream_error(s, tok, "expecting constant value");
266 goto error;
267 }
268
269 isl_int_fdiv_q(*f, *f, tok->u.v);
270
271 isl_token_free(tok);
272
273 return isl_stat_ok;
274 error:
275 isl_token_free(tok);
276 return isl_stat_error;
277 }
278
accept_cst_factor(__isl_keep isl_stream * s,isl_int * f)279 static isl_stat accept_cst_factor(__isl_keep isl_stream *s, isl_int *f)
280 {
281 struct isl_token *tok;
282
283 tok = next_token(s);
284 if (!tok || tok->type != ISL_TOKEN_VALUE) {
285 isl_stream_error(s, tok, "expecting constant value");
286 goto error;
287 }
288
289 isl_int_mul(*f, *f, tok->u.v);
290
291 isl_token_free(tok);
292
293 if (isl_stream_eat_if_available(s, '*'))
294 return accept_cst_factor(s, f);
295
296 return isl_stat_ok;
297 error:
298 isl_token_free(tok);
299 return isl_stat_error;
300 }
301
302 /* Given an affine expression aff, return an affine expression
303 * for aff % d, with d the next token on the stream, which is
304 * assumed to be a constant.
305 *
306 * We introduce an integer division q = [aff/d] and the result
307 * is set to aff - d q.
308 */
affine_mod(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_pw_aff * aff)309 static __isl_give isl_pw_aff *affine_mod(__isl_keep isl_stream *s,
310 struct vars *v, __isl_take isl_pw_aff *aff)
311 {
312 struct isl_token *tok;
313 isl_pw_aff *q;
314
315 tok = next_token(s);
316 if (!tok || tok->type != ISL_TOKEN_VALUE) {
317 isl_stream_error(s, tok, "expecting constant value");
318 goto error;
319 }
320
321 q = isl_pw_aff_copy(aff);
322 q = isl_pw_aff_scale_down(q, tok->u.v);
323 q = isl_pw_aff_floor(q);
324 q = isl_pw_aff_scale(q, tok->u.v);
325
326 aff = isl_pw_aff_sub(aff, q);
327
328 isl_token_free(tok);
329 return aff;
330 error:
331 isl_pw_aff_free(aff);
332 isl_token_free(tok);
333 return NULL;
334 }
335
336 static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
337 __isl_take isl_space *space, struct vars *v);
338 static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
339 __isl_take isl_space *space, struct vars *v);
340
accept_minmax(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v)341 static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s,
342 __isl_take isl_space *space, struct vars *v)
343 {
344 struct isl_token *tok;
345 isl_pw_aff_list *list = NULL;
346 int min;
347
348 tok = isl_stream_next_token(s);
349 if (!tok)
350 goto error;
351 min = tok->type == ISL_TOKEN_MIN;
352 isl_token_free(tok);
353
354 if (isl_stream_eat(s, '('))
355 goto error;
356
357 list = accept_affine_list(s, isl_space_copy(space), v);
358 if (!list)
359 goto error;
360
361 if (isl_stream_eat(s, ')'))
362 goto error;
363
364 isl_space_free(space);
365 return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list);
366 error:
367 isl_space_free(space);
368 isl_pw_aff_list_free(list);
369 return NULL;
370 }
371
372 /* Is "tok" the start of an integer division?
373 */
is_start_of_div(struct isl_token * tok)374 static int is_start_of_div(struct isl_token *tok)
375 {
376 if (!tok)
377 return 0;
378 if (tok->type == '[')
379 return 1;
380 if (tok->type == ISL_TOKEN_FLOOR)
381 return 1;
382 if (tok->type == ISL_TOKEN_CEIL)
383 return 1;
384 if (tok->type == ISL_TOKEN_FLOORD)
385 return 1;
386 if (tok->type == ISL_TOKEN_CEILD)
387 return 1;
388 return 0;
389 }
390
391 /* Read an integer division from "s" and return it as an isl_pw_aff.
392 *
393 * The integer division can be of the form
394 *
395 * [<affine expression>]
396 * floor(<affine expression>)
397 * ceil(<affine expression>)
398 * floord(<affine expression>,<denominator>)
399 * ceild(<affine expression>,<denominator>)
400 */
accept_div(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v)401 static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s,
402 __isl_take isl_space *space, struct vars *v)
403 {
404 struct isl_token *tok;
405 int f = 0;
406 int c = 0;
407 int extra = 0;
408 isl_pw_aff *pwaff = NULL;
409
410 if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD))
411 extra = f = 1;
412 else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD))
413 extra = c = 1;
414 else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR))
415 f = 1;
416 else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL))
417 c = 1;
418 if (f || c) {
419 if (isl_stream_eat(s, '('))
420 goto error;
421 } else {
422 if (isl_stream_eat(s, '['))
423 goto error;
424 }
425
426 pwaff = accept_affine(s, isl_space_copy(space), v);
427
428 if (extra) {
429 if (isl_stream_eat(s, ','))
430 goto error;
431
432 tok = next_token(s);
433 if (!tok)
434 goto error;
435 if (tok->type != ISL_TOKEN_VALUE) {
436 isl_stream_error(s, tok, "expected denominator");
437 isl_stream_push_token(s, tok);
438 goto error;
439 }
440 pwaff = isl_pw_aff_scale_down(pwaff, tok->u.v);
441 isl_token_free(tok);
442 }
443
444 if (c)
445 pwaff = isl_pw_aff_ceil(pwaff);
446 else
447 pwaff = isl_pw_aff_floor(pwaff);
448
449 if (f || c) {
450 if (isl_stream_eat(s, ')'))
451 goto error;
452 } else {
453 if (isl_stream_eat(s, ']'))
454 goto error;
455 }
456
457 isl_space_free(space);
458 return pwaff;
459 error:
460 isl_space_free(space);
461 isl_pw_aff_free(pwaff);
462 return NULL;
463 }
464
465 /* Divide "pa" by an integer constant read from the stream.
466 */
pw_aff_div_by_cst(__isl_keep isl_stream * s,__isl_take isl_pw_aff * pa)467 static __isl_give isl_pw_aff *pw_aff_div_by_cst(__isl_keep isl_stream *s,
468 __isl_take isl_pw_aff *pa)
469 {
470 isl_int f;
471 isl_int_init(f);
472 isl_int_set_si(f, 1);
473 if (accept_cst_factor(s, &f) < 0)
474 pa = isl_pw_aff_free(pa);
475 pa = isl_pw_aff_scale_down(pa, f);
476 isl_int_clear(f);
477
478 return pa;
479 }
480
accept_affine_factor(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v)481 static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s,
482 __isl_take isl_space *space, struct vars *v)
483 {
484 struct isl_token *tok = NULL;
485 isl_pw_aff *res = NULL;
486
487 tok = next_token(s);
488 if (!tok) {
489 isl_stream_error(s, NULL, "unexpected EOF");
490 goto error;
491 }
492
493 if (tok->type == ISL_TOKEN_AFF) {
494 res = isl_pw_aff_copy(tok->u.pwaff);
495 isl_token_free(tok);
496 } else if (tok->type == ISL_TOKEN_IDENT) {
497 int n = v->n;
498 int pos = vars_pos(v, tok->u.s, -1);
499 isl_aff *aff;
500
501 if (pos < 0)
502 goto error;
503 if (pos >= n) {
504 vars_drop(v, v->n - n);
505 isl_stream_error(s, tok, "unknown identifier");
506 goto error;
507 }
508
509 aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(space)));
510 if (!aff)
511 goto error;
512 isl_int_set_si(aff->v->el[2 + pos], 1);
513 res = isl_pw_aff_from_aff(aff);
514 isl_token_free(tok);
515 } else if (tok->type == ISL_TOKEN_VALUE) {
516 if (isl_stream_eat_if_available(s, '*')) {
517 res = accept_affine_factor(s, isl_space_copy(space), v);
518 res = isl_pw_aff_scale(res, tok->u.v);
519 } else {
520 isl_local_space *ls;
521 isl_aff *aff;
522 ls = isl_local_space_from_space(isl_space_copy(space));
523 aff = isl_aff_zero_on_domain(ls);
524 aff = isl_aff_add_constant(aff, tok->u.v);
525 res = isl_pw_aff_from_aff(aff);
526 }
527 isl_token_free(tok);
528 } else if (tok->type == '(') {
529 isl_token_free(tok);
530 tok = NULL;
531 res = accept_affine(s, isl_space_copy(space), v);
532 if (!res)
533 goto error;
534 if (isl_stream_eat(s, ')'))
535 goto error;
536 } else if (is_start_of_div(tok)) {
537 isl_stream_push_token(s, tok);
538 tok = NULL;
539 res = accept_div(s, isl_space_copy(space), v);
540 } else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) {
541 isl_stream_push_token(s, tok);
542 tok = NULL;
543 res = accept_minmax(s, isl_space_copy(space), v);
544 } else {
545 isl_stream_error(s, tok, "expecting factor");
546 goto error;
547 }
548 if (isl_stream_eat_if_available(s, '%') ||
549 isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) {
550 isl_space_free(space);
551 return affine_mod(s, v, res);
552 }
553 if (isl_stream_eat_if_available(s, '*')) {
554 isl_int f;
555 isl_int_init(f);
556 isl_int_set_si(f, 1);
557 if (accept_cst_factor(s, &f) < 0) {
558 isl_int_clear(f);
559 goto error2;
560 }
561 res = isl_pw_aff_scale(res, f);
562 isl_int_clear(f);
563 }
564 if (isl_stream_eat_if_available(s, '/'))
565 res = pw_aff_div_by_cst(s, res);
566 if (isl_stream_eat_if_available(s, ISL_TOKEN_INT_DIV))
567 res = isl_pw_aff_floor(pw_aff_div_by_cst(s, res));
568
569 isl_space_free(space);
570 return res;
571 error:
572 isl_token_free(tok);
573 error2:
574 isl_pw_aff_free(res);
575 isl_space_free(space);
576 return NULL;
577 }
578
add_cst(__isl_take isl_pw_aff * pwaff,isl_int v)579 static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v)
580 {
581 isl_aff *aff;
582 isl_space *space;
583
584 space = isl_pw_aff_get_domain_space(pwaff);
585 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
586 aff = isl_aff_add_constant(aff, v);
587
588 return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff));
589 }
590
591 /* Return a piecewise affine expression defined on the specified domain
592 * that represents NaN.
593 */
nan_on_domain(__isl_keep isl_space * space)594 static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space)
595 {
596 isl_local_space *ls;
597
598 ls = isl_local_space_from_space(isl_space_copy(space));
599 return isl_pw_aff_nan_on_domain(ls);
600 }
601
accept_affine(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v)602 static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
603 __isl_take isl_space *space, struct vars *v)
604 {
605 struct isl_token *tok = NULL;
606 isl_local_space *ls;
607 isl_pw_aff *res;
608 int sign = 1;
609
610 ls = isl_local_space_from_space(isl_space_copy(space));
611 res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
612 if (!res)
613 goto error;
614
615 for (;;) {
616 tok = next_token(s);
617 if (!tok) {
618 isl_stream_error(s, NULL, "unexpected EOF");
619 goto error;
620 }
621 if (tok->type == '-') {
622 sign = -sign;
623 isl_token_free(tok);
624 continue;
625 }
626 if (tok->type == '(' || is_start_of_div(tok) ||
627 tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX ||
628 tok->type == ISL_TOKEN_IDENT ||
629 tok->type == ISL_TOKEN_AFF) {
630 isl_pw_aff *term;
631 isl_stream_push_token(s, tok);
632 tok = NULL;
633 term = accept_affine_factor(s,
634 isl_space_copy(space), v);
635 if (sign < 0)
636 res = isl_pw_aff_sub(res, term);
637 else
638 res = isl_pw_aff_add(res, term);
639 if (!res)
640 goto error;
641 sign = 1;
642 } else if (tok->type == ISL_TOKEN_VALUE) {
643 if (sign < 0)
644 isl_int_neg(tok->u.v, tok->u.v);
645 if (isl_stream_eat_if_available(s, '*') ||
646 isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
647 isl_pw_aff *term;
648 term = accept_affine_factor(s,
649 isl_space_copy(space), v);
650 term = isl_pw_aff_scale(term, tok->u.v);
651 res = isl_pw_aff_add(res, term);
652 if (!res)
653 goto error;
654 } else {
655 if (isl_stream_eat_if_available(s,
656 ISL_TOKEN_INT_DIV) &&
657 int_div_by_cst(s, &tok->u.v) < 0)
658 goto error;
659 res = add_cst(res, tok->u.v);
660 }
661 sign = 1;
662 } else if (tok->type == ISL_TOKEN_NAN) {
663 res = isl_pw_aff_add(res, nan_on_domain(space));
664 } else {
665 isl_stream_error(s, tok, "unexpected isl_token");
666 isl_stream_push_token(s, tok);
667 isl_pw_aff_free(res);
668 isl_space_free(space);
669 return NULL;
670 }
671 isl_token_free(tok);
672
673 tok = next_token(s);
674 if (tok && tok->type == '-') {
675 sign = -sign;
676 isl_token_free(tok);
677 } else if (tok && tok->type == '+') {
678 /* nothing */
679 isl_token_free(tok);
680 } else if (tok && tok->type == ISL_TOKEN_VALUE &&
681 isl_int_is_neg(tok->u.v)) {
682 isl_stream_push_token(s, tok);
683 } else {
684 if (tok)
685 isl_stream_push_token(s, tok);
686 break;
687 }
688 }
689
690 isl_space_free(space);
691 return res;
692 error:
693 isl_space_free(space);
694 isl_token_free(tok);
695 isl_pw_aff_free(res);
696 return NULL;
697 }
698
699 /* Is "type" the type of a comparison operator between lists
700 * of affine expressions?
701 */
is_list_comparator_type(int type)702 static int is_list_comparator_type(int type)
703 {
704 switch (type) {
705 case ISL_TOKEN_LEX_LT:
706 case ISL_TOKEN_LEX_GT:
707 case ISL_TOKEN_LEX_LE:
708 case ISL_TOKEN_LEX_GE:
709 return 1;
710 default:
711 return 0;
712 }
713 }
714
is_comparator(struct isl_token * tok)715 static int is_comparator(struct isl_token *tok)
716 {
717 if (!tok)
718 return 0;
719 if (is_list_comparator_type(tok->type))
720 return 1;
721
722 switch (tok->type) {
723 case ISL_TOKEN_LT:
724 case ISL_TOKEN_GT:
725 case ISL_TOKEN_LE:
726 case ISL_TOKEN_GE:
727 case ISL_TOKEN_NE:
728 case '=':
729 return 1;
730 default:
731 return 0;
732 }
733 }
734
735 static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
736 struct vars *v, __isl_take isl_map *map, int rational);
737 static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
738 __isl_take isl_space *space, struct vars *v, int rational);
739
740 /* Accept a ternary operator, given the first argument.
741 */
accept_ternary(__isl_keep isl_stream * s,__isl_take isl_map * cond,struct vars * v,int rational)742 static __isl_give isl_pw_aff *accept_ternary(__isl_keep isl_stream *s,
743 __isl_take isl_map *cond, struct vars *v, int rational)
744 {
745 isl_space *space;
746 isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond;
747
748 if (!cond)
749 return NULL;
750
751 if (isl_stream_eat(s, '?'))
752 goto error;
753
754 space = isl_space_wrap(isl_map_get_space(cond));
755 pwaff1 = accept_extended_affine(s, space, v, rational);
756 if (!pwaff1)
757 goto error;
758
759 if (isl_stream_eat(s, ':'))
760 goto error;
761
762 space = isl_pw_aff_get_domain_space(pwaff1);
763 pwaff2 = accept_extended_affine(s, space, v, rational);
764 if (!pwaff2)
765 goto error;
766
767 pa_cond = isl_set_indicator_function(isl_map_wrap(cond));
768 return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2);
769 error:
770 isl_map_free(cond);
771 isl_pw_aff_free(pwaff1);
772 isl_pw_aff_free(pwaff2);
773 return NULL;
774 }
775
776 /* Set *line and *col to those of the next token, if any.
777 */
set_current_line_col(__isl_keep isl_stream * s,int * line,int * col)778 static void set_current_line_col(__isl_keep isl_stream *s, int *line, int *col)
779 {
780 struct isl_token *tok;
781
782 tok = isl_stream_next_token(s);
783 if (!tok)
784 return;
785
786 *line = tok->line;
787 *col = tok->col;
788 isl_stream_push_token(s, tok);
789 }
790
791 /* Push a token encapsulating "pa" onto "s", with the given
792 * line and column.
793 */
push_aff(__isl_keep isl_stream * s,int line,int col,__isl_take isl_pw_aff * pa)794 static isl_stat push_aff(__isl_keep isl_stream *s, int line, int col,
795 __isl_take isl_pw_aff *pa)
796 {
797 struct isl_token *tok;
798
799 tok = isl_token_new(s->ctx, line, col, 0);
800 if (!tok)
801 goto error;
802 tok->type = ISL_TOKEN_AFF;
803 tok->u.pwaff = pa;
804 isl_stream_push_token(s, tok);
805
806 return isl_stat_ok;
807 error:
808 isl_pw_aff_free(pa);
809 return isl_stat_error;
810 }
811
812 /* Is the next token a comparison operator?
813 */
next_is_comparator(__isl_keep isl_stream * s)814 static int next_is_comparator(__isl_keep isl_stream *s)
815 {
816 int is_comp;
817 struct isl_token *tok;
818
819 tok = isl_stream_next_token(s);
820 if (!tok)
821 return 0;
822
823 is_comp = is_comparator(tok);
824 isl_stream_push_token(s, tok);
825
826 return is_comp;
827 }
828
829 /* Accept an affine expression that may involve ternary operators.
830 * We first read an affine expression.
831 * If it is not followed by a comparison operator, we simply return it.
832 * Otherwise, we assume the affine expression is part of the first
833 * argument of a ternary operator and try to parse that.
834 */
accept_extended_affine(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v,int rational)835 static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
836 __isl_take isl_space *space, struct vars *v, int rational)
837 {
838 isl_map *cond;
839 isl_pw_aff *pwaff;
840 int line = -1, col = -1;
841
842 set_current_line_col(s, &line, &col);
843
844 pwaff = accept_affine(s, space, v);
845 if (rational)
846 pwaff = isl_pw_aff_set_rational(pwaff);
847 if (!pwaff)
848 return NULL;
849 if (!next_is_comparator(s))
850 return pwaff;
851
852 space = isl_pw_aff_get_domain_space(pwaff);
853 cond = isl_map_universe(isl_space_unwrap(space));
854
855 if (push_aff(s, line, col, pwaff) < 0)
856 cond = isl_map_free(cond);
857 if (!cond)
858 return NULL;
859
860 cond = read_formula(s, v, cond, rational);
861
862 return accept_ternary(s, cond, v, rational);
863 }
864
read_var_def(__isl_keep isl_stream * s,__isl_take isl_map * map,enum isl_dim_type type,struct vars * v,int rational)865 static __isl_give isl_map *read_var_def(__isl_keep isl_stream *s,
866 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
867 int rational)
868 {
869 isl_pw_aff *def;
870 isl_size pos;
871 isl_map *def_map;
872
873 if (type == isl_dim_param)
874 pos = isl_map_dim(map, isl_dim_param);
875 else {
876 pos = isl_map_dim(map, isl_dim_in);
877 if (type == isl_dim_out) {
878 isl_size n_out = isl_map_dim(map, isl_dim_out);
879 if (pos < 0 || n_out < 0)
880 return isl_map_free(map);
881 pos += n_out;
882 }
883 type = isl_dim_in;
884 }
885 if (pos < 0)
886 return isl_map_free(map);
887 --pos;
888
889 def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)),
890 v, rational);
891 def_map = isl_map_from_pw_aff(def);
892 def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0);
893 def_map = isl_set_unwrap(isl_map_domain(def_map));
894
895 map = isl_map_intersect(map, def_map);
896
897 return map;
898 }
899
accept_affine_list(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v)900 static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
901 __isl_take isl_space *space, struct vars *v)
902 {
903 isl_pw_aff *pwaff;
904 isl_pw_aff_list *list;
905 struct isl_token *tok = NULL;
906
907 pwaff = accept_affine(s, isl_space_copy(space), v);
908 list = isl_pw_aff_list_from_pw_aff(pwaff);
909 if (!list)
910 goto error;
911
912 for (;;) {
913 tok = isl_stream_next_token(s);
914 if (!tok) {
915 isl_stream_error(s, NULL, "unexpected EOF");
916 goto error;
917 }
918 if (tok->type != ',') {
919 isl_stream_push_token(s, tok);
920 break;
921 }
922 isl_token_free(tok);
923
924 pwaff = accept_affine(s, isl_space_copy(space), v);
925 list = isl_pw_aff_list_concat(list,
926 isl_pw_aff_list_from_pw_aff(pwaff));
927 if (!list)
928 goto error;
929 }
930
931 isl_space_free(space);
932 return list;
933 error:
934 isl_space_free(space);
935 isl_pw_aff_list_free(list);
936 return NULL;
937 }
938
read_defined_var_list(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)939 static __isl_give isl_map *read_defined_var_list(__isl_keep isl_stream *s,
940 struct vars *v, __isl_take isl_map *map, int rational)
941 {
942 struct isl_token *tok;
943
944 while ((tok = isl_stream_next_token(s)) != NULL) {
945 int p;
946 int n = v->n;
947
948 if (tok->type != ISL_TOKEN_IDENT)
949 break;
950
951 p = vars_pos(v, tok->u.s, -1);
952 if (p < 0)
953 goto error;
954 if (p < n) {
955 isl_stream_error(s, tok, "expecting unique identifier");
956 goto error;
957 }
958
959 map = isl_map_add_dims(map, isl_dim_out, 1);
960
961 isl_token_free(tok);
962 tok = isl_stream_next_token(s);
963 if (tok && tok->type == '=') {
964 isl_token_free(tok);
965 map = read_var_def(s, map, isl_dim_out, v, rational);
966 tok = isl_stream_next_token(s);
967 }
968
969 if (!tok || tok->type != ',')
970 break;
971
972 isl_token_free(tok);
973 }
974 if (tok)
975 isl_stream_push_token(s, tok);
976
977 return map;
978 error:
979 isl_token_free(tok);
980 isl_map_free(map);
981 return NULL;
982 }
983
next_is_tuple(__isl_keep isl_stream * s)984 static int next_is_tuple(__isl_keep isl_stream *s)
985 {
986 struct isl_token *tok;
987 int is_tuple;
988
989 tok = isl_stream_next_token(s);
990 if (!tok)
991 return 0;
992 if (tok->type == '[') {
993 isl_stream_push_token(s, tok);
994 return 1;
995 }
996 if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) {
997 isl_stream_push_token(s, tok);
998 return 0;
999 }
1000
1001 is_tuple = isl_stream_next_token_is(s, '[');
1002
1003 isl_stream_push_token(s, tok);
1004
1005 return is_tuple;
1006 }
1007
1008 /* Does the next token mark the end of a tuple element?
1009 */
next_is_end_tuple_element(__isl_keep isl_stream * s)1010 static int next_is_end_tuple_element(__isl_keep isl_stream *s)
1011 {
1012 return isl_stream_next_token_is(s, ',') ||
1013 isl_stream_next_token_is(s, ']');
1014 }
1015
1016 /* Is the next token one that necessarily forms the start of a condition?
1017 */
next_is_condition_start(__isl_keep isl_stream * s)1018 static int next_is_condition_start(__isl_keep isl_stream *s)
1019 {
1020 return isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) ||
1021 isl_stream_next_token_is(s, ISL_TOKEN_NOT) ||
1022 isl_stream_next_token_is(s, ISL_TOKEN_TRUE) ||
1023 isl_stream_next_token_is(s, ISL_TOKEN_FALSE) ||
1024 isl_stream_next_token_is(s, ISL_TOKEN_MAP);
1025 }
1026
1027 /* Is "pa" an expression in term of earlier dimensions?
1028 * The alternative is that the dimension is defined to be equal to itself,
1029 * meaning that it has a universe domain and an expression that depends
1030 * on itself. "i" is the position of the expression in a sequence
1031 * of "n" expressions. The final dimensions of "pa" correspond to
1032 * these "n" expressions.
1033 */
pw_aff_is_expr(__isl_keep isl_pw_aff * pa,int i,int n)1034 static isl_bool pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n)
1035 {
1036 isl_aff *aff;
1037
1038 if (!pa)
1039 return isl_bool_error;
1040 if (pa->n != 1)
1041 return isl_bool_true;
1042 if (!isl_set_plain_is_universe(pa->p[0].set))
1043 return isl_bool_true;
1044
1045 aff = pa->p[0].aff;
1046 if (isl_int_is_zero(aff->v->el[aff->v->size - n + i]))
1047 return isl_bool_true;
1048 return isl_bool_false;
1049 }
1050
1051 /* Does the tuple contain any dimensions that are defined
1052 * in terms of earlier dimensions?
1053 */
tuple_has_expr(__isl_keep isl_multi_pw_aff * tuple)1054 static isl_bool tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple)
1055 {
1056 int i;
1057 isl_size n;
1058 isl_bool has_expr = isl_bool_false;
1059 isl_pw_aff *pa;
1060
1061 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
1062 if (n < 0)
1063 return isl_bool_error;
1064 for (i = 0; i < n; ++i) {
1065 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
1066 has_expr = pw_aff_is_expr(pa, i, n);
1067 isl_pw_aff_free(pa);
1068 if (has_expr < 0 || has_expr)
1069 break;
1070 }
1071
1072 return has_expr;
1073 }
1074
1075 /* Set the name of dimension "pos" in "space" to "name".
1076 * During printing, we add primes if the same name appears more than once
1077 * to distinguish the occurrences. Here, we remove those primes from "name"
1078 * before setting the name of the dimension.
1079 */
space_set_dim_name(__isl_take isl_space * space,int pos,char * name)1080 static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space,
1081 int pos, char *name)
1082 {
1083 char *prime;
1084
1085 if (!name)
1086 return space;
1087
1088 prime = strchr(name, '\'');
1089 if (prime)
1090 *prime = '\0';
1091 space = isl_space_set_dim_name(space, isl_dim_out, pos, name);
1092 if (prime)
1093 *prime = '\'';
1094
1095 return space;
1096 }
1097
1098 /* Construct an isl_pw_aff defined on a "space" (with v->n variables)
1099 * that is equal to the last of those variables.
1100 */
identity_tuple_el_on_space(__isl_take isl_space * space,struct vars * v)1101 static __isl_give isl_pw_aff *identity_tuple_el_on_space(
1102 __isl_take isl_space *space, struct vars *v)
1103 {
1104 isl_aff *aff;
1105
1106 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
1107 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n - 1, 1);
1108 return isl_pw_aff_from_aff(aff);
1109 }
1110
1111 /* Construct an isl_pw_aff defined on the domain space of "pa"
1112 * that is equal to the last variable in "v".
1113 *
1114 * That is, if D is the domain space of "pa", then construct
1115 *
1116 * D[..., i] -> i.
1117 */
init_range(__isl_keep isl_pw_aff * pa,struct vars * v)1118 static __isl_give isl_pw_aff *init_range(__isl_keep isl_pw_aff *pa,
1119 struct vars *v)
1120 {
1121 isl_space *space;
1122
1123 space = isl_pw_aff_get_domain_space(pa);
1124 return identity_tuple_el_on_space(space, v);
1125 }
1126
1127 /* Impose the lower bound "lower" on the variable represented by "range_pa".
1128 *
1129 * In particular, "range_pa" is of the form
1130 *
1131 * D[..., i] -> i : C
1132 *
1133 * with D also the domains space of "lower' and "C" some constraints.
1134 *
1135 * Return the expression
1136 *
1137 * D[..., i] -> i : C and i >= lower
1138 */
set_lower(__isl_take isl_pw_aff * range_pa,__isl_take isl_pw_aff * lower)1139 static __isl_give isl_pw_aff *set_lower(__isl_take isl_pw_aff *range_pa,
1140 __isl_take isl_pw_aff *lower)
1141 {
1142 isl_set *range;
1143
1144 range = isl_pw_aff_ge_set(isl_pw_aff_copy(range_pa), lower);
1145 return isl_pw_aff_intersect_domain(range_pa, range);
1146 }
1147
1148 /* Impose the upper bound "upper" on the variable represented by "range_pa".
1149 *
1150 * In particular, "range_pa" is of the form
1151 *
1152 * D[..., i] -> i : C
1153 *
1154 * with D also the domains space of "upper' and "C" some constraints.
1155 *
1156 * Return the expression
1157 *
1158 * D[..., i] -> i : C and i <= upper
1159 */
set_upper(__isl_take isl_pw_aff * range_pa,__isl_take isl_pw_aff * upper)1160 static __isl_give isl_pw_aff *set_upper(__isl_take isl_pw_aff *range_pa,
1161 __isl_take isl_pw_aff *upper)
1162 {
1163 isl_set *range;
1164
1165 range = isl_pw_aff_le_set(isl_pw_aff_copy(range_pa), upper);
1166 return isl_pw_aff_intersect_domain(range_pa, range);
1167 }
1168
1169 /* Construct a piecewise affine expression corresponding
1170 * to the last variable in "v" that is greater than or equal to "pa".
1171 *
1172 * In particular, if D is the domain space of "pa",
1173 * then construct the expression
1174 *
1175 * D[..., i] -> i,
1176 *
1177 * impose lower bound "pa" and return
1178 *
1179 * D[..., i] -> i : i >= pa
1180 */
construct_lower(__isl_take isl_pw_aff * pa,struct vars * v)1181 static __isl_give isl_pw_aff *construct_lower(__isl_take isl_pw_aff *pa,
1182 struct vars *v)
1183 {
1184 return set_lower(init_range(pa, v), pa);
1185 }
1186
1187 /* Construct a piecewise affine expression corresponding
1188 * to the last variable in "v" that is smaller than or equal to "pa".
1189 *
1190 * In particular, if D is the domain space of "pa",
1191 * then construct the expression
1192 *
1193 * D[..., i] -> i,
1194 *
1195 * impose lower bound "pa" and return
1196 *
1197 * D[..., i] -> i : i <= pa
1198 */
construct_upper(__isl_take isl_pw_aff * pa,struct vars * v)1199 static __isl_give isl_pw_aff *construct_upper(__isl_take isl_pw_aff *pa,
1200 struct vars *v)
1201 {
1202 return set_upper(init_range(pa, v), pa);
1203 }
1204
1205 /* Construct a piecewise affine expression corresponding
1206 * to the last variable in "v" that ranges between "pa" and "pa2".
1207 *
1208 * In particular, if D is the domain space of "pa" (and "pa2"),
1209 * then construct the expression
1210 *
1211 * D[..., i] -> i,
1212 *
1213 * impose lower bound "pa" and upper bound "pa2" and return
1214 *
1215 * D[..., i] -> i : pa <= i <= pa2
1216 */
construct_range(__isl_take isl_pw_aff * pa,__isl_take isl_pw_aff * pa2,struct vars * v)1217 static __isl_give isl_pw_aff *construct_range(__isl_take isl_pw_aff *pa,
1218 __isl_take isl_pw_aff *pa2, struct vars *v)
1219 {
1220 return set_upper(set_lower(init_range(pa, v), pa), pa2);
1221 }
1222
1223 static int resolve_paren_expr(__isl_keep isl_stream *s,
1224 struct vars *v, __isl_take isl_map *map, int rational);
1225
1226 /* Given that the (piecewise) affine expression "pa"
1227 * has just been parsed, followed by a colon,
1228 * continue parsing as part of a piecewise affine expression.
1229 *
1230 * In particular, check if the colon is followed by a condition.
1231 * If so, parse the conditions(a) on "pa" and include them in the domain.
1232 * Otherwise, if the colon is followed by another (piecewise) affine expression
1233 * then consider the two expressions as endpoints of a range of values and
1234 * return a piecewise affine expression that takes values in that range.
1235 * Note that an affine expression followed by a comparison operator
1236 * is considered to be part of a condition.
1237 * If the colon is not followed by anything (inside the tuple element),
1238 * then consider "pa" as a lower bound on a range of values without upper bound
1239 * and return a piecewise affine expression that takes values in that range.
1240 */
update_piecewise_affine_colon(__isl_take isl_pw_aff * pa,__isl_keep isl_stream * s,struct vars * v,int rational)1241 static __isl_give isl_pw_aff *update_piecewise_affine_colon(
1242 __isl_take isl_pw_aff *pa, __isl_keep isl_stream *s,
1243 struct vars *v, int rational)
1244 {
1245 isl_space *dom_space;
1246 isl_map *map;
1247
1248 dom_space = isl_pw_aff_get_domain_space(pa);
1249 map = isl_map_universe(isl_space_from_domain(dom_space));
1250
1251 if (isl_stream_next_token_is(s, '('))
1252 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
1253 goto error;
1254 if (next_is_end_tuple_element(s)) {
1255 isl_map_free(map);
1256 return construct_lower(pa, v);
1257 }
1258 if (!next_is_condition_start(s)) {
1259 int line = -1, col = -1;
1260 isl_space *space;
1261 isl_pw_aff *pa2;
1262
1263 set_current_line_col(s, &line, &col);
1264 space = isl_space_wrap(isl_map_get_space(map));
1265 pa2 = accept_affine(s, space, v);
1266 if (rational)
1267 pa2 = isl_pw_aff_set_rational(pa2);
1268 if (!next_is_comparator(s)) {
1269 isl_map_free(map);
1270 pa2 = isl_pw_aff_domain_factor_domain(pa2);
1271 return construct_range(pa, pa2, v);
1272 }
1273 if (push_aff(s, line, col, pa2) < 0)
1274 goto error;
1275 }
1276
1277 map = read_formula(s, v, map, rational);
1278 pa = isl_pw_aff_intersect_domain(pa, isl_map_domain(map));
1279
1280 return pa;
1281 error:
1282 isl_map_free(map);
1283 isl_pw_aff_free(pa);
1284 return NULL;
1285 }
1286
1287 /* Accept a piecewise affine expression.
1288 *
1289 * At the outer level, the piecewise affine expression may be of the form
1290 *
1291 * aff1 : condition1; aff2 : conditions2; ...
1292 *
1293 * or one of
1294 *
1295 * aff :
1296 * aff1 : aff2
1297 * : aff
1298 * :
1299 *
1300 * or simply
1301 *
1302 * aff
1303 *
1304 * each of the affine expressions may in turn include ternary operators.
1305 *
1306 * If the first token is a colon, then the expression must be
1307 * ":" or ": aff2", depending on whether anything follows the colon
1308 * inside the tuple element.
1309 * The first is considered to represent an arbitrary value.
1310 * The second is considered to represent a range of values
1311 * with the given upper bound and no lower bound.
1312 *
1313 * There may be parentheses around some subexpression of "aff1"
1314 * around "aff1" itself, around "aff1 : condition1" and/or
1315 * around the entire piecewise affine expression.
1316 * We therefore remove the opening parenthesis (if any) from the stream
1317 * in case the closing parenthesis follows the colon, but if the closing
1318 * parenthesis is the first thing in the stream after the parsed affine
1319 * expression, we push the parsed expression onto the stream and parse
1320 * again in case the parentheses enclose some subexpression of "aff1".
1321 */
accept_piecewise_affine(__isl_keep isl_stream * s,__isl_take isl_space * space,struct vars * v,int rational)1322 static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s,
1323 __isl_take isl_space *space, struct vars *v, int rational)
1324 {
1325 isl_pw_aff *res;
1326 isl_space *res_space;
1327
1328 if (isl_stream_eat_if_available(s, ':')) {
1329 if (next_is_end_tuple_element(s))
1330 return identity_tuple_el_on_space(space, v);
1331 else
1332 return construct_upper(accept_affine(s, space, v), v);
1333 }
1334
1335 res_space = isl_space_from_domain(isl_space_copy(space));
1336 res_space = isl_space_add_dims(res_space, isl_dim_out, 1);
1337 res = isl_pw_aff_empty(res_space);
1338 do {
1339 isl_pw_aff *pa;
1340 int seen_paren;
1341 int line = -1, col = -1;
1342
1343 set_current_line_col(s, &line, &col);
1344 seen_paren = isl_stream_eat_if_available(s, '(');
1345 if (seen_paren)
1346 pa = accept_piecewise_affine(s, isl_space_copy(space),
1347 v, rational);
1348 else
1349 pa = accept_extended_affine(s, isl_space_copy(space),
1350 v, rational);
1351 if (seen_paren && isl_stream_eat_if_available(s, ')')) {
1352 seen_paren = 0;
1353 if (push_aff(s, line, col, pa) < 0)
1354 goto error;
1355 pa = accept_extended_affine(s, isl_space_copy(space),
1356 v, rational);
1357 }
1358 if (isl_stream_eat_if_available(s, ':'))
1359 pa = update_piecewise_affine_colon(pa, s, v, rational);
1360
1361 res = isl_pw_aff_union_add(res, pa);
1362
1363 if (seen_paren && isl_stream_eat(s, ')'))
1364 goto error;
1365 } while (isl_stream_eat_if_available(s, ';'));
1366
1367 isl_space_free(space);
1368
1369 return res;
1370 error:
1371 isl_space_free(space);
1372 return isl_pw_aff_free(res);
1373 }
1374
1375 /* Read an affine expression from "s" for use in read_tuple.
1376 *
1377 * accept_extended_affine requires a wrapped space as input.
1378 * read_tuple on the other hand expects each isl_pw_aff
1379 * to have an anonymous space. We therefore adjust the space
1380 * of the isl_pw_aff before returning it.
1381 */
read_tuple_var_def(__isl_keep isl_stream * s,struct vars * v,int rational)1382 static __isl_give isl_pw_aff *read_tuple_var_def(__isl_keep isl_stream *s,
1383 struct vars *v, int rational)
1384 {
1385 isl_space *space;
1386 isl_pw_aff *def;
1387
1388 space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0));
1389
1390 def = accept_piecewise_affine(s, space, v, rational);
1391 def = isl_pw_aff_domain_factor_domain(def);
1392
1393 return def;
1394 }
1395
1396 /* Read a list of tuple elements by calling "read_el" on each of them and
1397 * return a space with the same number of set dimensions derived from
1398 * the parameter space "space" and possibly updated by "read_el".
1399 * The elements in the list are separated by either "," or "][".
1400 * If "comma" is set then only "," is allowed.
1401 */
read_tuple_list(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,int comma,__isl_give isl_space * (* read_el)(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,void * user),void * user)1402 static __isl_give isl_space *read_tuple_list(__isl_keep isl_stream *s,
1403 struct vars *v, __isl_take isl_space *space, int rational, int comma,
1404 __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
1405 struct vars *v, __isl_take isl_space *space, int rational,
1406 void *user),
1407 void *user)
1408 {
1409 if (!space)
1410 return NULL;
1411
1412 space = isl_space_set_from_params(space);
1413
1414 if (isl_stream_next_token_is(s, ']'))
1415 return space;
1416
1417 for (;;) {
1418 struct isl_token *tok;
1419
1420 space = isl_space_add_dims(space, isl_dim_set, 1);
1421
1422 space = read_el(s, v, space, rational, user);
1423 if (!space)
1424 return NULL;
1425
1426 tok = isl_stream_next_token(s);
1427 if (!comma && tok && tok->type == ']' &&
1428 isl_stream_next_token_is(s, '[')) {
1429 isl_token_free(tok);
1430 tok = isl_stream_next_token(s);
1431 } else if (!tok || tok->type != ',') {
1432 if (tok)
1433 isl_stream_push_token(s, tok);
1434 break;
1435 }
1436
1437 isl_token_free(tok);
1438 }
1439
1440 return space;
1441 }
1442
1443 /* Read a tuple space from "s" derived from the parameter space "space".
1444 * Call "read_el" on each element in the tuples.
1445 */
read_tuple_space(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,int comma,__isl_give isl_space * (* read_el)(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,void * user),void * user)1446 static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s,
1447 struct vars *v, __isl_take isl_space *space, int rational, int comma,
1448 __isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
1449 struct vars *v, __isl_take isl_space *space, int rational,
1450 void *user),
1451 void *user)
1452 {
1453 struct isl_token *tok;
1454 char *name = NULL;
1455 isl_space *res = NULL;
1456
1457 tok = isl_stream_next_token(s);
1458 if (!tok)
1459 goto error;
1460 if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) {
1461 name = strdup(tok->u.s);
1462 isl_token_free(tok);
1463 if (!name)
1464 goto error;
1465 } else
1466 isl_stream_push_token(s, tok);
1467 if (isl_stream_eat(s, '['))
1468 goto error;
1469 if (next_is_tuple(s)) {
1470 isl_space *out;
1471 res = read_tuple_space(s, v, isl_space_copy(space),
1472 rational, comma, read_el, user);
1473 if (isl_stream_eat(s, ISL_TOKEN_TO))
1474 goto error;
1475 out = read_tuple_space(s, v, isl_space_copy(space),
1476 rational, comma, read_el, user);
1477 res = isl_space_product(res, out);
1478 } else
1479 res = read_tuple_list(s, v, isl_space_copy(space),
1480 rational, comma, read_el, user);
1481 if (isl_stream_eat(s, ']'))
1482 goto error;
1483
1484 if (name) {
1485 res = isl_space_set_tuple_name(res, isl_dim_set, name);
1486 free(name);
1487 }
1488
1489 isl_space_free(space);
1490 return res;
1491 error:
1492 free(name);
1493 isl_space_free(res);
1494 isl_space_free(space);
1495 return NULL;
1496 }
1497
1498 /* Construct an isl_pw_aff defined on a space with v->n variables
1499 * that is equal to the last of those variables.
1500 */
identity_tuple_el(struct vars * v)1501 static __isl_give isl_pw_aff *identity_tuple_el(struct vars *v)
1502 {
1503 isl_space *space;
1504
1505 space = isl_space_set_alloc(v->ctx, 0, v->n);
1506 return identity_tuple_el_on_space(space, v);
1507 }
1508
1509 /* This function is called for each element in a tuple inside read_tuple.
1510 * Add a new variable to "v" and construct a corresponding isl_pw_aff defined
1511 * over a space containing all variables in "v" defined so far.
1512 * The isl_pw_aff expresses the new variable in terms of earlier variables
1513 * if a definition is provided. Otherwise, it is represented as being
1514 * equal to itself.
1515 * Add the isl_pw_aff to *list.
1516 * If the new variable was named, then adjust "space" accordingly and
1517 * return the updated space.
1518 */
read_tuple_pw_aff_el(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,void * user)1519 static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s,
1520 struct vars *v, __isl_take isl_space *space, int rational, void *user)
1521 {
1522 isl_pw_aff_list **list = (isl_pw_aff_list **) user;
1523 isl_pw_aff *pa;
1524 struct isl_token *tok;
1525 int new_name = 0;
1526
1527 tok = next_token(s);
1528 if (!tok) {
1529 isl_stream_error(s, NULL, "unexpected EOF");
1530 return isl_space_free(space);
1531 }
1532
1533 if (tok->type == ISL_TOKEN_IDENT) {
1534 int n = v->n;
1535 int p = vars_pos(v, tok->u.s, -1);
1536 if (p < 0)
1537 goto error;
1538 new_name = p >= n;
1539 }
1540
1541 if (tok->type == '*') {
1542 if (vars_add_anon(v) < 0)
1543 goto error;
1544 isl_token_free(tok);
1545 pa = identity_tuple_el(v);
1546 } else if (new_name) {
1547 isl_size pos = isl_space_dim(space, isl_dim_out);
1548 if (pos < 0)
1549 goto error;
1550 pos -= 1;
1551 space = space_set_dim_name(space, pos, v->v->name);
1552 isl_token_free(tok);
1553 if (isl_stream_eat_if_available(s, '='))
1554 pa = read_tuple_var_def(s, v, rational);
1555 else
1556 pa = identity_tuple_el(v);
1557 } else {
1558 isl_stream_push_token(s, tok);
1559 tok = NULL;
1560 if (vars_add_anon(v) < 0)
1561 goto error;
1562 pa = read_tuple_var_def(s, v, rational);
1563 }
1564
1565 *list = isl_pw_aff_list_add(*list, pa);
1566 if (!*list)
1567 return isl_space_free(space);
1568
1569 return space;
1570 error:
1571 isl_token_free(tok);
1572 return isl_space_free(space);
1573 }
1574
1575 /* Read a tuple and represent it as an isl_multi_pw_aff.
1576 * The range space of the isl_multi_pw_aff is the space of the tuple.
1577 * The domain space is an anonymous space
1578 * with a dimension for each variable in the set of variables in "v",
1579 * including the variables in the range.
1580 * If a given dimension is not defined in terms of earlier dimensions in
1581 * the input, then the corresponding isl_pw_aff is set equal to one time
1582 * the variable corresponding to the dimension being defined.
1583 *
1584 * The elements in the tuple are collected in a list by read_tuple_pw_aff_el.
1585 * Each element in this list is defined over a space representing
1586 * the variables defined so far. We need to adjust the earlier
1587 * elements to have as many variables in the domain as the final
1588 * element in the list.
1589 */
read_tuple(__isl_keep isl_stream * s,struct vars * v,int rational,int comma)1590 static __isl_give isl_multi_pw_aff *read_tuple(__isl_keep isl_stream *s,
1591 struct vars *v, int rational, int comma)
1592 {
1593 int i;
1594 isl_size n;
1595 isl_space *space;
1596 isl_pw_aff_list *list;
1597
1598 space = isl_space_params_alloc(v->ctx, 0);
1599 list = isl_pw_aff_list_alloc(s->ctx, 0);
1600 space = read_tuple_space(s, v, space, rational, comma,
1601 &read_tuple_pw_aff_el, &list);
1602 n = isl_space_dim(space, isl_dim_set);
1603 if (n < 0)
1604 space = isl_space_free(space);
1605 for (i = 0; i + 1 < n; ++i) {
1606 isl_pw_aff *pa;
1607
1608 pa = isl_pw_aff_list_get_pw_aff(list, i);
1609 pa = isl_pw_aff_add_dims(pa, isl_dim_in, n - (i + 1));
1610 list = isl_pw_aff_list_set_pw_aff(list, i, pa);
1611 }
1612
1613 space = isl_space_from_range(space);
1614 space = isl_space_add_dims(space, isl_dim_in, v->n);
1615 return isl_multi_pw_aff_from_pw_aff_list(space, list);
1616 }
1617
1618 /* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map".
1619 * We first create the appropriate space in "map" based on the range
1620 * space of this isl_multi_pw_aff. Then, we add equalities based
1621 * on the affine expressions. These live in an anonymous space,
1622 * however, so we first need to reset the space to that of "map".
1623 */
map_from_tuple(__isl_take isl_multi_pw_aff * tuple,__isl_take isl_map * map,enum isl_dim_type type,struct vars * v,int rational)1624 static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple,
1625 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
1626 int rational)
1627 {
1628 int i;
1629 isl_size n;
1630 isl_ctx *ctx;
1631 isl_space *space = NULL;
1632
1633 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
1634 if (!map || n < 0)
1635 goto error;
1636 ctx = isl_multi_pw_aff_get_ctx(tuple);
1637 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
1638 if (!space)
1639 goto error;
1640
1641 if (type == isl_dim_param) {
1642 if (isl_space_has_tuple_name(space, isl_dim_set) ||
1643 isl_space_is_wrapping(space)) {
1644 isl_die(ctx, isl_error_invalid,
1645 "parameter tuples cannot be named or nested",
1646 goto error);
1647 }
1648 map = isl_map_add_dims(map, type, n);
1649 for (i = 0; i < n; ++i) {
1650 isl_id *id;
1651 if (!isl_space_has_dim_name(space, isl_dim_set, i))
1652 isl_die(ctx, isl_error_invalid,
1653 "parameters must be named",
1654 goto error);
1655 id = isl_space_get_dim_id(space, isl_dim_set, i);
1656 map = isl_map_set_dim_id(map, isl_dim_param, i, id);
1657 }
1658 } else if (type == isl_dim_in) {
1659 isl_set *set;
1660
1661 set = isl_set_universe(isl_space_copy(space));
1662 if (rational)
1663 set = isl_set_set_rational(set);
1664 set = isl_set_intersect_params(set, isl_map_params(map));
1665 map = isl_map_from_domain(set);
1666 } else {
1667 isl_set *set;
1668
1669 set = isl_set_universe(isl_space_copy(space));
1670 if (rational)
1671 set = isl_set_set_rational(set);
1672 map = isl_map_from_domain_and_range(isl_map_domain(map), set);
1673 }
1674
1675 for (i = 0; i < n; ++i) {
1676 isl_pw_aff *pa;
1677 isl_space *space;
1678 isl_aff *aff;
1679 isl_set *set;
1680 isl_map *map_i;
1681
1682 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
1683 space = isl_pw_aff_get_domain_space(pa);
1684 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
1685 aff = isl_aff_add_coefficient_si(aff,
1686 isl_dim_in, v->n - n + i, -1);
1687 pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff));
1688 if (rational)
1689 pa = isl_pw_aff_set_rational(pa);
1690 set = isl_pw_aff_zero_set(pa);
1691 map_i = isl_map_from_range(set);
1692 map_i = isl_map_reset_space(map_i, isl_map_get_space(map));
1693 map = isl_map_intersect(map, map_i);
1694 }
1695
1696 isl_space_free(space);
1697 isl_multi_pw_aff_free(tuple);
1698 return map;
1699 error:
1700 isl_space_free(space);
1701 isl_multi_pw_aff_free(tuple);
1702 isl_map_free(map);
1703 return NULL;
1704 }
1705
1706 /* Read a tuple from "s" and add it to "map".
1707 * The tuple is initially represented as an isl_multi_pw_aff and
1708 * then added to "map".
1709 */
read_map_tuple(__isl_keep isl_stream * s,__isl_take isl_map * map,enum isl_dim_type type,struct vars * v,int rational,int comma)1710 static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s,
1711 __isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
1712 int rational, int comma)
1713 {
1714 isl_multi_pw_aff *tuple;
1715
1716 tuple = read_tuple(s, v, rational, comma);
1717 if (!tuple)
1718 return isl_map_free(map);
1719
1720 return map_from_tuple(tuple, map, type, v, rational);
1721 }
1722
1723 /* Given two equal-length lists of piecewise affine expression with the space
1724 * of "set" as domain, construct a set in the same space that expresses
1725 * that "left" and "right" satisfy the comparison "type".
1726 *
1727 * A space is constructed of the same dimension as the number of elements
1728 * in the two lists. The comparison is then expressed in a map from
1729 * this space to itself and wrapped into a set. Finally the two lists
1730 * of piecewise affine expressions are plugged into this set.
1731 *
1732 * Let S be the space of "set" and T the constructed space.
1733 * The lists are first changed into two isl_multi_pw_affs in S -> T and
1734 * then combined into an isl_multi_pw_aff in S -> [T -> T],
1735 * while the comparison is first expressed in T -> T, then [T -> T]
1736 * and finally in S.
1737 */
list_cmp(__isl_keep isl_set * set,int type,__isl_take isl_pw_aff_list * left,__isl_take isl_pw_aff_list * right)1738 static __isl_give isl_set *list_cmp(__isl_keep isl_set *set, int type,
1739 __isl_take isl_pw_aff_list *left, __isl_take isl_pw_aff_list *right)
1740 {
1741 isl_space *space;
1742 isl_size n;
1743 isl_multi_pw_aff *mpa1, *mpa2;
1744
1745 n = isl_pw_aff_list_n_pw_aff(left);
1746 if (!set || n < 0 || !right)
1747 goto error;
1748
1749 space = isl_set_get_space(set);
1750 space = isl_space_from_domain(space);
1751 space = isl_space_add_dims(space, isl_dim_out, n);
1752 mpa1 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), left);
1753 mpa2 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), right);
1754 mpa1 = isl_multi_pw_aff_range_product(mpa1, mpa2);
1755
1756 space = isl_space_range(space);
1757 switch (type) {
1758 case ISL_TOKEN_LEX_LT:
1759 set = isl_map_wrap(isl_map_lex_lt(space));
1760 break;
1761 case ISL_TOKEN_LEX_GT:
1762 set = isl_map_wrap(isl_map_lex_gt(space));
1763 break;
1764 case ISL_TOKEN_LEX_LE:
1765 set = isl_map_wrap(isl_map_lex_le(space));
1766 break;
1767 case ISL_TOKEN_LEX_GE:
1768 set = isl_map_wrap(isl_map_lex_ge(space));
1769 break;
1770 default:
1771 isl_multi_pw_aff_free(mpa1);
1772 isl_space_free(space);
1773 isl_die(isl_set_get_ctx(set), isl_error_internal,
1774 "unhandled list comparison type", return NULL);
1775 }
1776 set = isl_set_preimage_multi_pw_aff(set, mpa1);
1777 return set;
1778 error:
1779 isl_pw_aff_list_free(left);
1780 isl_pw_aff_list_free(right);
1781 return NULL;
1782 }
1783
1784 /* Construct constraints of the form
1785 *
1786 * a op b
1787 *
1788 * where a is an element in "left", op is an operator of type "type" and
1789 * b is an element in "right", add the constraints to "set" and return
1790 * the result.
1791 * "rational" is set if the constraints should be treated as
1792 * a rational constraints.
1793 *
1794 * If "type" is the type of a comparison operator between lists
1795 * of affine expressions, then a single (compound) constraint
1796 * is constructed by list_cmp instead.
1797 */
construct_constraints(__isl_take isl_set * set,int type,__isl_keep isl_pw_aff_list * left,__isl_keep isl_pw_aff_list * right,int rational)1798 static __isl_give isl_set *construct_constraints(
1799 __isl_take isl_set *set, int type,
1800 __isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right,
1801 int rational)
1802 {
1803 isl_set *cond;
1804
1805 left = isl_pw_aff_list_copy(left);
1806 right = isl_pw_aff_list_copy(right);
1807 if (rational) {
1808 left = isl_pw_aff_list_set_rational(left);
1809 right = isl_pw_aff_list_set_rational(right);
1810 }
1811 if (is_list_comparator_type(type))
1812 cond = list_cmp(set, type, left, right);
1813 else if (type == ISL_TOKEN_LE)
1814 cond = isl_pw_aff_list_le_set(left, right);
1815 else if (type == ISL_TOKEN_GE)
1816 cond = isl_pw_aff_list_ge_set(left, right);
1817 else if (type == ISL_TOKEN_LT)
1818 cond = isl_pw_aff_list_lt_set(left, right);
1819 else if (type == ISL_TOKEN_GT)
1820 cond = isl_pw_aff_list_gt_set(left, right);
1821 else if (type == ISL_TOKEN_NE)
1822 cond = isl_pw_aff_list_ne_set(left, right);
1823 else
1824 cond = isl_pw_aff_list_eq_set(left, right);
1825
1826 return isl_set_intersect(set, cond);
1827 }
1828
1829 /* Read a constraint from "s", add it to "map" and return the result.
1830 * "v" contains a description of the identifiers parsed so far.
1831 * "rational" is set if the constraint should be treated as
1832 * a rational constraint.
1833 * The constraint read from "s" may be applied to multiple pairs
1834 * of affine expressions and may be chained.
1835 * In particular, a list of affine expressions is read, followed
1836 * by a comparison operator and another list of affine expressions.
1837 * The comparison operator is then applied to each pair of elements
1838 * in the two lists and the results are added to "map".
1839 * However, if the operator expects two lists of affine expressions,
1840 * then it is applied directly to those lists and the two lists
1841 * are required to have the same length.
1842 * If the next token is another comparison operator, then another
1843 * list of affine expressions is read and the process repeats.
1844 *
1845 * The processing is performed on a wrapped copy of "map" because
1846 * an affine expression cannot have a binary relation as domain.
1847 */
add_constraint(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)1848 static __isl_give isl_map *add_constraint(__isl_keep isl_stream *s,
1849 struct vars *v, __isl_take isl_map *map, int rational)
1850 {
1851 struct isl_token *tok;
1852 int type;
1853 isl_pw_aff_list *list1 = NULL, *list2 = NULL;
1854 isl_size n1, n2;
1855 isl_set *set;
1856
1857 set = isl_map_wrap(map);
1858 list1 = accept_affine_list(s, isl_set_get_space(set), v);
1859 if (!list1)
1860 goto error;
1861 tok = isl_stream_next_token(s);
1862 if (!is_comparator(tok)) {
1863 isl_stream_error(s, tok, "missing operator");
1864 if (tok)
1865 isl_stream_push_token(s, tok);
1866 goto error;
1867 }
1868 type = tok->type;
1869 isl_token_free(tok);
1870 for (;;) {
1871 list2 = accept_affine_list(s, isl_set_get_space(set), v);
1872 n1 = isl_pw_aff_list_n_pw_aff(list1);
1873 n2 = isl_pw_aff_list_n_pw_aff(list2);
1874 if (n1 < 0 || n2 < 0)
1875 goto error;
1876 if (is_list_comparator_type(type) && n1 != n2) {
1877 isl_stream_error(s, NULL,
1878 "list arguments not of same size");
1879 goto error;
1880 }
1881
1882 set = construct_constraints(set, type, list1, list2, rational);
1883 isl_pw_aff_list_free(list1);
1884 list1 = list2;
1885
1886 if (!next_is_comparator(s))
1887 break;
1888 tok = isl_stream_next_token(s);
1889 type = tok->type;
1890 isl_token_free(tok);
1891 }
1892 isl_pw_aff_list_free(list1);
1893
1894 return isl_set_unwrap(set);
1895 error:
1896 isl_pw_aff_list_free(list1);
1897 isl_pw_aff_list_free(list2);
1898 isl_set_free(set);
1899 return NULL;
1900 }
1901
read_exists(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)1902 static __isl_give isl_map *read_exists(__isl_keep isl_stream *s,
1903 struct vars *v, __isl_take isl_map *map, int rational)
1904 {
1905 int n = v->n;
1906 int seen_paren = isl_stream_eat_if_available(s, '(');
1907
1908 map = isl_map_from_domain(isl_map_wrap(map));
1909 map = read_defined_var_list(s, v, map, rational);
1910
1911 if (isl_stream_eat(s, ':'))
1912 goto error;
1913
1914 map = read_formula(s, v, map, rational);
1915 map = isl_set_unwrap(isl_map_domain(map));
1916
1917 vars_drop(v, v->n - n);
1918 if (seen_paren && isl_stream_eat(s, ')'))
1919 goto error;
1920
1921 return map;
1922 error:
1923 isl_map_free(map);
1924 return NULL;
1925 }
1926
1927 /* Parse an expression between parentheses and push the result
1928 * back on the stream.
1929 *
1930 * The parsed expression may be either an affine expression
1931 * or a condition. The first type is pushed onto the stream
1932 * as an isl_pw_aff, while the second is pushed as an isl_map.
1933 *
1934 * If the initial token indicates the start of a condition,
1935 * we parse it as such.
1936 * Otherwise, we first parse an affine expression and push
1937 * that onto the stream. If the affine expression covers the
1938 * entire expression between parentheses, we return.
1939 * Otherwise, we assume that the affine expression is the
1940 * start of a condition and continue parsing.
1941 */
resolve_paren_expr(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)1942 static int resolve_paren_expr(__isl_keep isl_stream *s,
1943 struct vars *v, __isl_take isl_map *map, int rational)
1944 {
1945 struct isl_token *tok, *tok2;
1946 int has_paren;
1947 int line, col;
1948 isl_pw_aff *pwaff;
1949
1950 tok = isl_stream_next_token(s);
1951 if (!tok || tok->type != '(')
1952 goto error;
1953
1954 if (isl_stream_next_token_is(s, '('))
1955 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
1956 goto error;
1957
1958 if (next_is_condition_start(s)) {
1959 map = read_formula(s, v, map, rational);
1960 if (isl_stream_eat(s, ')'))
1961 goto error;
1962 tok->type = ISL_TOKEN_MAP;
1963 tok->u.map = map;
1964 isl_stream_push_token(s, tok);
1965 return 0;
1966 }
1967
1968 tok2 = isl_stream_next_token(s);
1969 if (!tok2)
1970 goto error;
1971 line = tok2->line;
1972 col = tok2->col;
1973 isl_stream_push_token(s, tok2);
1974
1975 pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v);
1976 if (!pwaff)
1977 goto error;
1978
1979 has_paren = isl_stream_eat_if_available(s, ')');
1980
1981 if (push_aff(s, line, col, pwaff) < 0)
1982 goto error;
1983
1984 if (has_paren) {
1985 isl_token_free(tok);
1986 isl_map_free(map);
1987 return 0;
1988 }
1989
1990 map = read_formula(s, v, map, rational);
1991 if (isl_stream_eat(s, ')'))
1992 goto error;
1993
1994 tok->type = ISL_TOKEN_MAP;
1995 tok->u.map = map;
1996 isl_stream_push_token(s, tok);
1997
1998 return 0;
1999 error:
2000 isl_token_free(tok);
2001 isl_map_free(map);
2002 return -1;
2003 }
2004
read_conjunct(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)2005 static __isl_give isl_map *read_conjunct(__isl_keep isl_stream *s,
2006 struct vars *v, __isl_take isl_map *map, int rational)
2007 {
2008 if (isl_stream_next_token_is(s, '('))
2009 if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
2010 goto error;
2011
2012 if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
2013 struct isl_token *tok;
2014 tok = isl_stream_next_token(s);
2015 if (!tok)
2016 goto error;
2017 isl_map_free(map);
2018 map = isl_map_copy(tok->u.map);
2019 isl_token_free(tok);
2020 return map;
2021 }
2022
2023 if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
2024 return read_exists(s, v, map, rational);
2025
2026 if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
2027 return map;
2028
2029 if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
2030 isl_space *space = isl_map_get_space(map);
2031 isl_map_free(map);
2032 return isl_map_empty(space);
2033 }
2034
2035 return add_constraint(s, v, map, rational);
2036 error:
2037 isl_map_free(map);
2038 return NULL;
2039 }
2040
read_conjuncts(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)2041 static __isl_give isl_map *read_conjuncts(__isl_keep isl_stream *s,
2042 struct vars *v, __isl_take isl_map *map, int rational)
2043 {
2044 isl_map *res;
2045 int negate;
2046
2047 negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
2048 res = read_conjunct(s, v, isl_map_copy(map), rational);
2049 if (negate)
2050 res = isl_map_subtract(isl_map_copy(map), res);
2051
2052 while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
2053 isl_map *res_i;
2054
2055 negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
2056 res_i = read_conjunct(s, v, isl_map_copy(map), rational);
2057 if (negate)
2058 res = isl_map_subtract(res, res_i);
2059 else
2060 res = isl_map_intersect(res, res_i);
2061 }
2062
2063 isl_map_free(map);
2064 return res;
2065 }
2066
read_disjuncts(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)2067 static __isl_give isl_map *read_disjuncts(__isl_keep isl_stream *s,
2068 struct vars *v, __isl_take isl_map *map, int rational)
2069 {
2070 isl_map *res;
2071
2072 if (isl_stream_next_token_is(s, '}'))
2073 return map;
2074
2075 res = read_conjuncts(s, v, isl_map_copy(map), rational);
2076 while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
2077 isl_map *res_i;
2078
2079 res_i = read_conjuncts(s, v, isl_map_copy(map), rational);
2080 res = isl_map_union(res, res_i);
2081 }
2082
2083 isl_map_free(map);
2084 return res;
2085 }
2086
2087 /* Read a first order formula from "s", add the corresponding
2088 * constraints to "map" and return the result.
2089 *
2090 * In particular, read a formula of the form
2091 *
2092 * a
2093 *
2094 * or
2095 *
2096 * a implies b
2097 *
2098 * where a and b are disjunctions.
2099 *
2100 * In the first case, map is replaced by
2101 *
2102 * map \cap { [..] : a }
2103 *
2104 * In the second case, it is replaced by
2105 *
2106 * (map \setminus { [..] : a}) \cup (map \cap { [..] : b })
2107 */
read_formula(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_map * map,int rational)2108 static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
2109 struct vars *v, __isl_take isl_map *map, int rational)
2110 {
2111 isl_map *res;
2112
2113 res = read_disjuncts(s, v, isl_map_copy(map), rational);
2114
2115 if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) {
2116 isl_map *res2;
2117
2118 res = isl_map_subtract(isl_map_copy(map), res);
2119 res2 = read_disjuncts(s, v, map, rational);
2120 res = isl_map_union(res, res2);
2121 } else
2122 isl_map_free(map);
2123
2124 return res;
2125 }
2126
polylib_pos_to_isl_pos(__isl_keep isl_basic_map * bmap,int pos)2127 static isl_size polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
2128 {
2129 isl_size n_out, n_in, n_param, n_div;
2130
2131 n_param = isl_basic_map_dim(bmap, isl_dim_param);
2132 n_in = isl_basic_map_dim(bmap, isl_dim_in);
2133 n_out = isl_basic_map_dim(bmap, isl_dim_out);
2134 n_div = isl_basic_map_dim(bmap, isl_dim_div);
2135 if (n_param < 0 || n_in < 0 || n_out < 0 || n_div < 0)
2136 return isl_size_error;
2137
2138 if (pos < n_out)
2139 return 1 + n_param + n_in + pos;
2140 pos -= n_out;
2141
2142 if (pos < n_in)
2143 return 1 + n_param + pos;
2144 pos -= n_in;
2145
2146 if (pos < n_div)
2147 return 1 + n_param + n_in + n_out + pos;
2148 pos -= n_div;
2149
2150 if (pos < n_param)
2151 return 1 + pos;
2152
2153 return 0;
2154 }
2155
basic_map_read_polylib_constraint(__isl_keep isl_stream * s,__isl_take isl_basic_map * bmap)2156 static __isl_give isl_basic_map *basic_map_read_polylib_constraint(
2157 __isl_keep isl_stream *s, __isl_take isl_basic_map *bmap)
2158 {
2159 int j;
2160 struct isl_token *tok;
2161 int type;
2162 int k;
2163 isl_int *c;
2164 isl_size total;
2165
2166 if (!bmap)
2167 return NULL;
2168
2169 tok = isl_stream_next_token(s);
2170 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2171 isl_stream_error(s, tok, "expecting coefficient");
2172 if (tok)
2173 isl_stream_push_token(s, tok);
2174 goto error;
2175 }
2176 if (!tok->on_new_line) {
2177 isl_stream_error(s, tok, "coefficient should appear on new line");
2178 isl_stream_push_token(s, tok);
2179 goto error;
2180 }
2181
2182 type = isl_int_get_si(tok->u.v);
2183 isl_token_free(tok);
2184
2185 isl_assert(s->ctx, type == 0 || type == 1, goto error);
2186 if (type == 0) {
2187 k = isl_basic_map_alloc_equality(bmap);
2188 c = bmap->eq[k];
2189 } else {
2190 k = isl_basic_map_alloc_inequality(bmap);
2191 c = bmap->ineq[k];
2192 }
2193 if (k < 0)
2194 goto error;
2195
2196 total = isl_basic_map_dim(bmap, isl_dim_all);
2197 if (total < 0)
2198 return isl_basic_map_free(bmap);
2199 for (j = 0; j < 1 + total; ++j) {
2200 isl_size pos;
2201 tok = isl_stream_next_token(s);
2202 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2203 isl_stream_error(s, tok, "expecting coefficient");
2204 if (tok)
2205 isl_stream_push_token(s, tok);
2206 goto error;
2207 }
2208 if (tok->on_new_line) {
2209 isl_stream_error(s, tok,
2210 "coefficient should not appear on new line");
2211 isl_stream_push_token(s, tok);
2212 goto error;
2213 }
2214 pos = polylib_pos_to_isl_pos(bmap, j);
2215 if (pos >= 0)
2216 isl_int_set(c[pos], tok->u.v);
2217 isl_token_free(tok);
2218 if (pos < 0)
2219 return isl_basic_map_free(bmap);
2220 }
2221
2222 return bmap;
2223 error:
2224 isl_basic_map_free(bmap);
2225 return NULL;
2226 }
2227
basic_map_read_polylib(__isl_keep isl_stream * s)2228 static __isl_give isl_basic_map *basic_map_read_polylib(
2229 __isl_keep isl_stream *s)
2230 {
2231 int i;
2232 struct isl_token *tok;
2233 struct isl_token *tok2;
2234 int n_row, n_col;
2235 int on_new_line;
2236 unsigned in = 0, out, local = 0;
2237 struct isl_basic_map *bmap = NULL;
2238 int nparam = 0;
2239
2240 tok = isl_stream_next_token(s);
2241 if (!tok) {
2242 isl_stream_error(s, NULL, "unexpected EOF");
2243 return NULL;
2244 }
2245 tok2 = isl_stream_next_token(s);
2246 if (!tok2) {
2247 isl_token_free(tok);
2248 isl_stream_error(s, NULL, "unexpected EOF");
2249 return NULL;
2250 }
2251 if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) {
2252 isl_stream_push_token(s, tok2);
2253 isl_stream_push_token(s, tok);
2254 isl_stream_error(s, NULL,
2255 "expecting constraint matrix dimensions");
2256 return NULL;
2257 }
2258 n_row = isl_int_get_si(tok->u.v);
2259 n_col = isl_int_get_si(tok2->u.v);
2260 on_new_line = tok2->on_new_line;
2261 isl_token_free(tok2);
2262 isl_token_free(tok);
2263 isl_assert(s->ctx, !on_new_line, return NULL);
2264 isl_assert(s->ctx, n_row >= 0, return NULL);
2265 isl_assert(s->ctx, n_col >= 2 + nparam, return NULL);
2266 tok = isl_stream_next_token_on_same_line(s);
2267 if (tok) {
2268 if (tok->type != ISL_TOKEN_VALUE) {
2269 isl_stream_error(s, tok,
2270 "expecting number of output dimensions");
2271 isl_stream_push_token(s, tok);
2272 goto error;
2273 }
2274 out = isl_int_get_si(tok->u.v);
2275 isl_token_free(tok);
2276
2277 tok = isl_stream_next_token_on_same_line(s);
2278 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2279 isl_stream_error(s, tok,
2280 "expecting number of input dimensions");
2281 if (tok)
2282 isl_stream_push_token(s, tok);
2283 goto error;
2284 }
2285 in = isl_int_get_si(tok->u.v);
2286 isl_token_free(tok);
2287
2288 tok = isl_stream_next_token_on_same_line(s);
2289 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2290 isl_stream_error(s, tok,
2291 "expecting number of existentials");
2292 if (tok)
2293 isl_stream_push_token(s, tok);
2294 goto error;
2295 }
2296 local = isl_int_get_si(tok->u.v);
2297 isl_token_free(tok);
2298
2299 tok = isl_stream_next_token_on_same_line(s);
2300 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2301 isl_stream_error(s, tok,
2302 "expecting number of parameters");
2303 if (tok)
2304 isl_stream_push_token(s, tok);
2305 goto error;
2306 }
2307 nparam = isl_int_get_si(tok->u.v);
2308 isl_token_free(tok);
2309 if (n_col != 1 + out + in + local + nparam + 1) {
2310 isl_stream_error(s, NULL,
2311 "dimensions don't match");
2312 goto error;
2313 }
2314 } else
2315 out = n_col - 2 - nparam;
2316 bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row);
2317 if (!bmap)
2318 return NULL;
2319
2320 for (i = 0; i < local; ++i) {
2321 int k = isl_basic_map_alloc_div(bmap);
2322 if (k < 0)
2323 goto error;
2324 isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local);
2325 }
2326
2327 for (i = 0; i < n_row; ++i)
2328 bmap = basic_map_read_polylib_constraint(s, bmap);
2329
2330 tok = isl_stream_next_token_on_same_line(s);
2331 if (tok) {
2332 isl_stream_error(s, tok, "unexpected extra token on line");
2333 isl_stream_push_token(s, tok);
2334 goto error;
2335 }
2336
2337 bmap = isl_basic_map_simplify(bmap);
2338 bmap = isl_basic_map_finalize(bmap);
2339 return bmap;
2340 error:
2341 isl_basic_map_free(bmap);
2342 return NULL;
2343 }
2344
map_read_polylib(__isl_keep isl_stream * s)2345 static __isl_give isl_map *map_read_polylib(__isl_keep isl_stream *s)
2346 {
2347 struct isl_token *tok;
2348 struct isl_token *tok2;
2349 int i, n;
2350 struct isl_map *map;
2351
2352 tok = isl_stream_next_token(s);
2353 if (!tok) {
2354 isl_stream_error(s, NULL, "unexpected EOF");
2355 return NULL;
2356 }
2357 tok2 = isl_stream_next_token_on_same_line(s);
2358 if (tok2 && tok2->type == ISL_TOKEN_VALUE) {
2359 isl_stream_push_token(s, tok2);
2360 isl_stream_push_token(s, tok);
2361 return isl_map_from_basic_map(basic_map_read_polylib(s));
2362 }
2363 if (tok2) {
2364 isl_stream_error(s, tok2, "unexpected token");
2365 isl_stream_push_token(s, tok2);
2366 isl_stream_push_token(s, tok);
2367 return NULL;
2368 }
2369 n = isl_int_get_si(tok->u.v);
2370 isl_token_free(tok);
2371
2372 isl_assert(s->ctx, n >= 1, return NULL);
2373
2374 map = isl_map_from_basic_map(basic_map_read_polylib(s));
2375
2376 for (i = 1; map && i < n; ++i)
2377 map = isl_map_union(map,
2378 isl_map_from_basic_map(basic_map_read_polylib(s)));
2379
2380 return map;
2381 }
2382
optional_power(__isl_keep isl_stream * s)2383 static int optional_power(__isl_keep isl_stream *s)
2384 {
2385 int pow;
2386 struct isl_token *tok;
2387
2388 tok = isl_stream_next_token(s);
2389 if (!tok)
2390 return 1;
2391 if (tok->type != '^') {
2392 isl_stream_push_token(s, tok);
2393 return 1;
2394 }
2395 isl_token_free(tok);
2396 tok = isl_stream_next_token(s);
2397 if (!tok || tok->type != ISL_TOKEN_VALUE) {
2398 isl_stream_error(s, tok, "expecting exponent");
2399 if (tok)
2400 isl_stream_push_token(s, tok);
2401 return 1;
2402 }
2403 pow = isl_int_get_si(tok->u.v);
2404 isl_token_free(tok);
2405 return pow;
2406 }
2407
2408 static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
2409 __isl_keep isl_map *map, struct vars *v);
2410
read_factor(__isl_keep isl_stream * s,__isl_keep isl_map * map,struct vars * v)2411 static __isl_give isl_pw_qpolynomial *read_factor(__isl_keep isl_stream *s,
2412 __isl_keep isl_map *map, struct vars *v)
2413 {
2414 isl_pw_qpolynomial *pwqp;
2415 struct isl_token *tok;
2416
2417 tok = next_token(s);
2418 if (!tok) {
2419 isl_stream_error(s, NULL, "unexpected EOF");
2420 return NULL;
2421 }
2422 if (tok->type == '(') {
2423 int pow;
2424
2425 isl_token_free(tok);
2426 pwqp = read_term(s, map, v);
2427 if (!pwqp)
2428 return NULL;
2429 if (isl_stream_eat(s, ')'))
2430 goto error;
2431 pow = optional_power(s);
2432 pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
2433 } else if (tok->type == ISL_TOKEN_VALUE) {
2434 struct isl_token *tok2;
2435 isl_qpolynomial *qp;
2436
2437 tok2 = isl_stream_next_token(s);
2438 if (tok2 && tok2->type == '/') {
2439 isl_token_free(tok2);
2440 tok2 = next_token(s);
2441 if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
2442 isl_stream_error(s, tok2, "expected denominator");
2443 isl_token_free(tok);
2444 isl_token_free(tok2);
2445 return NULL;
2446 }
2447 qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map),
2448 tok->u.v, tok2->u.v);
2449 isl_token_free(tok2);
2450 } else {
2451 isl_stream_push_token(s, tok2);
2452 qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map),
2453 tok->u.v);
2454 }
2455 isl_token_free(tok);
2456 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2457 } else if (tok->type == ISL_TOKEN_INFTY) {
2458 isl_qpolynomial *qp;
2459 isl_token_free(tok);
2460 qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map));
2461 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2462 } else if (tok->type == ISL_TOKEN_NAN) {
2463 isl_qpolynomial *qp;
2464 isl_token_free(tok);
2465 qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map));
2466 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2467 } else if (tok->type == ISL_TOKEN_IDENT) {
2468 int n = v->n;
2469 int pos = vars_pos(v, tok->u.s, -1);
2470 int pow;
2471 isl_qpolynomial *qp;
2472 if (pos < 0) {
2473 isl_token_free(tok);
2474 return NULL;
2475 }
2476 if (pos >= n) {
2477 vars_drop(v, v->n - n);
2478 isl_stream_error(s, tok, "unknown identifier");
2479 isl_token_free(tok);
2480 return NULL;
2481 }
2482 isl_token_free(tok);
2483 pow = optional_power(s);
2484 qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow);
2485 pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
2486 } else if (is_start_of_div(tok)) {
2487 isl_pw_aff *pwaff;
2488 int pow;
2489
2490 isl_stream_push_token(s, tok);
2491 pwaff = accept_div(s, isl_map_get_space(map), v);
2492 pow = optional_power(s);
2493 pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff);
2494 pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
2495 } else if (tok->type == '-') {
2496 isl_token_free(tok);
2497 pwqp = read_factor(s, map, v);
2498 pwqp = isl_pw_qpolynomial_neg(pwqp);
2499 } else {
2500 isl_stream_error(s, tok, "unexpected isl_token");
2501 isl_stream_push_token(s, tok);
2502 return NULL;
2503 }
2504
2505 if (isl_stream_eat_if_available(s, '*') ||
2506 isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
2507 isl_pw_qpolynomial *pwqp2;
2508
2509 pwqp2 = read_factor(s, map, v);
2510 pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2);
2511 }
2512
2513 return pwqp;
2514 error:
2515 isl_pw_qpolynomial_free(pwqp);
2516 return NULL;
2517 }
2518
read_term(__isl_keep isl_stream * s,__isl_keep isl_map * map,struct vars * v)2519 static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
2520 __isl_keep isl_map *map, struct vars *v)
2521 {
2522 struct isl_token *tok;
2523 isl_pw_qpolynomial *pwqp;
2524
2525 pwqp = read_factor(s, map, v);
2526
2527 for (;;) {
2528 tok = next_token(s);
2529 if (!tok)
2530 return pwqp;
2531
2532 if (tok->type == '+') {
2533 isl_pw_qpolynomial *pwqp2;
2534
2535 isl_token_free(tok);
2536 pwqp2 = read_factor(s, map, v);
2537 pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
2538 } else if (tok->type == '-') {
2539 isl_pw_qpolynomial *pwqp2;
2540
2541 isl_token_free(tok);
2542 pwqp2 = read_factor(s, map, v);
2543 pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2);
2544 } else if (tok->type == ISL_TOKEN_VALUE &&
2545 isl_int_is_neg(tok->u.v)) {
2546 isl_pw_qpolynomial *pwqp2;
2547
2548 isl_stream_push_token(s, tok);
2549 pwqp2 = read_factor(s, map, v);
2550 pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
2551 } else {
2552 isl_stream_push_token(s, tok);
2553 break;
2554 }
2555 }
2556
2557 return pwqp;
2558 }
2559
read_optional_formula(__isl_keep isl_stream * s,__isl_take isl_map * map,struct vars * v,int rational)2560 static __isl_give isl_map *read_optional_formula(__isl_keep isl_stream *s,
2561 __isl_take isl_map *map, struct vars *v, int rational)
2562 {
2563 struct isl_token *tok;
2564
2565 tok = isl_stream_next_token(s);
2566 if (!tok) {
2567 isl_stream_error(s, NULL, "unexpected EOF");
2568 goto error;
2569 }
2570 if (tok->type == ':' ||
2571 (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
2572 isl_token_free(tok);
2573 map = read_formula(s, v, map, rational);
2574 } else
2575 isl_stream_push_token(s, tok);
2576
2577 return map;
2578 error:
2579 isl_map_free(map);
2580 return NULL;
2581 }
2582
obj_read_poly(__isl_keep isl_stream * s,__isl_take isl_map * map,struct vars * v,int n)2583 static struct isl_obj obj_read_poly(__isl_keep isl_stream *s,
2584 __isl_take isl_map *map, struct vars *v, int n)
2585 {
2586 struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL };
2587 isl_pw_qpolynomial *pwqp;
2588 struct isl_set *set;
2589
2590 pwqp = read_term(s, map, v);
2591 map = read_optional_formula(s, map, v, 0);
2592 set = isl_map_range(map);
2593
2594 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set);
2595
2596 vars_drop(v, v->n - n);
2597
2598 obj.v = pwqp;
2599 return obj;
2600 }
2601
obj_read_poly_or_fold(__isl_keep isl_stream * s,__isl_take isl_set * set,struct vars * v,int n)2602 static struct isl_obj obj_read_poly_or_fold(__isl_keep isl_stream *s,
2603 __isl_take isl_set *set, struct vars *v, int n)
2604 {
2605 struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL };
2606 isl_pw_qpolynomial *pwqp;
2607 isl_pw_qpolynomial_fold *pwf = NULL;
2608
2609 if (!isl_stream_eat_if_available(s, ISL_TOKEN_MAX))
2610 return obj_read_poly(s, set, v, n);
2611
2612 if (isl_stream_eat(s, '('))
2613 goto error;
2614
2615 pwqp = read_term(s, set, v);
2616 pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, pwqp);
2617
2618 while (isl_stream_eat_if_available(s, ',')) {
2619 isl_pw_qpolynomial_fold *pwf_i;
2620 pwqp = read_term(s, set, v);
2621 pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max,
2622 pwqp);
2623 pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i);
2624 }
2625
2626 if (isl_stream_eat(s, ')'))
2627 goto error;
2628
2629 set = read_optional_formula(s, set, v, 0);
2630 pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set);
2631
2632 vars_drop(v, v->n - n);
2633
2634 obj.v = pwf;
2635 return obj;
2636 error:
2637 isl_set_free(set);
2638 isl_pw_qpolynomial_fold_free(pwf);
2639 obj.type = isl_obj_none;
2640 return obj;
2641 }
2642
is_rational(__isl_keep isl_stream * s)2643 static int is_rational(__isl_keep isl_stream *s)
2644 {
2645 struct isl_token *tok;
2646
2647 tok = isl_stream_next_token(s);
2648 if (!tok)
2649 return 0;
2650 if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
2651 isl_token_free(tok);
2652 isl_stream_eat(s, ':');
2653 return 1;
2654 }
2655
2656 isl_stream_push_token(s, tok);
2657
2658 return 0;
2659 }
2660
obj_read_body(__isl_keep isl_stream * s,__isl_take isl_map * map,struct vars * v)2661 static struct isl_obj obj_read_body(__isl_keep isl_stream *s,
2662 __isl_take isl_map *map, struct vars *v)
2663 {
2664 struct isl_token *tok;
2665 struct isl_obj obj = { isl_obj_set, NULL };
2666 int n = v->n;
2667 int rational;
2668
2669 rational = is_rational(s);
2670 if (rational)
2671 map = isl_map_set_rational(map);
2672
2673 if (isl_stream_next_token_is(s, ':')) {
2674 obj.type = isl_obj_set;
2675 obj.v = read_optional_formula(s, map, v, rational);
2676 return obj;
2677 }
2678
2679 if (!next_is_tuple(s))
2680 return obj_read_poly_or_fold(s, map, v, n);
2681
2682 map = read_map_tuple(s, map, isl_dim_in, v, rational, 0);
2683 if (!map)
2684 goto error;
2685 tok = isl_stream_next_token(s);
2686 if (!tok)
2687 goto error;
2688 if (tok->type == ISL_TOKEN_TO) {
2689 obj.type = isl_obj_map;
2690 isl_token_free(tok);
2691 if (!next_is_tuple(s)) {
2692 isl_set *set = isl_map_domain(map);
2693 return obj_read_poly_or_fold(s, set, v, n);
2694 }
2695 map = read_map_tuple(s, map, isl_dim_out, v, rational, 0);
2696 if (!map)
2697 goto error;
2698 } else {
2699 map = isl_map_domain(map);
2700 isl_stream_push_token(s, tok);
2701 }
2702
2703 map = read_optional_formula(s, map, v, rational);
2704
2705 vars_drop(v, v->n - n);
2706
2707 obj.v = map;
2708 return obj;
2709 error:
2710 isl_map_free(map);
2711 obj.type = isl_obj_none;
2712 return obj;
2713 }
2714
to_union(isl_ctx * ctx,struct isl_obj obj)2715 static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj)
2716 {
2717 if (obj.type == isl_obj_map) {
2718 obj.v = isl_union_map_from_map(obj.v);
2719 obj.type = isl_obj_union_map;
2720 } else if (obj.type == isl_obj_set) {
2721 obj.v = isl_union_set_from_set(obj.v);
2722 obj.type = isl_obj_union_set;
2723 } else if (obj.type == isl_obj_pw_qpolynomial) {
2724 obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
2725 obj.type = isl_obj_union_pw_qpolynomial;
2726 } else if (obj.type == isl_obj_pw_qpolynomial_fold) {
2727 obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
2728 obj.type = isl_obj_union_pw_qpolynomial_fold;
2729 } else
2730 isl_assert(ctx, 0, goto error);
2731 return obj;
2732 error:
2733 obj.type->free(obj.v);
2734 obj.type = isl_obj_none;
2735 return obj;
2736 }
2737
obj_add(__isl_keep isl_stream * s,struct isl_obj obj1,struct isl_obj obj2)2738 static struct isl_obj obj_add(__isl_keep isl_stream *s,
2739 struct isl_obj obj1, struct isl_obj obj2)
2740 {
2741 if (obj2.type == isl_obj_none || !obj2.v)
2742 goto error;
2743 if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set)
2744 obj1 = to_union(s->ctx, obj1);
2745 if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set)
2746 obj2 = to_union(s->ctx, obj2);
2747 if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map)
2748 obj1 = to_union(s->ctx, obj1);
2749 if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map)
2750 obj2 = to_union(s->ctx, obj2);
2751 if (obj1.type == isl_obj_pw_qpolynomial &&
2752 obj2.type == isl_obj_union_pw_qpolynomial)
2753 obj1 = to_union(s->ctx, obj1);
2754 if (obj1.type == isl_obj_union_pw_qpolynomial &&
2755 obj2.type == isl_obj_pw_qpolynomial)
2756 obj2 = to_union(s->ctx, obj2);
2757 if (obj1.type == isl_obj_pw_qpolynomial_fold &&
2758 obj2.type == isl_obj_union_pw_qpolynomial_fold)
2759 obj1 = to_union(s->ctx, obj1);
2760 if (obj1.type == isl_obj_union_pw_qpolynomial_fold &&
2761 obj2.type == isl_obj_pw_qpolynomial_fold)
2762 obj2 = to_union(s->ctx, obj2);
2763 if (obj1.type != obj2.type) {
2764 isl_stream_error(s, NULL,
2765 "attempt to combine incompatible objects");
2766 goto error;
2767 }
2768 if (!obj1.type->add)
2769 isl_die(s->ctx, isl_error_internal,
2770 "combination not supported on object type", goto error);
2771 if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) {
2772 obj1 = to_union(s->ctx, obj1);
2773 obj2 = to_union(s->ctx, obj2);
2774 }
2775 if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) {
2776 obj1 = to_union(s->ctx, obj1);
2777 obj2 = to_union(s->ctx, obj2);
2778 }
2779 if (obj1.type == isl_obj_pw_qpolynomial &&
2780 !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) {
2781 obj1 = to_union(s->ctx, obj1);
2782 obj2 = to_union(s->ctx, obj2);
2783 }
2784 if (obj1.type == isl_obj_pw_qpolynomial_fold &&
2785 !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) {
2786 obj1 = to_union(s->ctx, obj1);
2787 obj2 = to_union(s->ctx, obj2);
2788 }
2789 obj1.v = obj1.type->add(obj1.v, obj2.v);
2790 return obj1;
2791 error:
2792 obj1.type->free(obj1.v);
2793 obj2.type->free(obj2.v);
2794 obj1.type = isl_obj_none;
2795 obj1.v = NULL;
2796 return obj1;
2797 }
2798
2799 /* Are the first two tokens on "s", "domain" (either as a string
2800 * or as an identifier) followed by ":"?
2801 */
next_is_domain_colon(__isl_keep isl_stream * s)2802 static int next_is_domain_colon(__isl_keep isl_stream *s)
2803 {
2804 struct isl_token *tok;
2805 char *name;
2806 int res;
2807
2808 tok = isl_stream_next_token(s);
2809 if (!tok)
2810 return 0;
2811 if (tok->type != ISL_TOKEN_IDENT && tok->type != ISL_TOKEN_STRING) {
2812 isl_stream_push_token(s, tok);
2813 return 0;
2814 }
2815
2816 name = isl_token_get_str(s->ctx, tok);
2817 res = !strcmp(name, "domain") && isl_stream_next_token_is(s, ':');
2818 free(name);
2819
2820 isl_stream_push_token(s, tok);
2821
2822 return res;
2823 }
2824
2825 /* Do the first tokens on "s" look like a schedule?
2826 *
2827 * The root of a schedule is always a domain node, so the first thing
2828 * we expect in the stream is a domain key, i.e., "domain" followed
2829 * by ":". If the schedule was printed in YAML flow style, then
2830 * we additionally expect a "{" to open the outer mapping.
2831 */
next_is_schedule(__isl_keep isl_stream * s)2832 static int next_is_schedule(__isl_keep isl_stream *s)
2833 {
2834 struct isl_token *tok;
2835 int is_schedule;
2836
2837 tok = isl_stream_next_token(s);
2838 if (!tok)
2839 return 0;
2840 if (tok->type != '{') {
2841 isl_stream_push_token(s, tok);
2842 return next_is_domain_colon(s);
2843 }
2844
2845 is_schedule = next_is_domain_colon(s);
2846 isl_stream_push_token(s, tok);
2847
2848 return is_schedule;
2849 }
2850
2851 /* Read an isl_schedule from "s" and store it in an isl_obj.
2852 */
schedule_read(__isl_keep isl_stream * s)2853 static struct isl_obj schedule_read(__isl_keep isl_stream *s)
2854 {
2855 struct isl_obj obj;
2856
2857 obj.type = isl_obj_schedule;
2858 obj.v = isl_stream_read_schedule(s);
2859
2860 return obj;
2861 }
2862
2863 /* Read a disjunction of object bodies from "s".
2864 * That is, read the inside of the braces, but not the braces themselves.
2865 * "v" contains a description of the identifiers parsed so far.
2866 * "map" contains information about the parameters.
2867 */
obj_read_disjuncts(__isl_keep isl_stream * s,struct vars * v,__isl_keep isl_map * map)2868 static struct isl_obj obj_read_disjuncts(__isl_keep isl_stream *s,
2869 struct vars *v, __isl_keep isl_map *map)
2870 {
2871 struct isl_obj obj = { isl_obj_set, NULL };
2872
2873 if (isl_stream_next_token_is(s, '}')) {
2874 obj.type = isl_obj_union_set;
2875 obj.v = isl_union_set_empty(isl_map_get_space(map));
2876 return obj;
2877 }
2878
2879 for (;;) {
2880 struct isl_obj o;
2881 o = obj_read_body(s, isl_map_copy(map), v);
2882 if (!obj.v)
2883 obj = o;
2884 else
2885 obj = obj_add(s, obj, o);
2886 if (obj.type == isl_obj_none || !obj.v)
2887 return obj;
2888 if (!isl_stream_eat_if_available(s, ';'))
2889 break;
2890 if (isl_stream_next_token_is(s, '}'))
2891 break;
2892 }
2893
2894 return obj;
2895 }
2896
obj_read(__isl_keep isl_stream * s)2897 static struct isl_obj obj_read(__isl_keep isl_stream *s)
2898 {
2899 isl_map *map = NULL;
2900 struct isl_token *tok;
2901 struct vars *v = NULL;
2902 struct isl_obj obj = { isl_obj_set, NULL };
2903
2904 if (next_is_schedule(s))
2905 return schedule_read(s);
2906
2907 tok = next_token(s);
2908 if (!tok) {
2909 isl_stream_error(s, NULL, "unexpected EOF");
2910 goto error;
2911 }
2912 if (tok->type == ISL_TOKEN_VALUE) {
2913 struct isl_token *tok2;
2914 struct isl_map *map;
2915
2916 tok2 = isl_stream_next_token(s);
2917 if (!tok2 || tok2->type != ISL_TOKEN_VALUE ||
2918 isl_int_is_neg(tok2->u.v)) {
2919 if (tok2)
2920 isl_stream_push_token(s, tok2);
2921 obj.type = isl_obj_val;
2922 obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v);
2923 isl_token_free(tok);
2924 return obj;
2925 }
2926 isl_stream_push_token(s, tok2);
2927 isl_stream_push_token(s, tok);
2928 map = map_read_polylib(s);
2929 if (!map)
2930 goto error;
2931 if (isl_map_may_be_set(map))
2932 obj.v = isl_map_range(map);
2933 else {
2934 obj.type = isl_obj_map;
2935 obj.v = map;
2936 }
2937 return obj;
2938 }
2939 v = vars_new(s->ctx);
2940 if (!v) {
2941 isl_stream_push_token(s, tok);
2942 goto error;
2943 }
2944 map = isl_map_universe(isl_space_params_alloc(s->ctx, 0));
2945 if (tok->type == '[') {
2946 isl_stream_push_token(s, tok);
2947 map = read_map_tuple(s, map, isl_dim_param, v, 0, 0);
2948 if (!map)
2949 goto error;
2950 tok = isl_stream_next_token(s);
2951 if (!tok || tok->type != ISL_TOKEN_TO) {
2952 isl_stream_error(s, tok, "expecting '->'");
2953 if (tok)
2954 isl_stream_push_token(s, tok);
2955 goto error;
2956 }
2957 isl_token_free(tok);
2958 tok = isl_stream_next_token(s);
2959 }
2960 if (!tok || tok->type != '{') {
2961 isl_stream_error(s, tok, "expecting '{'");
2962 if (tok)
2963 isl_stream_push_token(s, tok);
2964 goto error;
2965 }
2966 isl_token_free(tok);
2967
2968 tok = isl_stream_next_token(s);
2969 if (!tok)
2970 ;
2971 else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) {
2972 isl_token_free(tok);
2973 if (isl_stream_eat(s, '='))
2974 goto error;
2975 map = read_map_tuple(s, map, isl_dim_param, v, 0, 1);
2976 if (!map)
2977 goto error;
2978 } else
2979 isl_stream_push_token(s, tok);
2980
2981 obj = obj_read_disjuncts(s, v, map);
2982 if (obj.type == isl_obj_none || !obj.v)
2983 goto error;
2984
2985 tok = isl_stream_next_token(s);
2986 if (tok && tok->type == '}') {
2987 isl_token_free(tok);
2988 } else {
2989 isl_stream_error(s, tok, "unexpected isl_token");
2990 if (tok)
2991 isl_token_free(tok);
2992 goto error;
2993 }
2994
2995 vars_free(v);
2996 isl_map_free(map);
2997
2998 return obj;
2999 error:
3000 isl_map_free(map);
3001 obj.type->free(obj.v);
3002 if (v)
3003 vars_free(v);
3004 obj.v = NULL;
3005 return obj;
3006 }
3007
isl_stream_read_obj(__isl_keep isl_stream * s)3008 struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s)
3009 {
3010 return obj_read(s);
3011 }
3012
isl_stream_read_map(__isl_keep isl_stream * s)3013 __isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s)
3014 {
3015 struct isl_obj obj;
3016
3017 obj = obj_read(s);
3018 if (obj.v)
3019 isl_assert(s->ctx, obj.type == isl_obj_map ||
3020 obj.type == isl_obj_set, goto error);
3021
3022 if (obj.type == isl_obj_set)
3023 obj.v = isl_map_from_range(obj.v);
3024
3025 return obj.v;
3026 error:
3027 obj.type->free(obj.v);
3028 return NULL;
3029 }
3030
isl_stream_read_set(__isl_keep isl_stream * s)3031 __isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s)
3032 {
3033 struct isl_obj obj;
3034
3035 obj = obj_read(s);
3036 if (obj.v) {
3037 if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) {
3038 obj.v = isl_map_range(obj.v);
3039 obj.type = isl_obj_set;
3040 }
3041 isl_assert(s->ctx, obj.type == isl_obj_set, goto error);
3042 }
3043
3044 return obj.v;
3045 error:
3046 obj.type->free(obj.v);
3047 return NULL;
3048 }
3049
isl_stream_read_union_map(__isl_keep isl_stream * s)3050 __isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s)
3051 {
3052 struct isl_obj obj;
3053
3054 obj = obj_read(s);
3055 if (obj.type == isl_obj_map) {
3056 obj.type = isl_obj_union_map;
3057 obj.v = isl_union_map_from_map(obj.v);
3058 }
3059 if (obj.type == isl_obj_set) {
3060 obj.type = isl_obj_union_set;
3061 obj.v = isl_union_set_from_set(obj.v);
3062 }
3063 if (obj.v && obj.type == isl_obj_union_set &&
3064 isl_union_set_is_empty(obj.v))
3065 obj.type = isl_obj_union_map;
3066 if (obj.v && obj.type != isl_obj_union_map)
3067 isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
3068
3069 return obj.v;
3070 error:
3071 obj.type->free(obj.v);
3072 return NULL;
3073 }
3074
3075 /* Extract an isl_union_set from "obj".
3076 * This only works if the object was detected as either a set
3077 * (in which case it is converted to a union set) or a union set.
3078 */
extract_union_set(isl_ctx * ctx,struct isl_obj obj)3079 static __isl_give isl_union_set *extract_union_set(isl_ctx *ctx,
3080 struct isl_obj obj)
3081 {
3082 if (obj.type == isl_obj_set) {
3083 obj.type = isl_obj_union_set;
3084 obj.v = isl_union_set_from_set(obj.v);
3085 }
3086 if (obj.v)
3087 isl_assert(ctx, obj.type == isl_obj_union_set, goto error);
3088
3089 return obj.v;
3090 error:
3091 obj.type->free(obj.v);
3092 return NULL;
3093 }
3094
3095 /* Read an isl_union_set from "s".
3096 * First read a generic object and then try and extract
3097 * an isl_union_set from that.
3098 */
isl_stream_read_union_set(__isl_keep isl_stream * s)3099 __isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s)
3100 {
3101 struct isl_obj obj;
3102
3103 obj = obj_read(s);
3104 return extract_union_set(s->ctx, obj);
3105 }
3106
basic_map_read(__isl_keep isl_stream * s)3107 static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s)
3108 {
3109 struct isl_obj obj;
3110 struct isl_map *map;
3111 struct isl_basic_map *bmap;
3112
3113 obj = obj_read(s);
3114 if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set))
3115 isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map",
3116 goto error);
3117 map = obj.v;
3118 if (!map)
3119 return NULL;
3120
3121 if (map->n > 1)
3122 isl_die(s->ctx, isl_error_invalid,
3123 "set or map description involves "
3124 "more than one disjunct", goto error);
3125
3126 if (map->n == 0)
3127 bmap = isl_basic_map_empty(isl_map_get_space(map));
3128 else
3129 bmap = isl_basic_map_copy(map->p[0]);
3130
3131 isl_map_free(map);
3132
3133 return bmap;
3134 error:
3135 obj.type->free(obj.v);
3136 return NULL;
3137 }
3138
basic_set_read(__isl_keep isl_stream * s)3139 static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s)
3140 {
3141 isl_basic_map *bmap;
3142 bmap = basic_map_read(s);
3143 if (!bmap)
3144 return NULL;
3145 if (!isl_basic_map_may_be_set(bmap))
3146 isl_die(s->ctx, isl_error_invalid,
3147 "input is not a set", goto error);
3148 return isl_basic_map_range(bmap);
3149 error:
3150 isl_basic_map_free(bmap);
3151 return NULL;
3152 }
3153
isl_basic_map_read_from_file(isl_ctx * ctx,FILE * input)3154 __isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
3155 FILE *input)
3156 {
3157 struct isl_basic_map *bmap;
3158 isl_stream *s = isl_stream_new_file(ctx, input);
3159 if (!s)
3160 return NULL;
3161 bmap = basic_map_read(s);
3162 isl_stream_free(s);
3163 return bmap;
3164 }
3165
isl_basic_set_read_from_file(isl_ctx * ctx,FILE * input)3166 __isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
3167 FILE *input)
3168 {
3169 isl_basic_set *bset;
3170 isl_stream *s = isl_stream_new_file(ctx, input);
3171 if (!s)
3172 return NULL;
3173 bset = basic_set_read(s);
3174 isl_stream_free(s);
3175 return bset;
3176 }
3177
isl_basic_map_read_from_str(isl_ctx * ctx,const char * str)3178 __isl_give isl_basic_map *isl_basic_map_read_from_str(isl_ctx *ctx,
3179 const char *str)
3180 {
3181 struct isl_basic_map *bmap;
3182 isl_stream *s = isl_stream_new_str(ctx, str);
3183 if (!s)
3184 return NULL;
3185 bmap = basic_map_read(s);
3186 isl_stream_free(s);
3187 return bmap;
3188 }
3189
isl_basic_set_read_from_str(isl_ctx * ctx,const char * str)3190 __isl_give isl_basic_set *isl_basic_set_read_from_str(isl_ctx *ctx,
3191 const char *str)
3192 {
3193 isl_basic_set *bset;
3194 isl_stream *s = isl_stream_new_str(ctx, str);
3195 if (!s)
3196 return NULL;
3197 bset = basic_set_read(s);
3198 isl_stream_free(s);
3199 return bset;
3200 }
3201
isl_map_read_from_file(struct isl_ctx * ctx,FILE * input)3202 __isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx,
3203 FILE *input)
3204 {
3205 struct isl_map *map;
3206 isl_stream *s = isl_stream_new_file(ctx, input);
3207 if (!s)
3208 return NULL;
3209 map = isl_stream_read_map(s);
3210 isl_stream_free(s);
3211 return map;
3212 }
3213
isl_map_read_from_str(struct isl_ctx * ctx,const char * str)3214 __isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx,
3215 const char *str)
3216 {
3217 struct isl_map *map;
3218 isl_stream *s = isl_stream_new_str(ctx, str);
3219 if (!s)
3220 return NULL;
3221 map = isl_stream_read_map(s);
3222 isl_stream_free(s);
3223 return map;
3224 }
3225
isl_set_read_from_file(struct isl_ctx * ctx,FILE * input)3226 __isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx,
3227 FILE *input)
3228 {
3229 isl_set *set;
3230 isl_stream *s = isl_stream_new_file(ctx, input);
3231 if (!s)
3232 return NULL;
3233 set = isl_stream_read_set(s);
3234 isl_stream_free(s);
3235 return set;
3236 }
3237
isl_set_read_from_str(isl_ctx * ctx,const char * str)3238 __isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, const char *str)
3239 {
3240 isl_set *set;
3241 isl_stream *s = isl_stream_new_str(ctx, str);
3242 if (!s)
3243 return NULL;
3244 set = isl_stream_read_set(s);
3245 isl_stream_free(s);
3246 return set;
3247 }
3248
isl_union_map_read_from_file(isl_ctx * ctx,FILE * input)3249 __isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
3250 FILE *input)
3251 {
3252 isl_union_map *umap;
3253 isl_stream *s = isl_stream_new_file(ctx, input);
3254 if (!s)
3255 return NULL;
3256 umap = isl_stream_read_union_map(s);
3257 isl_stream_free(s);
3258 return umap;
3259 }
3260
isl_union_map_read_from_str(struct isl_ctx * ctx,const char * str)3261 __isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
3262 const char *str)
3263 {
3264 isl_union_map *umap;
3265 isl_stream *s = isl_stream_new_str(ctx, str);
3266 if (!s)
3267 return NULL;
3268 umap = isl_stream_read_union_map(s);
3269 isl_stream_free(s);
3270 return umap;
3271 }
3272
isl_union_set_read_from_file(isl_ctx * ctx,FILE * input)3273 __isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
3274 FILE *input)
3275 {
3276 isl_union_set *uset;
3277 isl_stream *s = isl_stream_new_file(ctx, input);
3278 if (!s)
3279 return NULL;
3280 uset = isl_stream_read_union_set(s);
3281 isl_stream_free(s);
3282 return uset;
3283 }
3284
isl_union_set_read_from_str(struct isl_ctx * ctx,const char * str)3285 __isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
3286 const char *str)
3287 {
3288 isl_union_set *uset;
3289 isl_stream *s = isl_stream_new_str(ctx, str);
3290 if (!s)
3291 return NULL;
3292 uset = isl_stream_read_union_set(s);
3293 isl_stream_free(s);
3294 return uset;
3295 }
3296
isl_vec_read_polylib(__isl_keep isl_stream * s)3297 static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s)
3298 {
3299 struct isl_vec *vec = NULL;
3300 struct isl_token *tok;
3301 unsigned size;
3302 int j;
3303
3304 tok = isl_stream_next_token(s);
3305 if (!tok || tok->type != ISL_TOKEN_VALUE) {
3306 isl_stream_error(s, tok, "expecting vector length");
3307 goto error;
3308 }
3309
3310 size = isl_int_get_si(tok->u.v);
3311 isl_token_free(tok);
3312
3313 vec = isl_vec_alloc(s->ctx, size);
3314
3315 for (j = 0; j < size; ++j) {
3316 tok = isl_stream_next_token(s);
3317 if (!tok || tok->type != ISL_TOKEN_VALUE) {
3318 isl_stream_error(s, tok, "expecting constant value");
3319 goto error;
3320 }
3321 isl_int_set(vec->el[j], tok->u.v);
3322 isl_token_free(tok);
3323 }
3324
3325 return vec;
3326 error:
3327 isl_token_free(tok);
3328 isl_vec_free(vec);
3329 return NULL;
3330 }
3331
vec_read(__isl_keep isl_stream * s)3332 static __isl_give isl_vec *vec_read(__isl_keep isl_stream *s)
3333 {
3334 return isl_vec_read_polylib(s);
3335 }
3336
isl_vec_read_from_file(isl_ctx * ctx,FILE * input)3337 __isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
3338 {
3339 isl_vec *v;
3340 isl_stream *s = isl_stream_new_file(ctx, input);
3341 if (!s)
3342 return NULL;
3343 v = vec_read(s);
3344 isl_stream_free(s);
3345 return v;
3346 }
3347
isl_stream_read_pw_qpolynomial(__isl_keep isl_stream * s)3348 __isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
3349 __isl_keep isl_stream *s)
3350 {
3351 struct isl_obj obj;
3352
3353 obj = obj_read(s);
3354 if (obj.v)
3355 isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial,
3356 goto error);
3357
3358 return obj.v;
3359 error:
3360 obj.type->free(obj.v);
3361 return NULL;
3362 }
3363
isl_pw_qpolynomial_read_from_str(isl_ctx * ctx,const char * str)3364 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
3365 const char *str)
3366 {
3367 isl_pw_qpolynomial *pwqp;
3368 isl_stream *s = isl_stream_new_str(ctx, str);
3369 if (!s)
3370 return NULL;
3371 pwqp = isl_stream_read_pw_qpolynomial(s);
3372 isl_stream_free(s);
3373 return pwqp;
3374 }
3375
isl_pw_qpolynomial_read_from_file(isl_ctx * ctx,FILE * input)3376 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
3377 FILE *input)
3378 {
3379 isl_pw_qpolynomial *pwqp;
3380 isl_stream *s = isl_stream_new_file(ctx, input);
3381 if (!s)
3382 return NULL;
3383 pwqp = isl_stream_read_pw_qpolynomial(s);
3384 isl_stream_free(s);
3385 return pwqp;
3386 }
3387
3388 /* Is the next token an identifer not in "v"?
3389 */
next_is_fresh_ident(__isl_keep isl_stream * s,struct vars * v)3390 static int next_is_fresh_ident(__isl_keep isl_stream *s, struct vars *v)
3391 {
3392 int n = v->n;
3393 int fresh;
3394 struct isl_token *tok;
3395
3396 tok = isl_stream_next_token(s);
3397 if (!tok)
3398 return 0;
3399 fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
3400 isl_stream_push_token(s, tok);
3401
3402 vars_drop(v, v->n - n);
3403
3404 return fresh;
3405 }
3406
3407 /* First read the domain of the affine expression, which may be
3408 * a parameter space or a set.
3409 * The tricky part is that we don't know if the domain is a set or not,
3410 * so when we are trying to read the domain, we may actually be reading
3411 * the affine expression itself (defined on a parameter domains)
3412 * If the tuple we are reading is named, we assume it's the domain.
3413 * Also, if inside the tuple, the first thing we find is a nested tuple
3414 * or a new identifier, we again assume it's the domain.
3415 * Finally, if the tuple is empty, then it must be the domain
3416 * since it does not contain an affine expression.
3417 * Otherwise, we assume we are reading an affine expression.
3418 */
read_aff_domain(__isl_keep isl_stream * s,__isl_take isl_set * dom,struct vars * v)3419 static __isl_give isl_set *read_aff_domain(__isl_keep isl_stream *s,
3420 __isl_take isl_set *dom, struct vars *v)
3421 {
3422 struct isl_token *tok, *tok2;
3423 int is_empty;
3424
3425 tok = isl_stream_next_token(s);
3426 if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
3427 isl_stream_push_token(s, tok);
3428 return read_map_tuple(s, dom, isl_dim_set, v, 0, 0);
3429 }
3430 if (!tok || tok->type != '[') {
3431 isl_stream_error(s, tok, "expecting '['");
3432 goto error;
3433 }
3434 tok2 = isl_stream_next_token(s);
3435 is_empty = tok2 && tok2->type == ']';
3436 if (tok2)
3437 isl_stream_push_token(s, tok2);
3438 if (is_empty || next_is_tuple(s) || next_is_fresh_ident(s, v)) {
3439 isl_stream_push_token(s, tok);
3440 dom = read_map_tuple(s, dom, isl_dim_set, v, 0, 0);
3441 } else
3442 isl_stream_push_token(s, tok);
3443
3444 return dom;
3445 error:
3446 if (tok)
3447 isl_stream_push_token(s, tok);
3448 isl_set_free(dom);
3449 return NULL;
3450 }
3451
3452 /* Read an affine expression from "s".
3453 */
isl_stream_read_aff(__isl_keep isl_stream * s)3454 __isl_give isl_aff *isl_stream_read_aff(__isl_keep isl_stream *s)
3455 {
3456 isl_aff *aff;
3457 isl_multi_aff *ma;
3458 isl_size dim;
3459
3460 ma = isl_stream_read_multi_aff(s);
3461 dim = isl_multi_aff_dim(ma, isl_dim_out);
3462 if (dim < 0)
3463 goto error;
3464 if (dim != 1)
3465 isl_die(s->ctx, isl_error_invalid,
3466 "expecting single affine expression",
3467 goto error);
3468
3469 aff = isl_multi_aff_get_aff(ma, 0);
3470 isl_multi_aff_free(ma);
3471 return aff;
3472 error:
3473 isl_multi_aff_free(ma);
3474 return NULL;
3475 }
3476
3477 /* Read a piecewise affine expression from "s" with domain (space) "dom".
3478 */
read_pw_aff_with_dom(__isl_keep isl_stream * s,__isl_take isl_set * dom,struct vars * v)3479 static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s,
3480 __isl_take isl_set *dom, struct vars *v)
3481 {
3482 isl_pw_aff *pwaff = NULL;
3483
3484 if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
3485 goto error;
3486
3487 if (isl_stream_eat(s, '['))
3488 goto error;
3489
3490 pwaff = accept_affine(s, isl_set_get_space(dom), v);
3491
3492 if (isl_stream_eat(s, ']'))
3493 goto error;
3494
3495 dom = read_optional_formula(s, dom, v, 0);
3496 pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
3497
3498 return pwaff;
3499 error:
3500 isl_set_free(dom);
3501 isl_pw_aff_free(pwaff);
3502 return NULL;
3503 }
3504
isl_stream_read_pw_aff(__isl_keep isl_stream * s)3505 __isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s)
3506 {
3507 struct vars *v;
3508 isl_set *dom = NULL;
3509 isl_set *aff_dom;
3510 isl_pw_aff *pa = NULL;
3511 int n;
3512
3513 v = vars_new(s->ctx);
3514 if (!v)
3515 return NULL;
3516
3517 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3518 if (next_is_tuple(s)) {
3519 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3520 if (isl_stream_eat(s, ISL_TOKEN_TO))
3521 goto error;
3522 }
3523 if (isl_stream_eat(s, '{'))
3524 goto error;
3525
3526 n = v->n;
3527 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
3528 pa = read_pw_aff_with_dom(s, aff_dom, v);
3529 vars_drop(v, v->n - n);
3530
3531 while (isl_stream_eat_if_available(s, ';')) {
3532 isl_pw_aff *pa_i;
3533
3534 n = v->n;
3535 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
3536 pa_i = read_pw_aff_with_dom(s, aff_dom, v);
3537 vars_drop(v, v->n - n);
3538
3539 pa = isl_pw_aff_union_add(pa, pa_i);
3540 }
3541
3542 if (isl_stream_eat(s, '}'))
3543 goto error;
3544
3545 vars_free(v);
3546 isl_set_free(dom);
3547 return pa;
3548 error:
3549 vars_free(v);
3550 isl_set_free(dom);
3551 isl_pw_aff_free(pa);
3552 return NULL;
3553 }
3554
isl_aff_read_from_str(isl_ctx * ctx,const char * str)3555 __isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str)
3556 {
3557 isl_aff *aff;
3558 isl_stream *s = isl_stream_new_str(ctx, str);
3559 if (!s)
3560 return NULL;
3561 aff = isl_stream_read_aff(s);
3562 isl_stream_free(s);
3563 return aff;
3564 }
3565
isl_pw_aff_read_from_str(isl_ctx * ctx,const char * str)3566 __isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
3567 {
3568 isl_pw_aff *pa;
3569 isl_stream *s = isl_stream_new_str(ctx, str);
3570 if (!s)
3571 return NULL;
3572 pa = isl_stream_read_pw_aff(s);
3573 isl_stream_free(s);
3574 return pa;
3575 }
3576
3577 /* Extract an isl_multi_pw_aff with domain space "dom_space"
3578 * from a tuple "tuple" read by read_tuple.
3579 *
3580 * Note that the function read_tuple accepts tuples where some output or
3581 * set dimensions are defined in terms of other output or set dimensions
3582 * since this function is also used to read maps. As a special case,
3583 * read_tuple also accept dimensions that are defined in terms of themselves
3584 * (i.e., that are not defined).
3585 * These cases are not allowed when extracting an isl_multi_pw_aff so check
3586 * that the definitions of the output/set dimensions do not involve any
3587 * output/set dimensions.
3588 * Finally, drop the output dimensions from the domain of the result
3589 * of read_tuple (which is of the form [input, output] -> [output],
3590 * with anonymous domain) and reset the space.
3591 */
extract_mpa_from_tuple(__isl_take isl_space * dom_space,__isl_keep isl_multi_pw_aff * tuple)3592 static __isl_give isl_multi_pw_aff *extract_mpa_from_tuple(
3593 __isl_take isl_space *dom_space, __isl_keep isl_multi_pw_aff *tuple)
3594 {
3595 int i;
3596 isl_size dim, n;
3597 isl_space *space;
3598 isl_multi_pw_aff *mpa;
3599
3600 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
3601 dim = isl_space_dim(dom_space, isl_dim_all);
3602 if (n < 0 || dim < 0)
3603 dom_space = isl_space_free(dom_space);
3604 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
3605 space = isl_space_align_params(space, isl_space_copy(dom_space));
3606 if (!isl_space_is_params(dom_space))
3607 space = isl_space_map_from_domain_and_range(
3608 isl_space_copy(dom_space), space);
3609 isl_space_free(dom_space);
3610 mpa = isl_multi_pw_aff_alloc(space);
3611
3612 for (i = 0; i < n; ++i) {
3613 isl_pw_aff *pa;
3614 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
3615 if (!pa)
3616 return isl_multi_pw_aff_free(mpa);
3617 if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
3618 isl_ctx *ctx = isl_pw_aff_get_ctx(pa);
3619 isl_pw_aff_free(pa);
3620 isl_die(ctx, isl_error_invalid,
3621 "not an affine expression",
3622 return isl_multi_pw_aff_free(mpa));
3623 }
3624 pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n);
3625 space = isl_multi_pw_aff_get_domain_space(mpa);
3626 pa = isl_pw_aff_reset_domain_space(pa, space);
3627 mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
3628 }
3629
3630 return mpa;
3631 }
3632
3633 /* Read a tuple of affine expressions, together with optional constraints
3634 * on the domain from "s". "dom" represents the initial constraints
3635 * on the domain.
3636 *
3637 * The isl_multi_aff may live in either a set or a map space.
3638 * First read the first tuple and check if it is followed by a "->".
3639 * If so, convert the tuple into the domain of the isl_multi_pw_aff and
3640 * read in the next tuple. This tuple (or the first tuple if it was
3641 * not followed by a "->") is then converted into an isl_multi_pw_aff
3642 * through a call to extract_mpa_from_tuple.
3643 * The result is converted to an isl_pw_multi_aff and
3644 * its domain is intersected with the domain.
3645 */
read_conditional_multi_aff(__isl_keep isl_stream * s,__isl_take isl_set * dom,struct vars * v)3646 static __isl_give isl_pw_multi_aff *read_conditional_multi_aff(
3647 __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
3648 {
3649 isl_multi_pw_aff *tuple;
3650 isl_multi_pw_aff *mpa;
3651 isl_pw_multi_aff *pma;
3652 int n = v->n;
3653
3654 tuple = read_tuple(s, v, 0, 0);
3655 if (!tuple)
3656 goto error;
3657 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
3658 isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
3659 dom = isl_map_domain(map);
3660 tuple = read_tuple(s, v, 0, 0);
3661 if (!tuple)
3662 goto error;
3663 }
3664 mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
3665 isl_multi_pw_aff_free(tuple);
3666 if (!mpa)
3667 dom = isl_set_free(dom);
3668
3669 dom = read_optional_formula(s, dom, v, 0);
3670
3671 vars_drop(v, v->n - n);
3672
3673 pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
3674 pma = isl_pw_multi_aff_intersect_domain(pma, dom);
3675
3676 return pma;
3677 error:
3678 isl_set_free(dom);
3679 return NULL;
3680 }
3681
3682 /* Read an isl_union_pw_multi_aff from "s".
3683 *
3684 * In particular, first read the parameters and then read a sequence
3685 * of zero or more tuples of affine expressions with optional conditions and
3686 * add them up.
3687 */
isl_stream_read_union_pw_multi_aff(__isl_keep isl_stream * s)3688 __isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
3689 __isl_keep isl_stream *s)
3690 {
3691 struct vars *v;
3692 isl_set *dom;
3693 isl_union_pw_multi_aff *upma = NULL;
3694
3695 v = vars_new(s->ctx);
3696 if (!v)
3697 return NULL;
3698
3699 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3700 if (next_is_tuple(s)) {
3701 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3702 if (isl_stream_eat(s, ISL_TOKEN_TO))
3703 goto error;
3704 }
3705 if (isl_stream_eat(s, '{'))
3706 goto error;
3707
3708 upma = isl_union_pw_multi_aff_empty(isl_set_get_space(dom));
3709
3710 do {
3711 isl_pw_multi_aff *pma;
3712 isl_union_pw_multi_aff *upma2;
3713
3714 if (isl_stream_next_token_is(s, '}'))
3715 break;
3716
3717 pma = read_conditional_multi_aff(s, isl_set_copy(dom), v);
3718 upma2 = isl_union_pw_multi_aff_from_pw_multi_aff(pma);
3719 upma = isl_union_pw_multi_aff_union_add(upma, upma2);
3720 if (!upma)
3721 goto error;
3722 } while (isl_stream_eat_if_available(s, ';'));
3723
3724 if (isl_stream_eat(s, '}'))
3725 goto error;
3726
3727 isl_set_free(dom);
3728 vars_free(v);
3729 return upma;
3730 error:
3731 isl_union_pw_multi_aff_free(upma);
3732 isl_set_free(dom);
3733 vars_free(v);
3734 return NULL;
3735 }
3736
3737 /* Read an isl_pw_multi_aff from "s".
3738 *
3739 * Read a more generic isl_union_pw_multi_aff first and
3740 * then check that the result lives in a single space.
3741 */
isl_stream_read_pw_multi_aff(__isl_keep isl_stream * s)3742 __isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(
3743 __isl_keep isl_stream *s)
3744 {
3745 isl_bool single_space;
3746 isl_union_pw_multi_aff *upma;
3747
3748 upma = isl_stream_read_union_pw_multi_aff(s);
3749 single_space = isl_union_pw_multi_aff_isa_pw_multi_aff(upma);
3750 if (single_space < 0)
3751 upma = isl_union_pw_multi_aff_free(upma);
3752 else if (!single_space)
3753 isl_die(s->ctx, isl_error_invalid,
3754 "expecting expression in single space",
3755 upma = isl_union_pw_multi_aff_free(upma));
3756 return isl_union_pw_multi_aff_as_pw_multi_aff(upma);
3757 }
3758
isl_pw_multi_aff_read_from_str(isl_ctx * ctx,const char * str)3759 __isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
3760 const char *str)
3761 {
3762 isl_pw_multi_aff *pma;
3763 isl_stream *s = isl_stream_new_str(ctx, str);
3764 if (!s)
3765 return NULL;
3766 pma = isl_stream_read_pw_multi_aff(s);
3767 isl_stream_free(s);
3768 return pma;
3769 }
3770
3771 /* Read an isl_union_pw_multi_aff from "str".
3772 */
isl_union_pw_multi_aff_read_from_str(isl_ctx * ctx,const char * str)3773 __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
3774 isl_ctx *ctx, const char *str)
3775 {
3776 isl_union_pw_multi_aff *upma;
3777 isl_stream *s = isl_stream_new_str(ctx, str);
3778 if (!s)
3779 return NULL;
3780 upma = isl_stream_read_union_pw_multi_aff(s);
3781 isl_stream_free(s);
3782 return upma;
3783 }
3784
3785 /* Assuming "pa" represents a single affine expression defined on a universe
3786 * domain, extract this affine expression.
3787 */
aff_from_pw_aff(__isl_take isl_pw_aff * pa)3788 static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
3789 {
3790 isl_aff *aff;
3791
3792 if (!pa)
3793 return NULL;
3794 if (pa->n != 1)
3795 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
3796 "expecting single affine expression",
3797 goto error);
3798 if (!isl_set_plain_is_universe(pa->p[0].set))
3799 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
3800 "expecting universe domain",
3801 goto error);
3802
3803 aff = isl_aff_copy(pa->p[0].aff);
3804 isl_pw_aff_free(pa);
3805 return aff;
3806 error:
3807 isl_pw_aff_free(pa);
3808 return NULL;
3809 }
3810
3811 #undef BASE
3812 #define BASE val
3813
3814 #include <isl_multi_read_no_explicit_domain_templ.c>
3815
3816 #undef BASE
3817 #define BASE id
3818
3819 #include <isl_multi_read_no_explicit_domain_templ.c>
3820
3821 /* Read a multi-affine expression from "s".
3822 * If the multi-affine expression has a domain, then the tuple
3823 * representing this domain cannot involve any affine expressions.
3824 * The tuple representing the actual expressions needs to consist
3825 * of only affine expressions. Moreover, these expressions can
3826 * only depend on parameters and input dimensions and not on other
3827 * output dimensions.
3828 */
isl_stream_read_multi_aff(__isl_keep isl_stream * s)3829 __isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s)
3830 {
3831 struct vars *v;
3832 isl_set *dom = NULL;
3833 isl_multi_pw_aff *tuple = NULL;
3834 int i;
3835 isl_size dim, n;
3836 isl_space *space, *dom_space;
3837 isl_multi_aff *ma = NULL;
3838
3839 v = vars_new(s->ctx);
3840 if (!v)
3841 return NULL;
3842
3843 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3844 if (next_is_tuple(s)) {
3845 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3846 if (isl_stream_eat(s, ISL_TOKEN_TO))
3847 goto error;
3848 }
3849 if (!isl_set_plain_is_universe(dom))
3850 isl_die(s->ctx, isl_error_invalid,
3851 "expecting universe parameter domain", goto error);
3852 if (isl_stream_eat(s, '{'))
3853 goto error;
3854
3855 tuple = read_tuple(s, v, 0, 0);
3856 if (!tuple)
3857 goto error;
3858 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
3859 isl_set *set;
3860 isl_space *space;
3861 isl_bool has_expr;
3862
3863 has_expr = tuple_has_expr(tuple);
3864 if (has_expr < 0)
3865 goto error;
3866 if (has_expr)
3867 isl_die(s->ctx, isl_error_invalid,
3868 "expecting universe domain", goto error);
3869 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
3870 set = isl_set_universe(space);
3871 dom = isl_set_intersect_params(set, dom);
3872 isl_multi_pw_aff_free(tuple);
3873 tuple = read_tuple(s, v, 0, 0);
3874 if (!tuple)
3875 goto error;
3876 }
3877
3878 if (isl_stream_eat(s, '}'))
3879 goto error;
3880
3881 n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
3882 dim = isl_set_dim(dom, isl_dim_all);
3883 if (n < 0 || dim < 0)
3884 goto error;
3885 dom_space = isl_set_get_space(dom);
3886 space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
3887 space = isl_space_align_params(space, isl_space_copy(dom_space));
3888 if (!isl_space_is_params(dom_space))
3889 space = isl_space_map_from_domain_and_range(
3890 isl_space_copy(dom_space), space);
3891 isl_space_free(dom_space);
3892 ma = isl_multi_aff_alloc(space);
3893
3894 for (i = 0; i < n; ++i) {
3895 isl_pw_aff *pa;
3896 isl_aff *aff;
3897 pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
3898 aff = aff_from_pw_aff(pa);
3899 if (!aff)
3900 goto error;
3901 if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) {
3902 isl_aff_free(aff);
3903 isl_die(s->ctx, isl_error_invalid,
3904 "not an affine expression", goto error);
3905 }
3906 aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n);
3907 space = isl_multi_aff_get_domain_space(ma);
3908 aff = isl_aff_reset_domain_space(aff, space);
3909 ma = isl_multi_aff_set_aff(ma, i, aff);
3910 }
3911
3912 isl_multi_pw_aff_free(tuple);
3913 vars_free(v);
3914 isl_set_free(dom);
3915 return ma;
3916 error:
3917 isl_multi_pw_aff_free(tuple);
3918 vars_free(v);
3919 isl_set_free(dom);
3920 isl_multi_aff_free(ma);
3921 return NULL;
3922 }
3923
isl_multi_aff_read_from_str(isl_ctx * ctx,const char * str)3924 __isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
3925 const char *str)
3926 {
3927 isl_multi_aff *maff;
3928 isl_stream *s = isl_stream_new_str(ctx, str);
3929 if (!s)
3930 return NULL;
3931 maff = isl_stream_read_multi_aff(s);
3932 isl_stream_free(s);
3933 return maff;
3934 }
3935
3936 /* Read an isl_multi_pw_aff from "s".
3937 *
3938 * The input format is similar to that of map, except that any conditions
3939 * on the domains should be specified inside the tuple since each
3940 * piecewise affine expression may have a different domain.
3941 * However, additional, shared conditions can also be specified.
3942 * This is especially useful for setting the explicit domain
3943 * of a zero-dimensional isl_multi_pw_aff.
3944 *
3945 * Since we do not know in advance if the isl_multi_pw_aff lives
3946 * in a set or a map space, we first read the first tuple and check
3947 * if it is followed by a "->". If so, we convert the tuple into
3948 * the domain of the isl_multi_pw_aff and read in the next tuple.
3949 * This tuple (or the first tuple if it was not followed by a "->")
3950 * is then converted into the isl_multi_pw_aff through a call
3951 * to extract_mpa_from_tuple and the domain of the result
3952 * is intersected with the domain.
3953 */
isl_stream_read_multi_pw_aff(__isl_keep isl_stream * s)3954 __isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(
3955 __isl_keep isl_stream *s)
3956 {
3957 struct vars *v;
3958 isl_set *dom = NULL;
3959 isl_multi_pw_aff *tuple = NULL;
3960 isl_multi_pw_aff *mpa = NULL;
3961
3962 v = vars_new(s->ctx);
3963 if (!v)
3964 return NULL;
3965
3966 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
3967 if (next_is_tuple(s)) {
3968 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
3969 if (isl_stream_eat(s, ISL_TOKEN_TO))
3970 goto error;
3971 }
3972 if (isl_stream_eat(s, '{'))
3973 goto error;
3974
3975 tuple = read_tuple(s, v, 0, 0);
3976 if (!tuple)
3977 goto error;
3978 if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
3979 isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
3980 dom = isl_map_domain(map);
3981 tuple = read_tuple(s, v, 0, 0);
3982 if (!tuple)
3983 goto error;
3984 }
3985
3986 if (isl_stream_eat_if_available(s, ':'))
3987 dom = read_formula(s, v, dom, 0);
3988
3989 if (isl_stream_eat(s, '}'))
3990 goto error;
3991
3992 mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
3993
3994 isl_multi_pw_aff_free(tuple);
3995 vars_free(v);
3996 mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);
3997 return mpa;
3998 error:
3999 isl_multi_pw_aff_free(tuple);
4000 vars_free(v);
4001 isl_set_free(dom);
4002 isl_multi_pw_aff_free(mpa);
4003 return NULL;
4004 }
4005
4006 /* Read an isl_multi_pw_aff from "str".
4007 */
isl_multi_pw_aff_read_from_str(isl_ctx * ctx,const char * str)4008 __isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
4009 const char *str)
4010 {
4011 isl_multi_pw_aff *mpa;
4012 isl_stream *s = isl_stream_new_str(ctx, str);
4013 if (!s)
4014 return NULL;
4015 mpa = isl_stream_read_multi_pw_aff(s);
4016 isl_stream_free(s);
4017 return mpa;
4018 }
4019
4020 /* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom".
4021 */
read_union_pw_aff_with_dom(__isl_keep isl_stream * s,__isl_take isl_set * dom,struct vars * v)4022 static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom(
4023 __isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
4024 {
4025 isl_pw_aff *pa;
4026 isl_union_pw_aff *upa = NULL;
4027 isl_set *aff_dom;
4028 int n;
4029
4030 n = v->n;
4031 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
4032 pa = read_pw_aff_with_dom(s, aff_dom, v);
4033 vars_drop(v, v->n - n);
4034
4035 upa = isl_union_pw_aff_from_pw_aff(pa);
4036
4037 while (isl_stream_eat_if_available(s, ';')) {
4038 isl_pw_aff *pa_i;
4039 isl_union_pw_aff *upa_i;
4040
4041 n = v->n;
4042 aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
4043 pa_i = read_pw_aff_with_dom(s, aff_dom, v);
4044 vars_drop(v, v->n - n);
4045
4046 upa_i = isl_union_pw_aff_from_pw_aff(pa_i);
4047 upa = isl_union_pw_aff_union_add(upa, upa_i);
4048 }
4049
4050 isl_set_free(dom);
4051 return upa;
4052 }
4053
4054 /* Read an isl_union_pw_aff from "s".
4055 *
4056 * First check if there are any paramters, then read in the opening brace
4057 * and use read_union_pw_aff_with_dom to read in the body of
4058 * the isl_union_pw_aff. Finally, read the closing brace.
4059 */
isl_stream_read_union_pw_aff(__isl_keep isl_stream * s)4060 __isl_give isl_union_pw_aff *isl_stream_read_union_pw_aff(
4061 __isl_keep isl_stream *s)
4062 {
4063 struct vars *v;
4064 isl_set *dom;
4065 isl_union_pw_aff *upa = NULL;
4066
4067 v = vars_new(s->ctx);
4068 if (!v)
4069 return NULL;
4070
4071 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
4072 if (next_is_tuple(s)) {
4073 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
4074 if (isl_stream_eat(s, ISL_TOKEN_TO))
4075 goto error;
4076 }
4077 if (isl_stream_eat(s, '{'))
4078 goto error;
4079
4080 upa = read_union_pw_aff_with_dom(s, isl_set_copy(dom), v);
4081
4082 if (isl_stream_eat(s, '}'))
4083 goto error;
4084
4085 vars_free(v);
4086 isl_set_free(dom);
4087 return upa;
4088 error:
4089 vars_free(v);
4090 isl_set_free(dom);
4091 isl_union_pw_aff_free(upa);
4092 return NULL;
4093 }
4094
4095 /* Read an isl_union_pw_aff from "str".
4096 */
isl_union_pw_aff_read_from_str(isl_ctx * ctx,const char * str)4097 __isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx,
4098 const char *str)
4099 {
4100 isl_union_pw_aff *upa;
4101 isl_stream *s = isl_stream_new_str(ctx, str);
4102 if (!s)
4103 return NULL;
4104 upa = isl_stream_read_union_pw_aff(s);
4105 isl_stream_free(s);
4106 return upa;
4107 }
4108
4109 /* This function is called for each element in a tuple inside
4110 * isl_stream_read_multi_union_pw_aff.
4111 *
4112 * Read a '{', the union piecewise affine expression body and a '}' and
4113 * add the isl_union_pw_aff to *list.
4114 */
read_union_pw_aff_el(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space,int rational,void * user)4115 static __isl_give isl_space *read_union_pw_aff_el(__isl_keep isl_stream *s,
4116 struct vars *v, __isl_take isl_space *space, int rational, void *user)
4117 {
4118 isl_set *dom;
4119 isl_union_pw_aff *upa;
4120 isl_union_pw_aff_list **list = (isl_union_pw_aff_list **) user;
4121
4122 dom = isl_set_universe(isl_space_params(isl_space_copy(space)));
4123 if (isl_stream_eat(s, '{'))
4124 goto error;
4125 upa = read_union_pw_aff_with_dom(s, dom, v);
4126 *list = isl_union_pw_aff_list_add(*list, upa);
4127 if (isl_stream_eat(s, '}'))
4128 return isl_space_free(space);
4129 if (!*list)
4130 return isl_space_free(space);
4131 return space;
4132 error:
4133 isl_set_free(dom);
4134 return isl_space_free(space);
4135 }
4136
4137 /* Do the next tokens in "s" correspond to an empty tuple?
4138 * In particular, does the stream start with a '[', followed by a ']',
4139 * not followed by a "->"?
4140 */
next_is_empty_tuple(__isl_keep isl_stream * s)4141 static int next_is_empty_tuple(__isl_keep isl_stream *s)
4142 {
4143 struct isl_token *tok, *tok2, *tok3;
4144 int is_empty_tuple = 0;
4145
4146 tok = isl_stream_next_token(s);
4147 if (!tok)
4148 return 0;
4149 if (tok->type != '[') {
4150 isl_stream_push_token(s, tok);
4151 return 0;
4152 }
4153
4154 tok2 = isl_stream_next_token(s);
4155 if (tok2 && tok2->type == ']') {
4156 tok3 = isl_stream_next_token(s);
4157 is_empty_tuple = !tok || tok->type != ISL_TOKEN_TO;
4158 if (tok3)
4159 isl_stream_push_token(s, tok3);
4160 }
4161 if (tok2)
4162 isl_stream_push_token(s, tok2);
4163 isl_stream_push_token(s, tok);
4164
4165 return is_empty_tuple;
4166 }
4167
4168 /* Do the next tokens in "s" correspond to a tuple of parameters?
4169 * In particular, does the stream start with a '[' that is not
4170 * followed by a '{' or a nested tuple?
4171 */
next_is_param_tuple(__isl_keep isl_stream * s)4172 static int next_is_param_tuple(__isl_keep isl_stream *s)
4173 {
4174 struct isl_token *tok, *tok2;
4175 int is_tuple;
4176
4177 tok = isl_stream_next_token(s);
4178 if (!tok)
4179 return 0;
4180 if (tok->type != '[' || next_is_tuple(s)) {
4181 isl_stream_push_token(s, tok);
4182 return 0;
4183 }
4184
4185 tok2 = isl_stream_next_token(s);
4186 is_tuple = tok2 && tok2->type != '{';
4187 if (tok2)
4188 isl_stream_push_token(s, tok2);
4189 isl_stream_push_token(s, tok);
4190
4191 return is_tuple;
4192 }
4193
4194 /* Read the core of a body of an isl_multi_union_pw_aff from "s",
4195 * i.e., everything except the parameter specification and
4196 * without shared domain constraints.
4197 * "v" contains a description of the identifiers parsed so far.
4198 * The parameters, if any, are specified by "space".
4199 *
4200 * The body is of the form
4201 *
4202 * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4203 *
4204 * Read the tuple, collecting the individual isl_union_pw_aff
4205 * elements in a list and construct the result from the tuple space and
4206 * the list.
4207 */
read_multi_union_pw_aff_body_core(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space)4208 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_body_core(
4209 __isl_keep isl_stream *s, struct vars *v, __isl_take isl_space *space)
4210 {
4211 isl_union_pw_aff_list *list;
4212 isl_multi_union_pw_aff *mupa;
4213
4214 list = isl_union_pw_aff_list_alloc(s->ctx, 0);
4215 space = read_tuple_space(s, v, space, 1, 0,
4216 &read_union_pw_aff_el, &list);
4217 mupa = isl_multi_union_pw_aff_from_union_pw_aff_list(space, list);
4218
4219 return mupa;
4220 }
4221
4222 /* Read the body of an isl_union_set from "s",
4223 * i.e., everything except the parameter specification.
4224 * "v" contains a description of the identifiers parsed so far.
4225 * The parameters, if any, are specified by "space".
4226 *
4227 * First read a generic disjunction of object bodies and then try and extract
4228 * an isl_union_set from that.
4229 */
read_union_set_body(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space)4230 static __isl_give isl_union_set *read_union_set_body(__isl_keep isl_stream *s,
4231 struct vars *v, __isl_take isl_space *space)
4232 {
4233 struct isl_obj obj = { isl_obj_set, NULL };
4234 isl_map *map;
4235
4236 map = isl_set_universe(space);
4237 if (isl_stream_eat(s, '{') < 0)
4238 goto error;
4239 obj = obj_read_disjuncts(s, v, map);
4240 if (isl_stream_eat(s, '}') < 0)
4241 goto error;
4242 isl_map_free(map);
4243
4244 return extract_union_set(s->ctx, obj);
4245 error:
4246 obj.type->free(obj.v);
4247 isl_map_free(map);
4248 return NULL;
4249 }
4250
4251 /* Read the body of an isl_multi_union_pw_aff from "s",
4252 * i.e., everything except the parameter specification.
4253 * "v" contains a description of the identifiers parsed so far.
4254 * The parameters, if any, are specified by "space".
4255 *
4256 * In particular, handle the special case with shared domain constraints.
4257 * These are specified as
4258 *
4259 * ([...] : ...)
4260 *
4261 * and are especially useful for setting the explicit domain
4262 * of a zero-dimensional isl_multi_union_pw_aff.
4263 * The core isl_multi_union_pw_aff body ([...]) is read by
4264 * read_multi_union_pw_aff_body_core.
4265 */
read_multi_union_pw_aff_body(__isl_keep isl_stream * s,struct vars * v,__isl_take isl_space * space)4266 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_body(
4267 __isl_keep isl_stream *s, struct vars *v, __isl_take isl_space *space)
4268 {
4269 isl_multi_union_pw_aff *mupa;
4270
4271 if (!isl_stream_next_token_is(s, '('))
4272 return read_multi_union_pw_aff_body_core(s, v, space);
4273
4274 if (isl_stream_eat(s, '(') < 0)
4275 goto error;
4276 mupa = read_multi_union_pw_aff_body_core(s, v, isl_space_copy(space));
4277 if (isl_stream_eat_if_available(s, ':')) {
4278 isl_union_set *dom;
4279
4280 dom = read_union_set_body(s, v, space);
4281 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);
4282 } else {
4283 isl_space_free(space);
4284 }
4285 if (isl_stream_eat(s, ')') < 0)
4286 return isl_multi_union_pw_aff_free(mupa);
4287
4288 return mupa;
4289 error:
4290 isl_space_free(space);
4291 return NULL;
4292 }
4293
4294 /* Read an isl_multi_union_pw_aff from "s".
4295 *
4296 * The input has the form
4297 *
4298 * [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4299 *
4300 * or
4301 *
4302 * [..] -> [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
4303 *
4304 * Additionally, a shared domain may be specified as
4305 *
4306 * ([..] : ...)
4307 *
4308 * or
4309 *
4310 * [..] -> ([..] : ...)
4311 *
4312 * The first case is handled by the caller, the second case
4313 * is handled by read_multi_union_pw_aff_body.
4314 *
4315 * We first check for the special case of an empty tuple "[]".
4316 * Then we check if there are any parameters.
4317 * Finally, read the tuple and construct the result.
4318 */
read_multi_union_pw_aff_core(__isl_keep isl_stream * s)4319 static __isl_give isl_multi_union_pw_aff *read_multi_union_pw_aff_core(
4320 __isl_keep isl_stream *s)
4321 {
4322 struct vars *v;
4323 isl_set *dom = NULL;
4324 isl_space *space;
4325 isl_multi_union_pw_aff *mupa = NULL;
4326
4327 if (next_is_empty_tuple(s)) {
4328 if (isl_stream_eat(s, '['))
4329 return NULL;
4330 if (isl_stream_eat(s, ']'))
4331 return NULL;
4332 space = isl_space_set_alloc(s->ctx, 0, 0);
4333 return isl_multi_union_pw_aff_zero(space);
4334 }
4335
4336 v = vars_new(s->ctx);
4337 if (!v)
4338 return NULL;
4339
4340 dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
4341 if (next_is_param_tuple(s)) {
4342 dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
4343 if (isl_stream_eat(s, ISL_TOKEN_TO))
4344 goto error;
4345 }
4346 space = isl_set_get_space(dom);
4347 isl_set_free(dom);
4348 mupa = read_multi_union_pw_aff_body(s, v, space);
4349
4350 vars_free(v);
4351
4352 return mupa;
4353 error:
4354 vars_free(v);
4355 isl_set_free(dom);
4356 isl_multi_union_pw_aff_free(mupa);
4357 return NULL;
4358 }
4359
4360 /* Read an isl_multi_union_pw_aff from "s".
4361 *
4362 * In particular, handle the special case with shared domain constraints.
4363 * These are specified as
4364 *
4365 * ([...] : ...)
4366 *
4367 * and are especially useful for setting the explicit domain
4368 * of a zero-dimensional isl_multi_union_pw_aff.
4369 * The core isl_multi_union_pw_aff ([...]) is read by
4370 * read_multi_union_pw_aff_core.
4371 */
isl_stream_read_multi_union_pw_aff(__isl_keep isl_stream * s)4372 __isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff(
4373 __isl_keep isl_stream *s)
4374 {
4375 isl_multi_union_pw_aff *mupa;
4376
4377 if (!isl_stream_next_token_is(s, '('))
4378 return read_multi_union_pw_aff_core(s);
4379
4380 if (isl_stream_eat(s, '(') < 0)
4381 return NULL;
4382 mupa = read_multi_union_pw_aff_core(s);
4383 if (isl_stream_eat_if_available(s, ':')) {
4384 isl_union_set *dom;
4385
4386 dom = isl_stream_read_union_set(s);
4387 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);
4388 }
4389 if (isl_stream_eat(s, ')') < 0)
4390 return isl_multi_union_pw_aff_free(mupa);
4391 return mupa;
4392 }
4393
4394 /* Read an isl_multi_union_pw_aff from "str".
4395 */
isl_multi_union_pw_aff_read_from_str(isl_ctx * ctx,const char * str)4396 __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str(
4397 isl_ctx *ctx, const char *str)
4398 {
4399 isl_multi_union_pw_aff *mupa;
4400 isl_stream *s = isl_stream_new_str(ctx, str);
4401 if (!s)
4402 return NULL;
4403 mupa = isl_stream_read_multi_union_pw_aff(s);
4404 isl_stream_free(s);
4405 return mupa;
4406 }
4407
isl_stream_read_union_pw_qpolynomial(__isl_keep isl_stream * s)4408 __isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
4409 __isl_keep isl_stream *s)
4410 {
4411 struct isl_obj obj;
4412
4413 obj = obj_read(s);
4414 if (obj.type == isl_obj_pw_qpolynomial) {
4415 obj.type = isl_obj_union_pw_qpolynomial;
4416 obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
4417 }
4418 if (obj.v)
4419 isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
4420 goto error);
4421
4422 return obj.v;
4423 error:
4424 obj.type->free(obj.v);
4425 return NULL;
4426 }
4427
isl_union_pw_qpolynomial_read_from_str(isl_ctx * ctx,const char * str)4428 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
4429 isl_ctx *ctx, const char *str)
4430 {
4431 isl_union_pw_qpolynomial *upwqp;
4432 isl_stream *s = isl_stream_new_str(ctx, str);
4433 if (!s)
4434 return NULL;
4435 upwqp = isl_stream_read_union_pw_qpolynomial(s);
4436 isl_stream_free(s);
4437 return upwqp;
4438 }
4439