1 /*
2 * Copyright 2010-2011 INRIA Saclay
3 * Copyright 2011 Sven Verdoolaege
4 * Copyright 2012-2014 Ecole Normale Superieure
5 *
6 * Use of this software is governed by the MIT license
7 *
8 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
9 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
10 * 91893 Orsay, France
11 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
12 */
13
14 #include <isl/id.h>
15 #include <isl/aff.h>
16 #include <isl_sort.h>
17 #include <isl_val_private.h>
18
19 #include <isl_pw_macro.h>
20
21 #include "opt_type.h"
22
FN(PW,alloc_size)23 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *space
24 OPT_TYPE_PARAM, int n)
25 {
26 isl_ctx *ctx;
27 struct PW *pw;
28
29 if (!space)
30 return NULL;
31 ctx = isl_space_get_ctx(space);
32 isl_assert(ctx, n >= 0, goto error);
33 pw = isl_alloc(ctx, struct PW,
34 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
35 if (!pw)
36 goto error;
37
38 pw->ref = 1;
39 OPT_SET_TYPE(pw->, type);
40 pw->size = n;
41 pw->n = 0;
42 pw->dim = space;
43 return pw;
44 error:
45 isl_space_free(space);
46 return NULL;
47 }
48
FN(PW,ZERO)49 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *space OPT_TYPE_PARAM)
50 {
51 return FN(PW,alloc_size)(space OPT_TYPE_ARG(NO_LOC), 0);
52 }
53
FN(PW,add_piece)54 __isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
55 __isl_take isl_set *set, __isl_take EL *el)
56 {
57 isl_ctx *ctx;
58 isl_space *el_dim = NULL;
59
60 if (!pw || !set || !el)
61 goto error;
62
63 if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
64 isl_set_free(set);
65 FN(EL,free)(el);
66 return pw;
67 }
68
69 ctx = isl_set_get_ctx(set);
70 if (!OPT_EQUAL_TYPES(pw->, el->))
71 isl_die(ctx, isl_error_invalid, "fold types don't match",
72 goto error);
73 el_dim = FN(EL,get_space(el));
74 isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
75 isl_assert(ctx, pw->n < pw->size, goto error);
76
77 pw->p[pw->n].set = set;
78 pw->p[pw->n].FIELD = el;
79 pw->n++;
80
81 isl_space_free(el_dim);
82 return pw;
83 error:
84 isl_space_free(el_dim);
85 FN(PW,free)(pw);
86 isl_set_free(set);
87 FN(EL,free)(el);
88 return NULL;
89 }
90
91 /* Does the space of "set" correspond to that of the domain of "el".
92 */
FN(PW,compatible_domain)93 static isl_bool FN(PW,compatible_domain)(__isl_keep EL *el,
94 __isl_keep isl_set *set)
95 {
96 isl_bool ok;
97 isl_space *el_space, *set_space;
98
99 if (!set || !el)
100 return isl_bool_error;
101 set_space = isl_set_get_space(set);
102 el_space = FN(EL,get_space)(el);
103 ok = isl_space_is_domain_internal(set_space, el_space);
104 isl_space_free(el_space);
105 isl_space_free(set_space);
106 return ok;
107 }
108
109 /* Check that the space of "set" corresponds to that of the domain of "el".
110 */
FN(PW,check_compatible_domain)111 static isl_stat FN(PW,check_compatible_domain)(__isl_keep EL *el,
112 __isl_keep isl_set *set)
113 {
114 isl_bool ok;
115
116 ok = FN(PW,compatible_domain)(el, set);
117 if (ok < 0)
118 return isl_stat_error;
119 if (!ok)
120 isl_die(isl_set_get_ctx(set), isl_error_invalid,
121 "incompatible spaces", return isl_stat_error);
122
123 return isl_stat_ok;
124 }
125
FN(PW,alloc)126 __isl_give PW *FN(PW,alloc)(OPT_TYPE_PARAM_FIRST
127 __isl_take isl_set *set, __isl_take EL *el)
128 {
129 PW *pw;
130
131 if (FN(PW,check_compatible_domain)(el, set) < 0)
132 goto error;
133
134 pw = FN(PW,alloc_size)(FN(EL,get_space)(el) OPT_TYPE_ARG(NO_LOC), 1);
135
136 return FN(PW,add_piece)(pw, set, el);
137 error:
138 isl_set_free(set);
139 FN(EL,free)(el);
140 return NULL;
141 }
142
FN(PW,dup)143 __isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
144 {
145 int i;
146 PW *dup;
147
148 if (!pw)
149 return NULL;
150
151 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim)
152 OPT_TYPE_ARG(pw->), pw->n);
153 if (!dup)
154 return NULL;
155
156 for (i = 0; i < pw->n; ++i)
157 dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
158 FN(EL,copy)(pw->p[i].FIELD));
159
160 return dup;
161 }
162
FN(PW,cow)163 __isl_give PW *FN(PW,cow)(__isl_take PW *pw)
164 {
165 if (!pw)
166 return NULL;
167
168 if (pw->ref == 1)
169 return pw;
170 pw->ref--;
171 return FN(PW,dup)(pw);
172 }
173
FN(PW,copy)174 __isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
175 {
176 if (!pw)
177 return NULL;
178
179 pw->ref++;
180 return pw;
181 }
182
FN(PW,free)183 __isl_null PW *FN(PW,free)(__isl_take PW *pw)
184 {
185 int i;
186
187 if (!pw)
188 return NULL;
189 if (--pw->ref > 0)
190 return NULL;
191
192 for (i = 0; i < pw->n; ++i) {
193 isl_set_free(pw->p[i].set);
194 FN(EL,free)(pw->p[i].FIELD);
195 }
196 isl_space_free(pw->dim);
197 free(pw);
198
199 return NULL;
200 }
201
202 /* Create a piecewise expression with the given base expression on a universe
203 * domain.
204 */
FN(FN (FN (PW,from),BASE),type_base)205 static __isl_give PW *FN(FN(FN(PW,from),BASE),type_base)(__isl_take EL *el
206 OPT_TYPE_PARAM)
207 {
208 isl_set *dom = isl_set_universe(FN(EL,get_domain_space)(el));
209 return FN(PW,alloc)(OPT_TYPE_ARG_FIRST(NO_LOC) dom, el);
210 }
211
212 /* Create a piecewise expression with the given base expression on a universe
213 * domain.
214 *
215 * If the default value of this piecewise type is zero and
216 * if "el" is effectively zero, then create an empty piecewise expression
217 * instead.
218 */
FN(FN (FN (PW,from),BASE),type)219 static __isl_give PW *FN(FN(FN(PW,from),BASE),type)(__isl_take EL *el
220 OPT_TYPE_PARAM)
221 {
222 isl_bool is_zero;
223 isl_space *space;
224
225 if (!DEFAULT_IS_ZERO)
226 return FN(FN(FN(PW,from),BASE),type_base)(el
227 OPT_TYPE_ARG(NO_LOC));
228 is_zero = FN(EL,EL_IS_ZERO)(el);
229 if (is_zero < 0)
230 goto error;
231 if (!is_zero)
232 return FN(FN(FN(PW,from),BASE),type_base)(el
233 OPT_TYPE_ARG(NO_LOC));
234 space = FN(EL,get_space)(el);
235 FN(EL,free)(el);
236 return FN(PW,ZERO)(space OPT_TYPE_ARG(NO_LOC));
237 error:
238 FN(EL,free)(el);
239 return NULL;
240 }
241
242 #ifdef HAS_TYPE
243 /* Create a piecewise expression with the given base expression on a universe
244 * domain.
245 *
246 * Pass along the type as an extra argument for improved uniformity
247 * with piecewise types that do not have a fold type.
248 */
FN(FN (PW,from),BASE)249 __isl_give PW *FN(FN(PW,from),BASE)(__isl_take EL *el)
250 {
251 enum isl_fold type = FN(EL,get_type)(el);
252 return FN(FN(FN(PW,from),BASE),type)(el, type);
253 }
254 #else
FN(FN (PW,from),BASE)255 __isl_give PW *FN(FN(PW,from),BASE)(__isl_take EL *el)
256 {
257 return FN(FN(FN(PW,from),BASE),type)(el);
258 }
259 #endif
260
FN(PW,get_dim_name)261 const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
262 unsigned pos)
263 {
264 return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
265 }
266
FN(PW,has_dim_id)267 isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
268 unsigned pos)
269 {
270 return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
271 }
272
FN(PW,get_dim_id)273 __isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
274 unsigned pos)
275 {
276 return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
277 }
278
FN(PW,has_tuple_name)279 isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
280 {
281 return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
282 }
283
FN(PW,get_tuple_name)284 const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
285 {
286 return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
287 }
288
FN(PW,has_tuple_id)289 isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
290 {
291 return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
292 }
293
FN(PW,get_tuple_id)294 __isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
295 {
296 return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
297 }
298
FN(PW,IS_ZERO)299 isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
300 {
301 if (!pw)
302 return isl_bool_error;
303
304 return isl_bool_ok(pw->n == 0);
305 }
306
FN(PW,realign_domain)307 __isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
308 __isl_take isl_reordering *exp)
309 {
310 int i;
311
312 pw = FN(PW,cow)(pw);
313 if (!pw || !exp)
314 goto error;
315
316 for (i = 0; i < pw->n; ++i) {
317 pw->p[i].set = isl_set_realign(pw->p[i].set,
318 isl_reordering_copy(exp));
319 if (!pw->p[i].set)
320 goto error;
321 pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
322 isl_reordering_copy(exp));
323 if (!pw->p[i].FIELD)
324 goto error;
325 }
326
327 pw = FN(PW,reset_domain_space)(pw, isl_reordering_get_space(exp));
328
329 isl_reordering_free(exp);
330 return pw;
331 error:
332 isl_reordering_free(exp);
333 FN(PW,free)(pw);
334 return NULL;
335 }
336
337 #undef TYPE
338 #define TYPE PW
339
340 #include "isl_check_named_params_templ.c"
341
342 /* Align the parameters of "pw" to those of "model".
343 */
FN(PW,align_params)344 __isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
345 {
346 isl_ctx *ctx;
347 isl_bool equal_params;
348
349 if (!pw || !model)
350 goto error;
351
352 ctx = isl_space_get_ctx(model);
353 if (!isl_space_has_named_params(model))
354 isl_die(ctx, isl_error_invalid,
355 "model has unnamed parameters", goto error);
356 if (FN(PW,check_named_params)(pw) < 0)
357 goto error;
358 equal_params = isl_space_has_equal_params(pw->dim, model);
359 if (equal_params < 0)
360 goto error;
361 if (!equal_params) {
362 isl_reordering *exp;
363
364 exp = isl_parameter_alignment_reordering(pw->dim, model);
365 exp = isl_reordering_extend_space(exp,
366 FN(PW,get_domain_space)(pw));
367 pw = FN(PW,realign_domain)(pw, exp);
368 }
369
370 isl_space_free(model);
371 return pw;
372 error:
373 isl_space_free(model);
374 FN(PW,free)(pw);
375 return NULL;
376 }
377
378 #undef TYPE
379 #define TYPE PW
380
381 static
382 #include "isl_align_params_bin_templ.c"
383
384 #undef SUFFIX
385 #define SUFFIX set
386 #undef ARG1
387 #define ARG1 PW
388 #undef ARG2
389 #define ARG2 isl_set
390
391 static
392 #include "isl_align_params_templ.c"
393
394 #undef TYPE
395 #define TYPE PW
396
397 #include "isl_type_has_equal_space_bin_templ.c"
398 #include "isl_type_check_equal_space_templ.c"
399
400 /* Private version of "union_add". For isl_pw_qpolynomial and
401 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
402 */
FN(PW,union_add_)403 static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
404 {
405 int i, j, n;
406 struct PW *res;
407 isl_ctx *ctx;
408 isl_set *set;
409
410 if (FN(PW,align_params_bin)(&pw1, &pw2) < 0)
411 goto error;
412
413 ctx = isl_space_get_ctx(pw1->dim);
414 if (!OPT_EQUAL_TYPES(pw1->, pw2->))
415 isl_die(ctx, isl_error_invalid,
416 "fold types don't match", goto error);
417 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
418 goto error;
419
420 if (FN(PW,IS_ZERO)(pw1)) {
421 FN(PW,free)(pw1);
422 return pw2;
423 }
424
425 if (FN(PW,IS_ZERO)(pw2)) {
426 FN(PW,free)(pw2);
427 return pw1;
428 }
429
430 n = (pw1->n + 1) * (pw2->n + 1);
431 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim)
432 OPT_TYPE_ARG(pw1->), n);
433
434 for (i = 0; i < pw1->n; ++i) {
435 set = isl_set_copy(pw1->p[i].set);
436 for (j = 0; j < pw2->n; ++j) {
437 struct isl_set *common;
438 EL *sum;
439 common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
440 isl_set_copy(pw2->p[j].set));
441 if (isl_set_plain_is_empty(common)) {
442 isl_set_free(common);
443 continue;
444 }
445 set = isl_set_subtract(set,
446 isl_set_copy(pw2->p[j].set));
447
448 sum = FN(EL,add_on_domain)(common,
449 FN(EL,copy)(pw1->p[i].FIELD),
450 FN(EL,copy)(pw2->p[j].FIELD));
451
452 res = FN(PW,add_piece)(res, common, sum);
453 }
454 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
455 }
456
457 for (j = 0; j < pw2->n; ++j) {
458 set = isl_set_copy(pw2->p[j].set);
459 for (i = 0; i < pw1->n; ++i)
460 set = isl_set_subtract(set,
461 isl_set_copy(pw1->p[i].set));
462 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
463 }
464
465 FN(PW,free)(pw1);
466 FN(PW,free)(pw2);
467
468 return res;
469 error:
470 FN(PW,free)(pw1);
471 FN(PW,free)(pw2);
472 return NULL;
473 }
474
475 /* Make sure "pw" has room for at least "n" more pieces.
476 *
477 * If there is only one reference to pw, we extend it in place.
478 * Otherwise, we create a new PW and copy the pieces.
479 */
FN(PW,grow)480 static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
481 {
482 int i;
483 isl_ctx *ctx;
484 PW *res;
485
486 if (!pw)
487 return NULL;
488 if (pw->n + n <= pw->size)
489 return pw;
490 ctx = FN(PW,get_ctx)(pw);
491 n += pw->n;
492 if (pw->ref == 1) {
493 res = isl_realloc(ctx, pw, struct PW,
494 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
495 if (!res)
496 return FN(PW,free)(pw);
497 res->size = n;
498 return res;
499 }
500 res = FN(PW,alloc_size)(isl_space_copy(pw->dim) OPT_TYPE_ARG(pw->), n);
501 if (!res)
502 return FN(PW,free)(pw);
503 for (i = 0; i < pw->n; ++i)
504 res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
505 FN(EL,copy)(pw->p[i].FIELD));
506 FN(PW,free)(pw);
507 return res;
508 }
509
FN(PW,add_disjoint)510 __isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
511 {
512 int i;
513 isl_ctx *ctx;
514
515 if (FN(PW,align_params_bin)(&pw1, &pw2) < 0)
516 goto error;
517
518 if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
519 return FN(PW,add_disjoint)(pw2, pw1);
520
521 ctx = isl_space_get_ctx(pw1->dim);
522 if (!OPT_EQUAL_TYPES(pw1->, pw2->))
523 isl_die(ctx, isl_error_invalid,
524 "fold types don't match", goto error);
525 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
526 goto error;
527
528 if (FN(PW,IS_ZERO)(pw1)) {
529 FN(PW,free)(pw1);
530 return pw2;
531 }
532
533 if (FN(PW,IS_ZERO)(pw2)) {
534 FN(PW,free)(pw2);
535 return pw1;
536 }
537
538 pw1 = FN(PW,grow)(pw1, pw2->n);
539 if (!pw1)
540 goto error;
541
542 for (i = 0; i < pw2->n; ++i)
543 pw1 = FN(PW,add_piece)(pw1,
544 isl_set_copy(pw2->p[i].set),
545 FN(EL,copy)(pw2->p[i].FIELD));
546
547 FN(PW,free)(pw2);
548
549 return pw1;
550 error:
551 FN(PW,free)(pw1);
552 FN(PW,free)(pw2);
553 return NULL;
554 }
555
556 /* This function is currently only used from isl_aff.c
557 */
558 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
559 __isl_take PW *pw2, __isl_take isl_space *space,
560 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
561 __attribute__ ((unused));
562
563 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
564 * The result of "fn" (and therefore also of this function) lives in "space".
565 */
FN(PW,on_shared_domain_in)566 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
567 __isl_take PW *pw2, __isl_take isl_space *space,
568 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
569 {
570 int i, j, n;
571 PW *res = NULL;
572
573 if (!pw1 || !pw2)
574 goto error;
575
576 n = pw1->n * pw2->n;
577 res = FN(PW,alloc_size)(isl_space_copy(space) OPT_TYPE_ARG(pw1->), n);
578
579 for (i = 0; i < pw1->n; ++i) {
580 for (j = 0; j < pw2->n; ++j) {
581 isl_set *common;
582 EL *res_ij;
583 int empty;
584
585 common = isl_set_intersect(
586 isl_set_copy(pw1->p[i].set),
587 isl_set_copy(pw2->p[j].set));
588 empty = isl_set_plain_is_empty(common);
589 if (empty < 0 || empty) {
590 isl_set_free(common);
591 if (empty < 0)
592 goto error;
593 continue;
594 }
595
596 res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
597 FN(EL,copy)(pw2->p[j].FIELD));
598 res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
599
600 res = FN(PW,add_piece)(res, common, res_ij);
601 }
602 }
603
604 isl_space_free(space);
605 FN(PW,free)(pw1);
606 FN(PW,free)(pw2);
607 return res;
608 error:
609 isl_space_free(space);
610 FN(PW,free)(pw1);
611 FN(PW,free)(pw2);
612 FN(PW,free)(res);
613 return NULL;
614 }
615
616 /* This function is currently only used from isl_aff.c
617 */
618 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
619 __isl_take PW *pw2,
620 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
621 __attribute__ ((unused));
622
623 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
624 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
625 */
FN(PW,on_shared_domain)626 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
627 __isl_take PW *pw2,
628 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
629 {
630 isl_space *space;
631
632 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
633 goto error;
634
635 space = isl_space_copy(pw1->dim);
636 return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
637 error:
638 FN(PW,free)(pw1);
639 FN(PW,free)(pw2);
640 return NULL;
641 }
642
643 /* Return the parameter domain of "pw".
644 */
FN(PW,params)645 __isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
646 {
647 return isl_set_params(FN(PW,domain)(pw));
648 }
649
FN(PW,domain)650 __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
651 {
652 int i;
653 isl_set *dom;
654
655 if (!pw)
656 return NULL;
657
658 dom = isl_set_empty(FN(PW,get_domain_space)(pw));
659 for (i = 0; i < pw->n; ++i)
660 dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
661
662 FN(PW,free)(pw);
663
664 return dom;
665 }
666
667 /* Exploit the equalities in the domain of piece "i" of "pw"
668 * to simplify the associated function.
669 * If the domain of piece "i" is empty, then remove it entirely,
670 * replacing it with the final piece.
671 */
FN(PW,exploit_equalities_and_remove_if_empty)672 static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
673 int i)
674 {
675 isl_basic_set *aff;
676 int empty = isl_set_plain_is_empty(pw->p[i].set);
677
678 if (empty < 0)
679 return -1;
680 if (empty) {
681 isl_set_free(pw->p[i].set);
682 FN(EL,free)(pw->p[i].FIELD);
683 if (i != pw->n - 1)
684 pw->p[i] = pw->p[pw->n - 1];
685 pw->n--;
686
687 return 0;
688 }
689
690 aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
691 pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
692 if (!pw->p[i].FIELD)
693 return -1;
694
695 return 0;
696 }
697
698 /* Convert a piecewise expression defined over a parameter domain
699 * into one that is defined over a zero-dimensional set.
700 */
FN(PW,from_range)701 __isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
702 {
703 isl_space *space;
704
705 if (!pw)
706 return NULL;
707 if (!isl_space_is_set(pw->dim))
708 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
709 "not living in a set space", return FN(PW,free)(pw));
710
711 space = FN(PW,get_space)(pw);
712 space = isl_space_from_range(space);
713 pw = FN(PW,reset_space)(pw, space);
714
715 return pw;
716 }
717
718 /* Fix the value of the given parameter or domain dimension of "pw"
719 * to be equal to "value".
720 */
FN(PW,fix_si)721 __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
722 unsigned pos, int value)
723 {
724 int i;
725
726 if (!pw)
727 return NULL;
728
729 if (type == isl_dim_out)
730 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
731 "cannot fix output dimension", return FN(PW,free)(pw));
732
733 if (pw->n == 0)
734 return pw;
735
736 if (type == isl_dim_in)
737 type = isl_dim_set;
738
739 pw = FN(PW,cow)(pw);
740 if (!pw)
741 return FN(PW,free)(pw);
742
743 for (i = pw->n - 1; i >= 0; --i) {
744 pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
745 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
746 return FN(PW,free)(pw);
747 }
748
749 return pw;
750 }
751
752 /* Restrict the domain of "pw" by combining each cell
753 * with "set" through a call to "fn", where "fn" may be
754 * isl_set_intersect, isl_set_intersect_params, isl_set_intersect_factor_domain,
755 * isl_set_intersect_factor_range or isl_set_subtract.
756 */
FN(PW,restrict_domain_aligned)757 static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
758 __isl_take isl_set *set,
759 __isl_give isl_set *(*fn)(__isl_take isl_set *set1,
760 __isl_take isl_set *set2))
761 {
762 int i;
763
764 if (!pw || !set)
765 goto error;
766
767 if (pw->n == 0) {
768 isl_set_free(set);
769 return pw;
770 }
771
772 pw = FN(PW,cow)(pw);
773 if (!pw)
774 goto error;
775
776 for (i = pw->n - 1; i >= 0; --i) {
777 pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
778 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
779 goto error;
780 }
781
782 isl_set_free(set);
783 return pw;
784 error:
785 isl_set_free(set);
786 FN(PW,free)(pw);
787 return NULL;
788 }
789
FN(PW,intersect_domain)790 __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
791 __isl_take isl_set *context)
792 {
793 FN(PW,align_params_set)(&pw, &context);
794 return FN(PW,restrict_domain_aligned)(pw, context, &isl_set_intersect);
795 }
796
797 /* Intersect the domain of "pw" with the parameter domain "context".
798 */
FN(PW,intersect_params)799 __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
800 __isl_take isl_set *context)
801 {
802 FN(PW,align_params_set)(&pw, &context);
803 return FN(PW,restrict_domain_aligned)(pw, context,
804 &isl_set_intersect_params);
805 }
806
807 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
808 * a set in the space A, intersect the domain with the set.
809 */
FN(PW,intersect_domain_wrapped_domain)810 __isl_give PW *FN(PW,intersect_domain_wrapped_domain)(__isl_take PW *pw,
811 __isl_take isl_set *set)
812 {
813 FN(PW,align_params_set)(&pw, &set);
814 return FN(PW,restrict_domain_aligned)(pw, set,
815 &isl_set_intersect_factor_domain);
816 }
817
818 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
819 * a set in the space B, intersect the domain with the set.
820 */
FN(PW,intersect_domain_wrapped_range)821 __isl_give PW *FN(PW,intersect_domain_wrapped_range)(__isl_take PW *pw,
822 __isl_take isl_set *set)
823 {
824 FN(PW,align_params_set)(&pw, &set);
825 return FN(PW,restrict_domain_aligned)(pw, set,
826 &isl_set_intersect_factor_range);
827 }
828
829 /* Subtract "domain' from the domain of "pw".
830 */
FN(PW,subtract_domain)831 __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
832 __isl_take isl_set *domain)
833 {
834 FN(PW,align_params_set)(&pw, &domain);
835 return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
836 }
837
838 /* Compute the gist of "pw" with respect to the domain constraints
839 * of "context" for the case where the domain of the last element
840 * of "pw" is equal to "context".
841 * Call "fn_el" to compute the gist of this element, replace
842 * its domain by the universe and drop all other elements
843 * as their domains are necessarily disjoint from "context".
844 */
FN(PW,gist_last)845 static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
846 __isl_take isl_set *context,
847 __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
848 {
849 int i;
850 isl_space *space;
851
852 for (i = 0; i < pw->n - 1; ++i) {
853 isl_set_free(pw->p[i].set);
854 FN(EL,free)(pw->p[i].FIELD);
855 }
856 pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
857 pw->p[0].set = pw->p[pw->n - 1].set;
858 pw->n = 1;
859
860 space = isl_set_get_space(context);
861 pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
862 context = isl_set_universe(space);
863 isl_set_free(pw->p[0].set);
864 pw->p[0].set = context;
865
866 if (!pw->p[0].FIELD || !pw->p[0].set)
867 return FN(PW,free)(pw);
868
869 return pw;
870 }
871
872 /* Compute the gist of "pw" with respect to the domain constraints
873 * of "context". Call "fn_el" to compute the gist of the elements
874 * and "fn_dom" to compute the gist of the domains.
875 *
876 * If the piecewise expression is empty or the context is the universe,
877 * then nothing can be simplified.
878 */
FN(PW,gist_aligned)879 static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
880 __isl_take isl_set *context,
881 __isl_give EL *(*fn_el)(__isl_take EL *el,
882 __isl_take isl_set *set),
883 __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
884 __isl_take isl_basic_set *bset))
885 {
886 int i;
887 int is_universe;
888 isl_bool aligned;
889 isl_basic_set *hull = NULL;
890
891 if (!pw || !context)
892 goto error;
893
894 if (pw->n == 0) {
895 isl_set_free(context);
896 return pw;
897 }
898
899 is_universe = isl_set_plain_is_universe(context);
900 if (is_universe < 0)
901 goto error;
902 if (is_universe) {
903 isl_set_free(context);
904 return pw;
905 }
906
907 aligned = isl_set_space_has_equal_params(context, pw->dim);
908 if (aligned < 0)
909 goto error;
910 if (!aligned) {
911 pw = FN(PW,align_params)(pw, isl_set_get_space(context));
912 context = isl_set_align_params(context, FN(PW,get_space)(pw));
913 }
914
915 pw = FN(PW,cow)(pw);
916 if (!pw)
917 goto error;
918
919 if (pw->n == 1) {
920 int equal;
921
922 equal = isl_set_plain_is_equal(pw->p[0].set, context);
923 if (equal < 0)
924 goto error;
925 if (equal)
926 return FN(PW,gist_last)(pw, context, fn_el);
927 }
928
929 context = isl_set_compute_divs(context);
930 hull = isl_set_simple_hull(isl_set_copy(context));
931
932 for (i = pw->n - 1; i >= 0; --i) {
933 isl_set *set_i;
934 int empty;
935
936 if (i == pw->n - 1) {
937 int equal;
938 equal = isl_set_plain_is_equal(pw->p[i].set, context);
939 if (equal < 0)
940 goto error;
941 if (equal) {
942 isl_basic_set_free(hull);
943 return FN(PW,gist_last)(pw, context, fn_el);
944 }
945 }
946 set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
947 isl_set_copy(context));
948 empty = isl_set_plain_is_empty(set_i);
949 pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
950 pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
951 if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
952 goto error;
953 if (empty) {
954 isl_set_free(pw->p[i].set);
955 FN(EL,free)(pw->p[i].FIELD);
956 if (i != pw->n - 1)
957 pw->p[i] = pw->p[pw->n - 1];
958 pw->n--;
959 }
960 }
961
962 isl_basic_set_free(hull);
963 isl_set_free(context);
964
965 return pw;
966 error:
967 FN(PW,free)(pw);
968 isl_basic_set_free(hull);
969 isl_set_free(context);
970 return NULL;
971 }
972
FN(PW,gist)973 __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
974 {
975 FN(PW,align_params_set)(&pw, &context);
976 return FN(PW,gist_aligned)(pw, context, &FN(EL,gist),
977 &isl_set_gist_basic_set);
978 }
979
FN(PW,gist_params)980 __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
981 __isl_take isl_set *context)
982 {
983 FN(PW,align_params_set)(&pw, &context);
984 return FN(PW,gist_aligned)(pw, context, &FN(EL,gist_params),
985 &isl_set_gist_params_basic_set);
986 }
987
988 /* Return -1 if the piece "p1" should be sorted before "p2"
989 * and 1 if it should be sorted after "p2".
990 * Return 0 if they do not need to be sorted in a specific order.
991 *
992 * The two pieces are compared on the basis of their function value expressions.
993 */
FN(PW,sort_field_cmp)994 static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
995 {
996 struct FN(PW,piece) const *pc1 = p1;
997 struct FN(PW,piece) const *pc2 = p2;
998
999 return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
1000 }
1001
1002 /* Sort the pieces of "pw" according to their function value
1003 * expressions and then combine pairs of adjacent pieces with
1004 * the same such expression.
1005 *
1006 * The sorting is performed in place because it does not
1007 * change the meaning of "pw", but care needs to be
1008 * taken not to change any possible other copies of "pw"
1009 * in case anything goes wrong.
1010 */
FN(PW,sort)1011 __isl_give PW *FN(PW,sort)(__isl_take PW *pw)
1012 {
1013 int i, j;
1014 isl_set *set;
1015
1016 if (!pw)
1017 return NULL;
1018 if (pw->n <= 1)
1019 return pw;
1020 if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
1021 &FN(PW,sort_field_cmp), NULL) < 0)
1022 return FN(PW,free)(pw);
1023 for (i = pw->n - 1; i >= 1; --i) {
1024 if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
1025 continue;
1026 set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
1027 isl_set_copy(pw->p[i].set));
1028 if (!set)
1029 return FN(PW,free)(pw);
1030 isl_set_free(pw->p[i].set);
1031 FN(EL,free)(pw->p[i].FIELD);
1032 isl_set_free(pw->p[i - 1].set);
1033 pw->p[i - 1].set = set;
1034 for (j = i + 1; j < pw->n; ++j)
1035 pw->p[j - 1] = pw->p[j];
1036 pw->n--;
1037 }
1038
1039 return pw;
1040 }
1041
1042 /* Coalesce the domains of "pw".
1043 *
1044 * Prior to the actual coalescing, first sort the pieces such that
1045 * pieces with the same function value expression are combined
1046 * into a single piece, the combined domain of which can then
1047 * be coalesced.
1048 */
FN(PW,coalesce)1049 __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
1050 {
1051 int i;
1052
1053 pw = FN(PW,sort)(pw);
1054 if (!pw)
1055 return NULL;
1056
1057 for (i = 0; i < pw->n; ++i) {
1058 pw->p[i].set = isl_set_coalesce(pw->p[i].set);
1059 if (!pw->p[i].set)
1060 goto error;
1061 }
1062
1063 return pw;
1064 error:
1065 FN(PW,free)(pw);
1066 return NULL;
1067 }
1068
FN(PW,get_ctx)1069 isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
1070 {
1071 return pw ? isl_space_get_ctx(pw->dim) : NULL;
1072 }
1073
FN(PW,involves_dims)1074 isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
1075 unsigned first, unsigned n)
1076 {
1077 int i;
1078 enum isl_dim_type set_type;
1079
1080 if (!pw)
1081 return isl_bool_error;
1082 if (pw->n == 0 || n == 0)
1083 return isl_bool_false;
1084
1085 set_type = type == isl_dim_in ? isl_dim_set : type;
1086
1087 for (i = 0; i < pw->n; ++i) {
1088 isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
1089 type, first, n);
1090 if (involves < 0 || involves)
1091 return involves;
1092 involves = isl_set_involves_dims(pw->p[i].set,
1093 set_type, first, n);
1094 if (involves < 0 || involves)
1095 return involves;
1096 }
1097 return isl_bool_false;
1098 }
1099
FN(PW,set_dim_name)1100 __isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
1101 enum isl_dim_type type, unsigned pos, const char *s)
1102 {
1103 int i;
1104 enum isl_dim_type set_type;
1105
1106 pw = FN(PW,cow)(pw);
1107 if (!pw)
1108 return NULL;
1109
1110 set_type = type == isl_dim_in ? isl_dim_set : type;
1111
1112 pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
1113 if (!pw->dim)
1114 goto error;
1115
1116 for (i = 0; i < pw->n; ++i) {
1117 pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
1118 set_type, pos, s);
1119 if (!pw->p[i].set)
1120 goto error;
1121 pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
1122 if (!pw->p[i].FIELD)
1123 goto error;
1124 }
1125
1126 return pw;
1127 error:
1128 FN(PW,free)(pw);
1129 return NULL;
1130 }
1131
FN(PW,drop_dims)1132 __isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
1133 enum isl_dim_type type, unsigned first, unsigned n)
1134 {
1135 int i;
1136 enum isl_dim_type set_type;
1137
1138 if (!pw)
1139 return NULL;
1140 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1141 return pw;
1142
1143 set_type = type == isl_dim_in ? isl_dim_set : type;
1144
1145 pw = FN(PW,cow)(pw);
1146 if (!pw)
1147 return NULL;
1148 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1149 if (!pw->dim)
1150 goto error;
1151 for (i = 0; i < pw->n; ++i) {
1152 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1153 if (!pw->p[i].FIELD)
1154 goto error;
1155 if (type == isl_dim_out)
1156 continue;
1157 pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
1158 if (!pw->p[i].set)
1159 goto error;
1160 }
1161
1162 return pw;
1163 error:
1164 FN(PW,free)(pw);
1165 return NULL;
1166 }
1167
1168 /* This function is very similar to drop_dims.
1169 * The only difference is that the cells may still involve
1170 * the specified dimensions. They are removed using
1171 * isl_set_project_out instead of isl_set_drop.
1172 */
FN(PW,project_out)1173 __isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
1174 enum isl_dim_type type, unsigned first, unsigned n)
1175 {
1176 int i;
1177 enum isl_dim_type set_type;
1178
1179 if (!pw)
1180 return NULL;
1181 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1182 return pw;
1183
1184 set_type = type == isl_dim_in ? isl_dim_set : type;
1185
1186 pw = FN(PW,cow)(pw);
1187 if (!pw)
1188 return NULL;
1189 pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
1190 if (!pw->dim)
1191 goto error;
1192 for (i = 0; i < pw->n; ++i) {
1193 pw->p[i].set = isl_set_project_out(pw->p[i].set,
1194 set_type, first, n);
1195 if (!pw->p[i].set)
1196 goto error;
1197 pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
1198 if (!pw->p[i].FIELD)
1199 goto error;
1200 }
1201
1202 return pw;
1203 error:
1204 FN(PW,free)(pw);
1205 return NULL;
1206 }
1207
1208 /* Project the domain of pw onto its parameter space.
1209 */
FN(PW,project_domain_on_params)1210 __isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
1211 {
1212 isl_space *space;
1213 isl_size n;
1214
1215 n = FN(PW,dim)(pw, isl_dim_in);
1216 if (n < 0)
1217 return FN(PW,free)(pw);
1218 pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
1219 space = FN(PW,get_domain_space)(pw);
1220 space = isl_space_params(space);
1221 pw = FN(PW,reset_domain_space)(pw, space);
1222 return pw;
1223 }
1224
1225 /* Drop all parameters not referenced by "pw".
1226 */
FN(PW,drop_unused_params)1227 __isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw)
1228 {
1229 isl_size n;
1230 int i;
1231
1232 if (FN(PW,check_named_params)(pw) < 0)
1233 return FN(PW,free)(pw);
1234
1235 n = FN(PW,dim)(pw, isl_dim_param);
1236 if (n < 0)
1237 return FN(PW,free)(pw);
1238 for (i = n - 1; i >= 0; i--) {
1239 isl_bool involves;
1240
1241 involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1);
1242 if (involves < 0)
1243 return FN(PW,free)(pw);
1244 if (!involves)
1245 pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1);
1246 }
1247
1248 return pw;
1249 }
1250
FN(PW,fix_dim)1251 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1252 enum isl_dim_type type, unsigned pos, isl_int v)
1253 {
1254 int i;
1255
1256 if (!pw)
1257 return NULL;
1258
1259 if (type == isl_dim_in)
1260 type = isl_dim_set;
1261
1262 pw = FN(PW,cow)(pw);
1263 if (!pw)
1264 return NULL;
1265 for (i = 0; i < pw->n; ++i) {
1266 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1267 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1268 return FN(PW,free)(pw);
1269 }
1270
1271 return pw;
1272 }
1273
1274 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1275 * to be equal to "v".
1276 */
FN(PW,fix_val)1277 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1278 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1279 {
1280 if (!v)
1281 return FN(PW,free)(pw);
1282 if (!isl_val_is_int(v))
1283 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1284 "expecting integer value", goto error);
1285
1286 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1287 isl_val_free(v);
1288
1289 return pw;
1290 error:
1291 isl_val_free(v);
1292 return FN(PW,free)(pw);
1293 }
1294
FN(PW,dim)1295 isl_size FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1296 {
1297 return isl_space_dim(FN(PW,peek_space)(pw), type);
1298 }
1299
FN(PW,split_dims)1300 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1301 enum isl_dim_type type, unsigned first, unsigned n)
1302 {
1303 int i;
1304
1305 if (!pw)
1306 return NULL;
1307 if (n == 0)
1308 return pw;
1309
1310 if (type == isl_dim_in)
1311 type = isl_dim_set;
1312
1313 pw = FN(PW,cow)(pw);
1314 if (!pw)
1315 return NULL;
1316 if (!pw->dim)
1317 goto error;
1318 for (i = 0; i < pw->n; ++i) {
1319 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1320 if (!pw->p[i].set)
1321 goto error;
1322 }
1323
1324 return pw;
1325 error:
1326 FN(PW,free)(pw);
1327 return NULL;
1328 }
1329
1330 /* Return the space of "pw".
1331 */
FN(PW,peek_space)1332 __isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
1333 {
1334 return pw ? pw->dim : NULL;
1335 }
1336
FN(PW,get_space)1337 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
1338 {
1339 return isl_space_copy(FN(PW,peek_space)(pw));
1340 }
1341
1342 /* Return the space of "pw".
1343 * This may be either a copy or the space itself
1344 * if there is only one reference to "pw".
1345 * This allows the space to be modified inplace
1346 * if both the piecewise expression and its space have only a single reference.
1347 * The caller is not allowed to modify "pw" between this call and
1348 * a subsequent call to isl_pw_*_restore_*.
1349 * The only exception is that isl_pw_*_free can be called instead.
1350 */
FN(PW,take_space)1351 __isl_give isl_space *FN(PW,take_space)(__isl_keep PW *pw)
1352 {
1353 isl_space *space;
1354
1355 if (!pw)
1356 return NULL;
1357 if (pw->ref != 1)
1358 return FN(PW,get_space)(pw);
1359 space = pw->dim;
1360 pw->dim = NULL;
1361 return space;
1362 }
1363
1364 /* Set the space of "pw" to "space", where the space of "pw" may be missing
1365 * due to a preceding call to isl_pw_*_take_space.
1366 * However, in this case, "pw" only has a single reference and
1367 * then the call to isl_pw_*_cow has no effect.
1368 */
FN(PW,restore_space)1369 __isl_give PW *FN(PW,restore_space)(__isl_take PW *pw,
1370 __isl_take isl_space *space)
1371 {
1372 if (!pw || !space)
1373 goto error;
1374
1375 if (pw->dim == space) {
1376 isl_space_free(space);
1377 return pw;
1378 }
1379
1380 pw = FN(PW,cow)(pw);
1381 if (!pw)
1382 goto error;
1383 isl_space_free(pw->dim);
1384 pw->dim = space;
1385
1386 return pw;
1387 error:
1388 FN(PW,free)(pw);
1389 isl_space_free(space);
1390 return NULL;
1391 }
1392
1393 /* Check that "pos" is a valid position for a cell in "pw".
1394 */
FN(PW,check_pos)1395 static isl_stat FN(PW,check_pos)(__isl_keep PW *pw, int pos)
1396 {
1397 if (!pw)
1398 return isl_stat_error;
1399 if (pos < 0 || pos >= pw->n)
1400 isl_die(FN(PW,get_ctx)(pw), isl_error_internal,
1401 "position out of bounds", return isl_stat_error);
1402 return isl_stat_ok;
1403 }
1404
1405 /* Return the cell at position "pos" in "pw".
1406 */
FN(PW,peek_domain_at)1407 static __isl_keep isl_set *FN(PW,peek_domain_at)(__isl_keep PW *pw, int pos)
1408 {
1409 if (FN(PW,check_pos)(pw, pos) < 0)
1410 return NULL;
1411 return pw->p[pos].set;
1412 }
1413
1414 /* Return a copy of the base expression associated to
1415 * the cell at position "pos" in "pw".
1416 */
FN(PW,get_base_at)1417 __isl_give EL *FN(PW,get_base_at)(__isl_keep PW *pw, int pos)
1418 {
1419 if (FN(PW,check_pos)(pw, pos) < 0)
1420 return NULL;
1421 return FN(EL,copy)(pw->p[pos].FIELD);
1422 }
1423
1424 /* Return the base expression associated to
1425 * the cell at position "pos" in "pw".
1426 * This may be either a copy or the base expression itself
1427 * if there is only one reference to "pw".
1428 * This allows the base expression to be modified inplace
1429 * if both the piecewise expression and this base expression
1430 * have only a single reference.
1431 * The caller is not allowed to modify "pw" between this call and
1432 * a subsequent call to isl_pw_*_restore_*.
1433 * The only exception is that isl_pw_*_free can be called instead.
1434 */
FN(PW,take_base_at)1435 __isl_give EL *FN(PW,take_base_at)(__isl_keep PW *pw, int pos)
1436 {
1437 EL *el;
1438
1439 if (!pw)
1440 return NULL;
1441 if (pw->ref != 1)
1442 return FN(PW,get_base_at)(pw, pos);
1443 if (FN(PW,check_pos)(pw, pos) < 0)
1444 return NULL;
1445 el = pw->p[pos].FIELD;
1446 pw->p[pos].FIELD = NULL;
1447 return el;
1448 }
1449
1450 /* Set the base expression associated to
1451 * the cell at position "pos" in "pw" to "el",
1452 * where this base expression may be missing
1453 * due to a preceding call to isl_pw_*_take_base_at.
1454 * However, in this case, "pw" only has a single reference and
1455 * then the call to isl_pw_*_cow has no effect.
1456 */
FN(PW,restore_base_at)1457 __isl_give PW *FN(PW,restore_base_at)(__isl_take PW *pw, int pos,
1458 __isl_take EL *el)
1459 {
1460 if (FN(PW,check_pos)(pw, pos) < 0 || !el)
1461 goto error;
1462
1463 if (pw->p[pos].FIELD == el) {
1464 FN(EL,free)(el);
1465 return pw;
1466 }
1467
1468 pw = FN(PW,cow)(pw);
1469 if (!pw)
1470 goto error;
1471 FN(EL,free)(pw->p[pos].FIELD);
1472 pw->p[pos].FIELD = el;
1473
1474 return pw;
1475 error:
1476 FN(PW,free)(pw);
1477 FN(EL,free)(el);
1478 return NULL;
1479 }
1480
FN(PW,get_domain_space)1481 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1482 {
1483 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1484 }
1485
1486 /* Return the position of the dimension of the given type and name
1487 * in "pw".
1488 * Return -1 if no such dimension can be found.
1489 */
FN(PW,find_dim_by_name)1490 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1491 enum isl_dim_type type, const char *name)
1492 {
1493 if (!pw)
1494 return -1;
1495 return isl_space_find_dim_by_name(pw->dim, type, name);
1496 }
1497
1498 /* Return the position of the dimension of the given type and identifier
1499 * in "pw".
1500 * Return -1 if no such dimension can be found.
1501 */
FN(PW,find_dim_by_id)1502 static int FN(PW,find_dim_by_id)(__isl_keep PW *pw,
1503 enum isl_dim_type type, __isl_keep isl_id *id)
1504 {
1505 isl_space *space;
1506
1507 space = FN(PW,peek_space)(pw);
1508 return isl_space_find_dim_by_id(space, type, id);
1509 }
1510
1511 /* Does the piecewise expression "pw" depend in any way
1512 * on the parameter with identifier "id"?
1513 */
FN(PW,involves_param_id)1514 isl_bool FN(PW,involves_param_id)(__isl_keep PW *pw, __isl_keep isl_id *id)
1515 {
1516 int pos;
1517
1518 if (!pw || !id)
1519 return isl_bool_error;
1520 if (pw->n == 0)
1521 return isl_bool_false;
1522
1523 pos = FN(PW,find_dim_by_id)(pw, isl_dim_param, id);
1524 if (pos < 0)
1525 return isl_bool_false;
1526 return FN(PW,involves_dims)(pw, isl_dim_param, pos, 1);
1527 }
1528
1529 /* Reset the space of "pw". Since we don't know if the elements
1530 * represent the spaces themselves or their domains, we pass along
1531 * both when we call their reset_space_and_domain.
1532 */
FN(PW,reset_space_and_domain)1533 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1534 __isl_take isl_space *space, __isl_take isl_space *domain)
1535 {
1536 int i;
1537
1538 pw = FN(PW,cow)(pw);
1539 if (!pw || !space || !domain)
1540 goto error;
1541
1542 for (i = 0; i < pw->n; ++i) {
1543 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1544 isl_space_copy(domain));
1545 if (!pw->p[i].set)
1546 goto error;
1547 pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
1548 isl_space_copy(space), isl_space_copy(domain));
1549 if (!pw->p[i].FIELD)
1550 goto error;
1551 }
1552
1553 isl_space_free(domain);
1554
1555 isl_space_free(pw->dim);
1556 pw->dim = space;
1557
1558 return pw;
1559 error:
1560 isl_space_free(domain);
1561 isl_space_free(space);
1562 FN(PW,free)(pw);
1563 return NULL;
1564 }
1565
FN(PW,reset_domain_space)1566 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1567 __isl_take isl_space *domain)
1568 {
1569 isl_space *space;
1570
1571 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1572 FN(PW,get_space)(pw));
1573 return FN(PW,reset_space_and_domain)(pw, space, domain);
1574 }
1575
FN(PW,reset_space)1576 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
1577 {
1578 isl_space *domain;
1579
1580 domain = isl_space_domain(isl_space_copy(dim));
1581 return FN(PW,reset_space_and_domain)(pw, dim, domain);
1582 }
1583
FN(PW,set_tuple_id)1584 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1585 __isl_take isl_id *id)
1586 {
1587 isl_space *space;
1588
1589 pw = FN(PW,cow)(pw);
1590 if (!pw)
1591 goto error;
1592
1593 space = FN(PW,get_space)(pw);
1594 space = isl_space_set_tuple_id(space, type, id);
1595
1596 return FN(PW,reset_space)(pw, space);
1597 error:
1598 isl_id_free(id);
1599 return FN(PW,free)(pw);
1600 }
1601
1602 /* Drop the id on the specified tuple.
1603 */
FN(PW,reset_tuple_id)1604 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1605 {
1606 isl_space *space;
1607
1608 if (!pw)
1609 return NULL;
1610 if (!FN(PW,has_tuple_id)(pw, type))
1611 return pw;
1612
1613 pw = FN(PW,cow)(pw);
1614 if (!pw)
1615 return NULL;
1616
1617 space = FN(PW,get_space)(pw);
1618 space = isl_space_reset_tuple_id(space, type);
1619
1620 return FN(PW,reset_space)(pw, space);
1621 }
1622
FN(PW,set_dim_id)1623 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1624 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1625 {
1626 pw = FN(PW,cow)(pw);
1627 if (!pw)
1628 goto error;
1629 pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
1630 return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
1631 error:
1632 isl_id_free(id);
1633 return FN(PW,free)(pw);
1634 }
1635
1636 /* Reset the user pointer on all identifiers of parameters and tuples
1637 * of the space of "pw".
1638 */
FN(PW,reset_user)1639 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1640 {
1641 isl_space *space;
1642
1643 space = FN(PW,get_space)(pw);
1644 space = isl_space_reset_user(space);
1645
1646 return FN(PW,reset_space)(pw, space);
1647 }
1648
FN(PW,n_piece)1649 isl_size FN(PW,n_piece)(__isl_keep PW *pw)
1650 {
1651 return pw ? pw->n : isl_size_error;
1652 }
1653
FN(PW,foreach_piece)1654 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1655 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1656 void *user)
1657 {
1658 int i;
1659
1660 if (!pw)
1661 return isl_stat_error;
1662
1663 for (i = 0; i < pw->n; ++i)
1664 if (fn(isl_set_copy(pw->p[i].set),
1665 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1666 return isl_stat_error;
1667
1668 return isl_stat_ok;
1669 }
1670
1671 /* Is "pw" defined over a single universe domain?
1672 *
1673 * If the default value of this piecewise type is zero,
1674 * then a "pw" with a zero number of cells is also accepted
1675 * as it represents the default zero value.
1676 */
FN(FN (PW,isa),BASE)1677 isl_bool FN(FN(PW,isa),BASE)(__isl_keep PW *pw)
1678 {
1679 isl_size n;
1680
1681 n = FN(PW,n_piece)(pw);
1682 if (n < 0)
1683 return isl_bool_error;
1684 if (DEFAULT_IS_ZERO && n == 0)
1685 return isl_bool_true;
1686 if (n != 1)
1687 return isl_bool_false;
1688 return isl_set_plain_is_universe(FN(PW,peek_domain_at)(pw, 0));
1689 }
1690
1691 /* Return a zero base expression in the same space (and of the same type)
1692 * as "pw".
1693 */
FN(EL,zero_like_type)1694 static __isl_give EL *FN(EL,zero_like_type)(__isl_take PW *pw OPT_TYPE_PARAM)
1695 {
1696 isl_space *space;
1697
1698 space = FN(PW,get_space)(pw);
1699 FN(PW,free)(pw);
1700 return FN(EL,zero_in_space)(space OPT_TYPE_ARG(NO_LOC));
1701 }
1702
1703 #ifndef HAS_TYPE
1704 /* Return a zero base expression in the same space as "pw".
1705 */
FN(EL,zero_like)1706 static __isl_give EL *FN(EL,zero_like)(__isl_take PW *pw)
1707 {
1708 return FN(EL,zero_like_type)(pw);
1709 }
1710 #else
1711 /* Return a zero base expression in the same space and of the same type
1712 * as "pw".
1713 *
1714 * Pass along the type as an explicit argument for uniform handling
1715 * in isl_*_zero_like_type.
1716 */
FN(EL,zero_like)1717 static __isl_give EL *FN(EL,zero_like)(__isl_take PW *pw)
1718 {
1719 enum isl_fold type;
1720
1721 type = FN(PW,get_type)(pw);
1722 if (type < 0)
1723 goto error;
1724 return FN(EL,zero_like_type)(pw, type);
1725 error:
1726 FN(PW,free)(pw);
1727 return NULL;
1728 }
1729 #endif
1730
1731 /* Given that "pw" is defined over a single universe domain,
1732 * return the base expression associated to this domain.
1733 *
1734 * If the number of cells is zero, then "pw" is of a piecewise type
1735 * with a default zero value and effectively represents zero.
1736 * In this case, create a zero base expression in the same space
1737 * (and with the same type).
1738 * Otherwise, simply extract the associated base expression.
1739 */
FN(FN (PW,as),BASE)1740 __isl_give EL *FN(FN(PW,as),BASE)(__isl_take PW *pw)
1741 {
1742 isl_bool is_total;
1743 isl_size n;
1744 EL *el;
1745
1746 is_total = FN(FN(PW,isa),BASE)(pw);
1747 if (is_total < 0)
1748 goto error;
1749 if (!is_total)
1750 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1751 "expecting single total function", goto error);
1752 n = FN(PW,n_piece)(pw);
1753 if (n < 0)
1754 goto error;
1755 if (n == 0)
1756 return FN(EL,zero_like)(pw);
1757 el = FN(PW,take_base_at)(pw, 0);
1758 FN(PW,free)(pw);
1759 return el;
1760 error:
1761 FN(PW,free)(pw);
1762 return NULL;
1763 }
1764
1765 #ifdef HAS_TYPE
1766 /* Negate the type of "pw".
1767 */
FN(PW,negate_type)1768 static __isl_give PW *FN(PW,negate_type)(__isl_take PW *pw)
1769 {
1770 pw = FN(PW,cow)(pw);
1771 if (!pw)
1772 return NULL;
1773 pw->type = isl_fold_type_negate(pw->type);
1774 return pw;
1775 }
1776 #else
1777 /* Negate the type of "pw".
1778 * Since "pw" does not have a type, do nothing.
1779 */
FN(PW,negate_type)1780 static __isl_give PW *FN(PW,negate_type)(__isl_take PW *pw)
1781 {
1782 return pw;
1783 }
1784 #endif
1785
FN(PW,mul_isl_int)1786 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1787 {
1788 int i;
1789
1790 if (isl_int_is_one(v))
1791 return pw;
1792 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1793 PW *zero;
1794 isl_space *dim = FN(PW,get_space)(pw);
1795 zero = FN(PW,ZERO)(dim OPT_TYPE_ARG(pw->));
1796 FN(PW,free)(pw);
1797 return zero;
1798 }
1799 pw = FN(PW,cow)(pw);
1800 if (isl_int_is_neg(v))
1801 pw = FN(PW,negate_type)(pw);
1802 if (!pw)
1803 return NULL;
1804 if (pw->n == 0)
1805 return pw;
1806
1807 for (i = 0; i < pw->n; ++i) {
1808 pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
1809 if (!pw->p[i].FIELD)
1810 goto error;
1811 }
1812
1813 return pw;
1814 error:
1815 FN(PW,free)(pw);
1816 return NULL;
1817 }
1818
1819 /* Multiply the pieces of "pw" by "v" and return the result.
1820 */
FN(PW,scale_val)1821 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1822 {
1823 int i;
1824
1825 if (!pw || !v)
1826 goto error;
1827
1828 if (isl_val_is_one(v)) {
1829 isl_val_free(v);
1830 return pw;
1831 }
1832 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1833 PW *zero;
1834 isl_space *space = FN(PW,get_space)(pw);
1835 zero = FN(PW,ZERO)(space OPT_TYPE_ARG(pw->));
1836 FN(PW,free)(pw);
1837 isl_val_free(v);
1838 return zero;
1839 }
1840 if (pw->n == 0) {
1841 isl_val_free(v);
1842 return pw;
1843 }
1844 pw = FN(PW,cow)(pw);
1845 if (isl_val_is_neg(v))
1846 pw = FN(PW,negate_type)(pw);
1847 if (!pw)
1848 goto error;
1849
1850 for (i = 0; i < pw->n; ++i) {
1851 pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
1852 isl_val_copy(v));
1853 if (!pw->p[i].FIELD)
1854 goto error;
1855 }
1856
1857 isl_val_free(v);
1858 return pw;
1859 error:
1860 isl_val_free(v);
1861 FN(PW,free)(pw);
1862 return NULL;
1863 }
1864
1865 /* Divide the pieces of "pw" by "v" and return the result.
1866 */
FN(PW,scale_down_val)1867 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1868 {
1869 int i;
1870
1871 if (!pw || !v)
1872 goto error;
1873
1874 if (isl_val_is_one(v)) {
1875 isl_val_free(v);
1876 return pw;
1877 }
1878
1879 if (!isl_val_is_rat(v))
1880 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1881 "expecting rational factor", goto error);
1882 if (isl_val_is_zero(v))
1883 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1884 "cannot scale down by zero", goto error);
1885
1886 if (pw->n == 0) {
1887 isl_val_free(v);
1888 return pw;
1889 }
1890 pw = FN(PW,cow)(pw);
1891 if (isl_val_is_neg(v))
1892 pw = FN(PW,negate_type)(pw);
1893 if (!pw)
1894 goto error;
1895
1896 for (i = 0; i < pw->n; ++i) {
1897 pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
1898 isl_val_copy(v));
1899 if (!pw->p[i].FIELD)
1900 goto error;
1901 }
1902
1903 isl_val_free(v);
1904 return pw;
1905 error:
1906 isl_val_free(v);
1907 FN(PW,free)(pw);
1908 return NULL;
1909 }
1910
FN(PW,scale)1911 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1912 {
1913 return FN(PW,mul_isl_int)(pw, v);
1914 }
1915
1916 /* Apply some normalization to "pw".
1917 * In particular, sort the pieces according to their function value
1918 * expressions, combining pairs of adjacent pieces with
1919 * the same such expression, and then normalize the domains of the pieces.
1920 *
1921 * We normalize in place, but if anything goes wrong we need
1922 * to return NULL, so we need to make sure we don't change the
1923 * meaning of any possible other copies of "pw".
1924 */
FN(PW,normalize)1925 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
1926 {
1927 int i;
1928 isl_set *set;
1929
1930 pw = FN(PW,sort)(pw);
1931 if (!pw)
1932 return NULL;
1933 for (i = 0; i < pw->n; ++i) {
1934 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
1935 if (!set)
1936 return FN(PW,free)(pw);
1937 isl_set_free(pw->p[i].set);
1938 pw->p[i].set = set;
1939 }
1940
1941 return pw;
1942 }
1943
1944 /* Is pw1 obviously equal to pw2?
1945 * That is, do they have obviously identical cells and obviously identical
1946 * elements on each cell?
1947 *
1948 * If "pw1" or "pw2" contain any NaNs, then they are considered
1949 * not to be the same. A NaN is not equal to anything, not even
1950 * to another NaN.
1951 */
FN(PW,plain_is_equal)1952 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
1953 {
1954 int i;
1955 isl_bool equal, has_nan;
1956
1957 if (!pw1 || !pw2)
1958 return isl_bool_error;
1959
1960 has_nan = FN(PW,involves_nan)(pw1);
1961 if (has_nan >= 0 && !has_nan)
1962 has_nan = FN(PW,involves_nan)(pw2);
1963 if (has_nan < 0 || has_nan)
1964 return isl_bool_not(has_nan);
1965
1966 if (pw1 == pw2)
1967 return isl_bool_true;
1968 equal = FN(PW,has_equal_space)(pw1, pw2);
1969 if (equal < 0 || !equal)
1970 return equal;
1971
1972 pw1 = FN(PW,copy)(pw1);
1973 pw2 = FN(PW,copy)(pw2);
1974 pw1 = FN(PW,normalize)(pw1);
1975 pw2 = FN(PW,normalize)(pw2);
1976 if (!pw1 || !pw2)
1977 goto error;
1978
1979 equal = isl_bool_ok(pw1->n == pw2->n);
1980 for (i = 0; equal && i < pw1->n; ++i) {
1981 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
1982 if (equal < 0)
1983 goto error;
1984 if (!equal)
1985 break;
1986 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
1987 if (equal < 0)
1988 goto error;
1989 }
1990
1991 FN(PW,free)(pw1);
1992 FN(PW,free)(pw2);
1993 return equal;
1994 error:
1995 FN(PW,free)(pw1);
1996 FN(PW,free)(pw2);
1997 return isl_bool_error;
1998 }
1999
2000 /* Does "pw" involve any NaNs?
2001 */
FN(PW,involves_nan)2002 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2003 {
2004 int i;
2005
2006 if (!pw)
2007 return isl_bool_error;
2008 if (pw->n == 0)
2009 return isl_bool_false;
2010
2011 for (i = 0; i < pw->n; ++i) {
2012 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2013 if (has_nan < 0 || has_nan)
2014 return has_nan;
2015 }
2016
2017 return isl_bool_false;
2018 }
2019