extract out shared isl_pw_*_un_op
[isl.git] / isl_pw_templ.c
blob7f73a95fb5bc6a6fa2a13883941de63e14ea4d8a
1 /*
2 * Copyright 2010-2011 INRIA Saclay
3 * Copyright 2011 Sven Verdoolaege
4 * Copyright 2012-2014 Ecole Normale Superieure
6 * Use of this software is governed by the MIT license
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
14 #include <isl/id.h>
15 #include <isl/aff.h>
16 #include <isl_sort.h>
17 #include <isl_val_private.h>
19 #include <isl_pw_macro.h>
21 #include "opt_type.h"
23 __isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *space
24 OPT_TYPE_PARAM, int n)
26 isl_ctx *ctx;
27 struct PW *pw;
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;
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;
49 __isl_give PW *FN(PW,ZERO)(__isl_take isl_space *space OPT_TYPE_PARAM)
51 return FN(PW,alloc_size)(space OPT_TYPE_ARG(NO_LOC), 0);
54 /* Add a piece with domain "set" and base expression "el"
55 * to the piecewise expression "pw".
57 * Do this independently of the values of "set" and "el",
58 * such that this function can be used by isl_pw_*_dup.
60 __isl_give PW *FN(PW,add_dup_piece)(__isl_take PW *pw,
61 __isl_take isl_set *set, __isl_take EL *el)
63 isl_ctx *ctx;
64 isl_space *el_dim = NULL;
66 if (!pw || !set || !el)
67 goto error;
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);
77 pw->p[pw->n].set = set;
78 pw->p[pw->n].FIELD = el;
79 pw->n++;
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;
91 /* Add a piece with domain "set" and base expression "el"
92 * to the piecewise expression "pw", provided the domain
93 * is not obviously empty and the base expression
94 * is not equal to the default value.
96 __isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
97 __isl_take isl_set *set, __isl_take EL *el)
99 isl_bool skip;
101 skip = isl_set_plain_is_empty(set);
102 if (skip >= 0 && !skip)
103 skip = FN(EL,EL_IS_ZERO)(el);
104 if (skip >= 0 && !skip)
105 return FN(PW,add_dup_piece)(pw, set, el);
107 isl_set_free(set);
108 FN(EL,free)(el);
109 if (skip < 0)
110 return FN(PW,free)(pw);
111 return pw;
114 /* Does the space of "set" correspond to that of the domain of "el".
116 static isl_bool FN(PW,compatible_domain)(__isl_keep EL *el,
117 __isl_keep isl_set *set)
119 isl_bool ok;
120 isl_space *el_space, *set_space;
122 if (!set || !el)
123 return isl_bool_error;
124 set_space = isl_set_get_space(set);
125 el_space = FN(EL,get_space)(el);
126 ok = isl_space_is_domain_internal(set_space, el_space);
127 isl_space_free(el_space);
128 isl_space_free(set_space);
129 return ok;
132 /* Check that the space of "set" corresponds to that of the domain of "el".
134 static isl_stat FN(PW,check_compatible_domain)(__isl_keep EL *el,
135 __isl_keep isl_set *set)
137 isl_bool ok;
139 ok = FN(PW,compatible_domain)(el, set);
140 if (ok < 0)
141 return isl_stat_error;
142 if (!ok)
143 isl_die(isl_set_get_ctx(set), isl_error_invalid,
144 "incompatible spaces", return isl_stat_error);
146 return isl_stat_ok;
149 __isl_give PW *FN(PW,alloc)(OPT_TYPE_PARAM_FIRST
150 __isl_take isl_set *set, __isl_take EL *el)
152 PW *pw;
154 if (FN(PW,check_compatible_domain)(el, set) < 0)
155 goto error;
157 pw = FN(PW,alloc_size)(FN(EL,get_space)(el) OPT_TYPE_ARG(NO_LOC), 1);
159 return FN(PW,add_piece)(pw, set, el);
160 error:
161 isl_set_free(set);
162 FN(EL,free)(el);
163 return NULL;
166 __isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
168 int i;
169 PW *dup;
171 if (!pw)
172 return NULL;
174 dup = FN(PW,alloc_size)(isl_space_copy(pw->dim)
175 OPT_TYPE_ARG(pw->), pw->n);
176 if (!dup)
177 return NULL;
179 for (i = 0; i < pw->n; ++i)
180 dup = FN(PW,add_dup_piece)(dup, isl_set_copy(pw->p[i].set),
181 FN(EL,copy)(pw->p[i].FIELD));
183 return dup;
186 __isl_give PW *FN(PW,cow)(__isl_take PW *pw)
188 if (!pw)
189 return NULL;
191 if (pw->ref == 1)
192 return pw;
193 pw->ref--;
194 return FN(PW,dup)(pw);
197 __isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
199 if (!pw)
200 return NULL;
202 pw->ref++;
203 return pw;
206 __isl_null PW *FN(PW,free)(__isl_take PW *pw)
208 int i;
210 if (!pw)
211 return NULL;
212 if (--pw->ref > 0)
213 return NULL;
215 for (i = 0; i < pw->n; ++i) {
216 isl_set_free(pw->p[i].set);
217 FN(EL,free)(pw->p[i].FIELD);
219 isl_space_free(pw->dim);
220 free(pw);
222 return NULL;
225 /* Return the space of "pw".
227 __isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
229 return pw ? pw->dim : NULL;
232 __isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
234 return isl_space_copy(FN(PW,peek_space)(pw));
237 /* Return the space of "pw".
238 * This may be either a copy or the space itself
239 * if there is only one reference to "pw".
240 * This allows the space to be modified inplace
241 * if both the piecewise expression and its space have only a single reference.
242 * The caller is not allowed to modify "pw" between this call and
243 * a subsequent call to isl_pw_*_restore_*.
244 * The only exception is that isl_pw_*_free can be called instead.
246 __isl_give isl_space *FN(PW,take_space)(__isl_keep PW *pw)
248 isl_space *space;
250 if (!pw)
251 return NULL;
252 if (pw->ref != 1)
253 return FN(PW,get_space)(pw);
254 space = pw->dim;
255 pw->dim = NULL;
256 return space;
259 /* Set the space of "pw" to "space", where the space of "pw" may be missing
260 * due to a preceding call to isl_pw_*_take_space.
261 * However, in this case, "pw" only has a single reference and
262 * then the call to isl_pw_*_cow has no effect.
264 __isl_give PW *FN(PW,restore_space)(__isl_take PW *pw,
265 __isl_take isl_space *space)
267 if (!pw || !space)
268 goto error;
270 if (pw->dim == space) {
271 isl_space_free(space);
272 return pw;
275 pw = FN(PW,cow)(pw);
276 if (!pw)
277 goto error;
278 isl_space_free(pw->dim);
279 pw->dim = space;
281 return pw;
282 error:
283 FN(PW,free)(pw);
284 isl_space_free(space);
285 return NULL;
288 /* Check that "pos" is a valid position for a cell in "pw".
290 static isl_stat FN(PW,check_pos)(__isl_keep PW *pw, int pos)
292 if (!pw)
293 return isl_stat_error;
294 if (pos < 0 || pos >= pw->n)
295 isl_die(FN(PW,get_ctx)(pw), isl_error_internal,
296 "position out of bounds", return isl_stat_error);
297 return isl_stat_ok;
300 /* Return the cell at position "pos" in "pw".
302 static __isl_keep isl_set *FN(PW,peek_domain_at)(__isl_keep PW *pw, int pos)
304 if (FN(PW,check_pos)(pw, pos) < 0)
305 return NULL;
306 return pw->p[pos].set;
309 /* Return a copy of the cell at position "pos" in "pw".
311 __isl_give isl_set *FN(PW,get_domain_at)(__isl_keep PW *pw, int pos)
313 return isl_set_copy(FN(PW,peek_domain_at)(pw, pos));
316 /* Return the base expression associated to
317 * the cell at position "pos" in "pw".
319 static __isl_keep EL *FN(PW,peek_base_at)(__isl_keep PW *pw, int pos)
321 if (FN(PW,check_pos)(pw, pos) < 0)
322 return NULL;
323 return pw->p[pos].FIELD;
326 /* Return a copy of the base expression associated to
327 * the cell at position "pos" in "pw".
329 __isl_give EL *FN(PW,get_base_at)(__isl_keep PW *pw, int pos)
331 return FN(EL,copy)(FN(PW,peek_base_at)(pw, pos));
334 /* Return the base expression associated to
335 * the cell at position "pos" in "pw".
336 * This may be either a copy or the base expression itself
337 * if there is only one reference to "pw".
338 * This allows the base expression to be modified inplace
339 * if both the piecewise expression and this base expression
340 * have only a single reference.
341 * The caller is not allowed to modify "pw" between this call and
342 * a subsequent call to isl_pw_*_restore_*.
343 * The only exception is that isl_pw_*_free can be called instead.
345 __isl_give EL *FN(PW,take_base_at)(__isl_keep PW *pw, int pos)
347 EL *el;
349 if (!pw)
350 return NULL;
351 if (pw->ref != 1)
352 return FN(PW,get_base_at)(pw, pos);
353 if (FN(PW,check_pos)(pw, pos) < 0)
354 return NULL;
355 el = pw->p[pos].FIELD;
356 pw->p[pos].FIELD = NULL;
357 return el;
360 /* Set the base expression associated to
361 * the cell at position "pos" in "pw" to "el",
362 * where this base expression may be missing
363 * due to a preceding call to isl_pw_*_take_base_at.
364 * However, in this case, "pw" only has a single reference and
365 * then the call to isl_pw_*_cow has no effect.
367 __isl_give PW *FN(PW,restore_base_at)(__isl_take PW *pw, int pos,
368 __isl_take EL *el)
370 if (FN(PW,check_pos)(pw, pos) < 0 || !el)
371 goto error;
373 if (pw->p[pos].FIELD == el) {
374 FN(EL,free)(el);
375 return pw;
378 pw = FN(PW,cow)(pw);
379 if (!pw)
380 goto error;
381 FN(EL,free)(pw->p[pos].FIELD);
382 pw->p[pos].FIELD = el;
384 return pw;
385 error:
386 FN(PW,free)(pw);
387 FN(EL,free)(el);
388 return NULL;
391 /* Create a piecewise expression with the given base expression on a universe
392 * domain.
394 static __isl_give PW *FN(FN(FN(PW,from),BASE),type_base)(__isl_take EL *el
395 OPT_TYPE_PARAM)
397 isl_set *dom = isl_set_universe(FN(EL,get_domain_space)(el));
398 return FN(PW,alloc)(OPT_TYPE_ARG_FIRST(NO_LOC) dom, el);
401 /* Create a piecewise expression with the given base expression on a universe
402 * domain.
404 * If the default value of this piecewise type is zero and
405 * if "el" is effectively zero, then create an empty piecewise expression
406 * instead.
408 static __isl_give PW *FN(FN(FN(PW,from),BASE),type)(__isl_take EL *el
409 OPT_TYPE_PARAM)
411 isl_bool is_zero;
412 isl_space *space;
414 if (!DEFAULT_IS_ZERO)
415 return FN(FN(FN(PW,from),BASE),type_base)(el
416 OPT_TYPE_ARG(NO_LOC));
417 is_zero = FN(EL,EL_IS_ZERO)(el);
418 if (is_zero < 0)
419 goto error;
420 if (!is_zero)
421 return FN(FN(FN(PW,from),BASE),type_base)(el
422 OPT_TYPE_ARG(NO_LOC));
423 space = FN(EL,get_space)(el);
424 FN(EL,free)(el);
425 return FN(PW,ZERO)(space OPT_TYPE_ARG(NO_LOC));
426 error:
427 FN(EL,free)(el);
428 return NULL;
431 #ifdef HAS_TYPE
432 /* Create a piecewise expression with the given base expression on a universe
433 * domain.
435 * Pass along the type as an extra argument for improved uniformity
436 * with piecewise types that do not have a fold type.
438 __isl_give PW *FN(FN(PW,from),BASE)(__isl_take EL *el)
440 enum isl_fold type = FN(EL,get_type)(el);
441 return FN(FN(FN(PW,from),BASE),type)(el, type);
443 #else
444 __isl_give PW *FN(FN(PW,from),BASE)(__isl_take EL *el)
446 return FN(FN(FN(PW,from),BASE),type)(el);
448 #endif
450 const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
451 unsigned pos)
453 return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
456 isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
457 unsigned pos)
459 return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
462 __isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
463 unsigned pos)
465 return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
468 isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
470 return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
473 const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
475 return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
478 isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
480 return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
483 __isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
485 return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
488 isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
490 if (!pw)
491 return isl_bool_error;
493 return isl_bool_ok(pw->n == 0);
496 __isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
497 __isl_take isl_reordering *exp)
499 int i;
500 isl_size n;
502 pw = FN(PW,cow)(pw);
503 n = FN(PW,n_piece)(pw);
504 if (n < 0 || !exp)
505 goto error;
507 for (i = 0; i < n; ++i) {
508 EL *el;
510 pw->p[i].set = isl_set_realign(pw->p[i].set,
511 isl_reordering_copy(exp));
512 if (!pw->p[i].set)
513 goto error;
514 el = FN(PW,take_base_at)(pw, i);
515 el = FN(EL,realign_domain)(el, isl_reordering_copy(exp));
516 pw = FN(PW,restore_base_at)(pw, i, el);
517 if (!pw)
518 goto error;
521 pw = FN(PW,reset_domain_space)(pw, isl_reordering_get_space(exp));
523 isl_reordering_free(exp);
524 return pw;
525 error:
526 isl_reordering_free(exp);
527 FN(PW,free)(pw);
528 return NULL;
531 #undef TYPE
532 #define TYPE PW
534 #include "isl_check_named_params_templ.c"
536 /* Align the parameters of "pw" to those of "model".
538 __isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
540 isl_ctx *ctx;
541 isl_bool equal_params;
543 if (!pw || !model)
544 goto error;
546 ctx = isl_space_get_ctx(model);
547 if (!isl_space_has_named_params(model))
548 isl_die(ctx, isl_error_invalid,
549 "model has unnamed parameters", goto error);
550 if (FN(PW,check_named_params)(pw) < 0)
551 goto error;
552 equal_params = isl_space_has_equal_params(pw->dim, model);
553 if (equal_params < 0)
554 goto error;
555 if (!equal_params) {
556 isl_reordering *exp;
558 exp = isl_parameter_alignment_reordering(pw->dim, model);
559 exp = isl_reordering_extend_space(exp,
560 FN(PW,get_domain_space)(pw));
561 pw = FN(PW,realign_domain)(pw, exp);
564 isl_space_free(model);
565 return pw;
566 error:
567 isl_space_free(model);
568 FN(PW,free)(pw);
569 return NULL;
572 #undef TYPE
573 #define TYPE PW
575 static
576 #include "isl_align_params_bin_templ.c"
578 #undef SUFFIX
579 #define SUFFIX set
580 #undef ARG1
581 #define ARG1 PW
582 #undef ARG2
583 #define ARG2 isl_set
585 static
586 #include "isl_align_params_templ.c"
588 #undef TYPE
589 #define TYPE PW
591 #include "isl_type_has_equal_space_bin_templ.c"
592 #include "isl_type_check_equal_space_templ.c"
594 /* Private version of "union_add". For isl_pw_qpolynomial and
595 * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
597 static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
599 int i, j, n;
600 struct PW *res;
601 isl_ctx *ctx;
602 isl_set *set;
604 if (FN(PW,align_params_bin)(&pw1, &pw2) < 0)
605 goto error;
607 ctx = isl_space_get_ctx(pw1->dim);
608 if (!OPT_EQUAL_TYPES(pw1->, pw2->))
609 isl_die(ctx, isl_error_invalid,
610 "fold types don't match", goto error);
611 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
612 goto error;
614 if (FN(PW,IS_ZERO)(pw1)) {
615 FN(PW,free)(pw1);
616 return pw2;
619 if (FN(PW,IS_ZERO)(pw2)) {
620 FN(PW,free)(pw2);
621 return pw1;
624 n = (pw1->n + 1) * (pw2->n + 1);
625 res = FN(PW,alloc_size)(isl_space_copy(pw1->dim)
626 OPT_TYPE_ARG(pw1->), n);
628 for (i = 0; i < pw1->n; ++i) {
629 set = isl_set_copy(pw1->p[i].set);
630 for (j = 0; j < pw2->n; ++j) {
631 struct isl_set *common;
632 EL *sum;
633 common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
634 isl_set_copy(pw2->p[j].set));
635 if (isl_set_plain_is_empty(common)) {
636 isl_set_free(common);
637 continue;
639 set = isl_set_subtract(set,
640 isl_set_copy(pw2->p[j].set));
642 sum = FN(EL,add_on_domain)(common,
643 FN(EL,copy)(pw1->p[i].FIELD),
644 FN(EL,copy)(pw2->p[j].FIELD));
646 res = FN(PW,add_piece)(res, common, sum);
648 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
651 for (j = 0; j < pw2->n; ++j) {
652 set = isl_set_copy(pw2->p[j].set);
653 for (i = 0; i < pw1->n; ++i)
654 set = isl_set_subtract(set,
655 isl_set_copy(pw1->p[i].set));
656 res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
659 FN(PW,free)(pw1);
660 FN(PW,free)(pw2);
662 return res;
663 error:
664 FN(PW,free)(pw1);
665 FN(PW,free)(pw2);
666 return NULL;
669 /* Make sure "pw" has room for at least "n" more pieces.
671 * If there is only one reference to pw, we extend it in place.
672 * Otherwise, we create a new PW and copy the pieces.
674 static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
676 int i;
677 isl_ctx *ctx;
678 PW *res;
680 if (!pw)
681 return NULL;
682 if (pw->n + n <= pw->size)
683 return pw;
684 ctx = FN(PW,get_ctx)(pw);
685 n += pw->n;
686 if (pw->ref == 1) {
687 res = isl_realloc(ctx, pw, struct PW,
688 sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
689 if (!res)
690 return FN(PW,free)(pw);
691 res->size = n;
692 return res;
694 res = FN(PW,alloc_size)(isl_space_copy(pw->dim) OPT_TYPE_ARG(pw->), n);
695 if (!res)
696 return FN(PW,free)(pw);
697 for (i = 0; i < pw->n; ++i)
698 res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
699 FN(EL,copy)(pw->p[i].FIELD));
700 FN(PW,free)(pw);
701 return res;
704 __isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
706 int i;
707 isl_ctx *ctx;
709 if (FN(PW,align_params_bin)(&pw1, &pw2) < 0)
710 goto error;
712 if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
713 return FN(PW,add_disjoint)(pw2, pw1);
715 ctx = isl_space_get_ctx(pw1->dim);
716 if (!OPT_EQUAL_TYPES(pw1->, pw2->))
717 isl_die(ctx, isl_error_invalid,
718 "fold types don't match", goto error);
719 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
720 goto error;
722 if (FN(PW,IS_ZERO)(pw1)) {
723 FN(PW,free)(pw1);
724 return pw2;
727 if (FN(PW,IS_ZERO)(pw2)) {
728 FN(PW,free)(pw2);
729 return pw1;
732 pw1 = FN(PW,grow)(pw1, pw2->n);
733 if (!pw1)
734 goto error;
736 for (i = 0; i < pw2->n; ++i)
737 pw1 = FN(PW,add_piece)(pw1,
738 isl_set_copy(pw2->p[i].set),
739 FN(EL,copy)(pw2->p[i].FIELD));
741 FN(PW,free)(pw2);
743 return pw1;
744 error:
745 FN(PW,free)(pw1);
746 FN(PW,free)(pw2);
747 return NULL;
750 /* This function is currently only used from isl_aff.c
752 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
753 __isl_take PW *pw2, __isl_take isl_space *space,
754 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
755 __attribute__ ((unused));
757 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
758 * The result of "fn" (and therefore also of this function) lives in "space".
760 static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
761 __isl_take PW *pw2, __isl_take isl_space *space,
762 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
764 int i, j, n;
765 PW *res = NULL;
767 if (!pw1 || !pw2)
768 goto error;
770 n = pw1->n * pw2->n;
771 res = FN(PW,alloc_size)(isl_space_copy(space) OPT_TYPE_ARG(pw1->), n);
773 for (i = 0; i < pw1->n; ++i) {
774 for (j = 0; j < pw2->n; ++j) {
775 isl_set *common;
776 EL *res_ij;
777 int empty;
779 common = isl_set_intersect(
780 isl_set_copy(pw1->p[i].set),
781 isl_set_copy(pw2->p[j].set));
782 empty = isl_set_plain_is_empty(common);
783 if (empty < 0 || empty) {
784 isl_set_free(common);
785 if (empty < 0)
786 goto error;
787 continue;
790 res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
791 FN(EL,copy)(pw2->p[j].FIELD));
792 res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
794 res = FN(PW,add_piece)(res, common, res_ij);
798 isl_space_free(space);
799 FN(PW,free)(pw1);
800 FN(PW,free)(pw2);
801 return res;
802 error:
803 isl_space_free(space);
804 FN(PW,free)(pw1);
805 FN(PW,free)(pw2);
806 FN(PW,free)(res);
807 return NULL;
810 /* This function is currently only used from isl_aff.c
812 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
813 __isl_take PW *pw2,
814 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
815 __attribute__ ((unused));
817 /* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
818 * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
820 static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
821 __isl_take PW *pw2,
822 __isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
824 isl_space *space;
826 if (FN(PW,check_equal_space)(pw1, pw2) < 0)
827 goto error;
829 space = isl_space_copy(pw1->dim);
830 return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
831 error:
832 FN(PW,free)(pw1);
833 FN(PW,free)(pw2);
834 return NULL;
837 /* Return the parameter domain of "pw".
839 __isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
841 return isl_set_params(FN(PW,domain)(pw));
844 __isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
846 int i;
847 isl_set *dom;
849 if (!pw)
850 return NULL;
852 dom = isl_set_empty(FN(PW,get_domain_space)(pw));
853 for (i = 0; i < pw->n; ++i)
854 dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
856 FN(PW,free)(pw);
858 return dom;
861 /* Exploit the equalities in the domain of piece "i" of "pw"
862 * to simplify the associated function.
863 * If the domain of piece "i" is empty, then remove it entirely,
864 * replacing it with the final piece.
866 static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
867 int i)
869 isl_basic_set *aff;
870 int empty = isl_set_plain_is_empty(pw->p[i].set);
872 if (empty < 0)
873 return -1;
874 if (empty) {
875 isl_set_free(pw->p[i].set);
876 FN(EL,free)(pw->p[i].FIELD);
877 if (i != pw->n - 1)
878 pw->p[i] = pw->p[pw->n - 1];
879 pw->n--;
881 return 0;
884 aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
885 pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
886 if (!pw->p[i].FIELD)
887 return -1;
889 return 0;
892 /* Convert a piecewise expression defined over a parameter domain
893 * into one that is defined over a zero-dimensional set.
895 __isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
897 isl_space *space;
899 if (!pw)
900 return NULL;
901 if (!isl_space_is_set(pw->dim))
902 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
903 "not living in a set space", return FN(PW,free)(pw));
905 space = FN(PW,get_space)(pw);
906 space = isl_space_from_range(space);
907 pw = FN(PW,reset_space)(pw, space);
909 return pw;
912 /* Fix the value of the given parameter or domain dimension of "pw"
913 * to be equal to "value".
915 __isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
916 unsigned pos, int value)
918 int i;
919 isl_size n;
921 n = FN(PW,n_piece)(pw);
922 if (n < 0)
923 return FN(PW,free)(pw);
925 if (type == isl_dim_out)
926 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
927 "cannot fix output dimension", return FN(PW,free)(pw));
929 if (n == 0)
930 return pw;
932 if (type == isl_dim_in)
933 type = isl_dim_set;
935 pw = FN(PW,cow)(pw);
936 if (!pw)
937 return FN(PW,free)(pw);
939 for (i = n - 1; i >= 0; --i) {
940 pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
941 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
942 return FN(PW,free)(pw);
945 return pw;
948 /* Restrict the domain of "pw" by combining each cell
949 * with "set" through a call to "fn", where "fn" may be
950 * isl_set_intersect, isl_set_intersect_params, isl_set_intersect_factor_domain,
951 * isl_set_intersect_factor_range or isl_set_subtract.
953 static __isl_give PW *FN(PW,restrict_domain)(__isl_take PW *pw,
954 __isl_take isl_set *set,
955 __isl_give isl_set *(*fn)(__isl_take isl_set *set1,
956 __isl_take isl_set *set2))
958 int i;
959 isl_size n;
961 FN(PW,align_params_set)(&pw, &set);
962 n = FN(PW,n_piece)(pw);
963 if (n < 0 || !set)
964 goto error;
966 if (n == 0) {
967 isl_set_free(set);
968 return pw;
971 pw = FN(PW,cow)(pw);
972 if (!pw)
973 goto error;
975 for (i = n - 1; i >= 0; --i) {
976 pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
977 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
978 goto error;
981 isl_set_free(set);
982 return pw;
983 error:
984 isl_set_free(set);
985 FN(PW,free)(pw);
986 return NULL;
989 __isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
990 __isl_take isl_set *context)
992 return FN(PW,restrict_domain)(pw, context, &isl_set_intersect);
995 /* Intersect the domain of "pw" with the parameter domain "context".
997 __isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
998 __isl_take isl_set *context)
1000 return FN(PW,restrict_domain)(pw, context, &isl_set_intersect_params);
1003 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
1004 * a set in the space A, intersect the domain with the set.
1006 __isl_give PW *FN(PW,intersect_domain_wrapped_domain)(__isl_take PW *pw,
1007 __isl_take isl_set *set)
1009 return FN(PW,restrict_domain)(pw, set,
1010 &isl_set_intersect_factor_domain);
1013 /* Given a piecewise expression "pw" with domain in a space [A -> B] and
1014 * a set in the space B, intersect the domain with the set.
1016 __isl_give PW *FN(PW,intersect_domain_wrapped_range)(__isl_take PW *pw,
1017 __isl_take isl_set *set)
1019 return FN(PW,restrict_domain)(pw, set, &isl_set_intersect_factor_range);
1022 /* Subtract "domain' from the domain of "pw".
1024 __isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
1025 __isl_take isl_set *domain)
1027 return FN(PW,restrict_domain)(pw, domain, &isl_set_subtract);
1030 /* Return -1 if the piece "p1" should be sorted before "p2"
1031 * and 1 if it should be sorted after "p2".
1032 * Return 0 if they do not need to be sorted in a specific order.
1034 * The two pieces are compared on the basis of their function value expressions.
1036 static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
1038 struct FN(PW,piece) const *pc1 = p1;
1039 struct FN(PW,piece) const *pc2 = p2;
1041 return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
1044 /* Sort the pieces of "pw" according to their function value
1045 * expressions and then combine pairs of adjacent pieces with
1046 * the same such expression.
1048 * The sorting is performed in place because it does not
1049 * change the meaning of "pw", but care needs to be
1050 * taken not to change any possible other copies of "pw"
1051 * in case anything goes wrong.
1053 static __isl_give PW *FN(PW,sort_unique)(__isl_take PW *pw)
1055 int i, j;
1056 isl_set *set;
1058 if (!pw)
1059 return NULL;
1060 if (pw->n <= 1)
1061 return pw;
1062 if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
1063 &FN(PW,sort_field_cmp), NULL) < 0)
1064 return FN(PW,free)(pw);
1065 for (i = pw->n - 1; i >= 1; --i) {
1066 isl_bool equal;
1067 EL *el, *el_prev;
1068 isl_set *set_prev;
1070 el = FN(PW,peek_base_at)(pw, i);
1071 el_prev = FN(PW,peek_base_at)(pw, i - 1);
1072 equal = FN(EL,plain_is_equal)(el, el_prev);
1073 if (equal < 0)
1074 return FN(PW,free)(pw);
1075 if (!equal)
1076 continue;
1077 set = FN(PW,get_domain_at)(pw, i);
1078 set_prev = FN(PW,get_domain_at)(pw, i - 1);
1079 set = isl_set_union(set_prev, set);
1080 if (!set)
1081 return FN(PW,free)(pw);
1082 isl_set_free(pw->p[i].set);
1083 FN(EL,free)(pw->p[i].FIELD);
1084 isl_set_free(pw->p[i - 1].set);
1085 pw->p[i - 1].set = set;
1086 for (j = i + 1; j < pw->n; ++j)
1087 pw->p[j - 1] = pw->p[j];
1088 pw->n--;
1091 return pw;
1094 /* Compute the gist of "pw" with respect to the domain constraints
1095 * of "context" for the case where the domain of the last element
1096 * of "pw" is equal to "context".
1097 * Call "fn_el" to compute the gist of this element, replace
1098 * its domain by the universe and drop all other elements
1099 * as their domains are necessarily disjoint from "context".
1101 static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
1102 __isl_take isl_set *context,
1103 __isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
1105 int i;
1106 isl_space *space;
1107 EL *el;
1109 for (i = 0; i < pw->n - 1; ++i) {
1110 isl_set_free(pw->p[i].set);
1111 FN(EL,free)(pw->p[i].FIELD);
1113 pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
1114 pw->p[0].set = pw->p[pw->n - 1].set;
1115 pw->n = 1;
1117 space = isl_set_get_space(context);
1118 el = FN(PW,take_base_at)(pw, 0);
1119 el = fn_el(el, context);
1120 pw = FN(PW,restore_base_at)(pw, 0, el);
1121 if (!pw)
1122 goto error;
1123 context = isl_set_universe(space);
1124 isl_set_free(pw->p[0].set);
1125 pw->p[0].set = context;
1127 if (!pw->p[0].set)
1128 return FN(PW,free)(pw);
1130 return pw;
1131 error:
1132 isl_space_free(space);
1133 return FN(PW,free)(pw);
1136 /* Compute the gist of "pw" with respect to the domain constraints
1137 * of "context". Call "fn_el" to compute the gist of the elements
1138 * and "fn_dom" to compute the gist of the domains.
1140 * If the piecewise expression is empty or the context is the universe,
1141 * then nothing can be simplified.
1142 * If "pw" has a single domain and it is equal to "context",
1143 * then simply replace the domain by the universe.
1144 * Combine duplicate function value expressions first
1145 * to increase the chance of "pw" having a single domain.
1147 static __isl_give PW *FN(PW,gist_fn)(__isl_take PW *pw,
1148 __isl_take isl_set *context,
1149 __isl_give EL *(*fn_el)(__isl_take EL *el,
1150 __isl_take isl_set *set),
1151 __isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
1152 __isl_take isl_basic_set *bset))
1154 int i;
1155 int is_universe;
1156 isl_basic_set *hull = NULL;
1158 pw = FN(PW,sort_unique)(pw);
1159 if (!pw || !context)
1160 goto error;
1162 if (pw->n == 0) {
1163 isl_set_free(context);
1164 return pw;
1167 is_universe = isl_set_plain_is_universe(context);
1168 if (is_universe < 0)
1169 goto error;
1170 if (is_universe) {
1171 isl_set_free(context);
1172 return pw;
1175 FN(PW,align_params_set)(&pw, &context);
1177 pw = FN(PW,cow)(pw);
1178 if (!pw)
1179 goto error;
1181 if (pw->n == 1) {
1182 int equal;
1184 equal = isl_set_plain_is_equal(pw->p[0].set, context);
1185 if (equal < 0)
1186 goto error;
1187 if (equal)
1188 return FN(PW,gist_last)(pw, context, fn_el);
1191 context = isl_set_compute_divs(context);
1192 hull = isl_set_simple_hull(isl_set_copy(context));
1194 for (i = pw->n - 1; i >= 0; --i) {
1195 isl_set *set_i;
1196 EL *el;
1197 int empty;
1199 if (i == pw->n - 1) {
1200 int equal;
1201 equal = isl_set_plain_is_equal(pw->p[i].set, context);
1202 if (equal < 0)
1203 goto error;
1204 if (equal) {
1205 isl_basic_set_free(hull);
1206 return FN(PW,gist_last)(pw, context, fn_el);
1209 set_i = FN(PW,get_domain_at)(pw, i);
1210 set_i = isl_set_intersect(set_i, isl_set_copy(context));
1211 empty = isl_set_plain_is_empty(set_i);
1212 el = FN(PW,take_base_at)(pw, i);
1213 el = fn_el(el, set_i);
1214 pw = FN(PW,restore_base_at)(pw, i, el);
1215 if (!pw)
1216 goto error;
1217 pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
1218 if (empty < 0 || !pw->p[i].set)
1219 goto error;
1220 if (empty) {
1221 isl_set_free(pw->p[i].set);
1222 FN(EL,free)(pw->p[i].FIELD);
1223 if (i != pw->n - 1)
1224 pw->p[i] = pw->p[pw->n - 1];
1225 pw->n--;
1229 isl_basic_set_free(hull);
1230 isl_set_free(context);
1232 return pw;
1233 error:
1234 FN(PW,free)(pw);
1235 isl_basic_set_free(hull);
1236 isl_set_free(context);
1237 return NULL;
1240 __isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
1242 return FN(PW,gist_fn)(pw, context, &FN(EL,gist),
1243 &isl_set_gist_basic_set);
1246 __isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
1247 __isl_take isl_set *context)
1249 return FN(PW,gist_fn)(pw, context, &FN(EL,gist_params),
1250 &isl_set_gist_params_basic_set);
1253 /* Coalesce the domains of "pw".
1255 * Prior to the actual coalescing, first sort the pieces such that
1256 * pieces with the same function value expression are combined
1257 * into a single piece, the combined domain of which can then
1258 * be coalesced.
1260 __isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
1262 int i;
1263 isl_size n;
1265 pw = FN(PW,sort_unique)(pw);
1266 n = FN(PW,n_piece)(pw);
1267 if (n < 0)
1268 return FN(PW,free)(pw);
1270 for (i = 0; i < n; ++i) {
1271 pw->p[i].set = isl_set_coalesce(pw->p[i].set);
1272 if (!pw->p[i].set)
1273 goto error;
1276 return pw;
1277 error:
1278 FN(PW,free)(pw);
1279 return NULL;
1282 isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
1284 return pw ? isl_space_get_ctx(pw->dim) : NULL;
1287 isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
1288 unsigned first, unsigned n)
1290 int i;
1291 enum isl_dim_type set_type;
1293 if (!pw)
1294 return isl_bool_error;
1295 if (pw->n == 0 || n == 0)
1296 return isl_bool_false;
1298 set_type = type == isl_dim_in ? isl_dim_set : type;
1300 for (i = 0; i < pw->n; ++i) {
1301 isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
1302 type, first, n);
1303 if (involves < 0 || involves)
1304 return involves;
1305 involves = isl_set_involves_dims(pw->p[i].set,
1306 set_type, first, n);
1307 if (involves < 0 || involves)
1308 return involves;
1310 return isl_bool_false;
1313 __isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
1314 enum isl_dim_type type, unsigned pos, const char *s)
1316 isl_space *space;
1318 space = FN(PW,get_space)(pw);
1319 space = isl_space_set_dim_name(space, type, pos, s);
1320 return FN(PW,reset_space)(pw, space);
1323 __isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
1324 enum isl_dim_type type, unsigned first, unsigned n)
1326 int i;
1327 isl_size n_piece;
1328 enum isl_dim_type set_type;
1329 isl_space *space;
1331 n_piece = FN(PW,n_piece)(pw);
1332 if (n_piece < 0)
1333 return FN(PW,free)(pw);
1334 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1335 return pw;
1337 set_type = type == isl_dim_in ? isl_dim_set : type;
1339 space = FN(PW,take_space)(pw);
1340 space = isl_space_drop_dims(space, type, first, n);
1341 pw = FN(PW,restore_space)(pw, space);
1342 pw = FN(PW,cow)(pw);
1343 for (i = 0; i < n_piece; ++i) {
1344 EL *el;
1346 el = FN(PW,take_base_at)(pw, i);
1347 el = FN(EL,drop_dims)(el, type, first, n);
1348 pw = FN(PW,restore_base_at)(pw, i, el);
1349 if (!pw)
1350 return NULL;
1351 if (type == isl_dim_out)
1352 continue;
1353 pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
1354 if (!pw->p[i].set)
1355 goto error;
1358 return pw;
1359 error:
1360 FN(PW,free)(pw);
1361 return NULL;
1364 /* This function is very similar to drop_dims.
1365 * The only difference is that the cells may still involve
1366 * the specified dimensions. They are removed using
1367 * isl_set_project_out instead of isl_set_drop.
1369 __isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
1370 enum isl_dim_type type, unsigned first, unsigned n)
1372 int i;
1373 isl_size n_piece;
1374 enum isl_dim_type set_type;
1375 isl_space *space;
1377 n_piece = FN(PW,n_piece)(pw);
1378 if (n_piece < 0)
1379 return FN(PW,free)(pw);
1380 if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
1381 return pw;
1383 set_type = type == isl_dim_in ? isl_dim_set : type;
1385 space = FN(PW,take_space)(pw);
1386 space = isl_space_drop_dims(space, type, first, n);
1387 pw = FN(PW,restore_space)(pw, space);
1388 pw = FN(PW,cow)(pw);
1389 if (!pw)
1390 return NULL;
1391 for (i = 0; i < n_piece; ++i) {
1392 EL *el;
1394 pw->p[i].set = isl_set_project_out(pw->p[i].set,
1395 set_type, first, n);
1396 if (!pw->p[i].set)
1397 goto error;
1398 el = FN(PW,take_base_at)(pw, i);
1399 el = FN(EL,drop_dims)(el, type, first, n);
1400 pw = FN(PW,restore_base_at)(pw, i, el);
1401 if (!pw)
1402 return NULL;
1405 return pw;
1406 error:
1407 FN(PW,free)(pw);
1408 return NULL;
1411 /* Project the domain of pw onto its parameter space.
1413 __isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
1415 isl_space *space;
1416 isl_size n;
1418 n = FN(PW,dim)(pw, isl_dim_in);
1419 if (n < 0)
1420 return FN(PW,free)(pw);
1421 pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
1422 space = FN(PW,get_domain_space)(pw);
1423 space = isl_space_params(space);
1424 pw = FN(PW,reset_domain_space)(pw, space);
1425 return pw;
1428 /* Drop all parameters not referenced by "pw".
1430 __isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw)
1432 isl_size n;
1433 int i;
1435 if (FN(PW,check_named_params)(pw) < 0)
1436 return FN(PW,free)(pw);
1438 n = FN(PW,dim)(pw, isl_dim_param);
1439 if (n < 0)
1440 return FN(PW,free)(pw);
1441 for (i = n - 1; i >= 0; i--) {
1442 isl_bool involves;
1444 involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1);
1445 if (involves < 0)
1446 return FN(PW,free)(pw);
1447 if (!involves)
1448 pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1);
1451 return pw;
1454 __isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
1455 enum isl_dim_type type, unsigned pos, isl_int v)
1457 int i;
1458 isl_size n;
1460 n = FN(PW,n_piece)(pw);
1461 if (n < 0)
1462 return FN(PW,free)(pw);
1464 if (type == isl_dim_in)
1465 type = isl_dim_set;
1467 pw = FN(PW,cow)(pw);
1468 if (!pw)
1469 return NULL;
1470 for (i = 0; i < n; ++i) {
1471 pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
1472 if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
1473 return FN(PW,free)(pw);
1476 return pw;
1479 /* Fix the value of the variable at position "pos" of type "type" of "pw"
1480 * to be equal to "v".
1482 __isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
1483 enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
1485 if (!v)
1486 return FN(PW,free)(pw);
1487 if (!isl_val_is_int(v))
1488 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1489 "expecting integer value", goto error);
1491 pw = FN(PW,fix_dim)(pw, type, pos, v->n);
1492 isl_val_free(v);
1494 return pw;
1495 error:
1496 isl_val_free(v);
1497 return FN(PW,free)(pw);
1500 isl_size FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
1502 return isl_space_dim(FN(PW,peek_space)(pw), type);
1505 __isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
1506 enum isl_dim_type type, unsigned first, unsigned n)
1508 int i;
1509 isl_size n_piece;
1511 n_piece = FN(PW,n_piece)(pw);
1512 if (n_piece < 0)
1513 return FN(PW,free)(pw);
1514 if (n == 0)
1515 return pw;
1517 if (type == isl_dim_in)
1518 type = isl_dim_set;
1520 pw = FN(PW,cow)(pw);
1521 if (!pw)
1522 return NULL;
1523 for (i = 0; i < n; ++i) {
1524 pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
1525 if (!pw->p[i].set)
1526 goto error;
1529 return pw;
1530 error:
1531 FN(PW,free)(pw);
1532 return NULL;
1535 __isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
1537 return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
1540 /* Return the position of the dimension of the given type and name
1541 * in "pw".
1542 * Return -1 if no such dimension can be found.
1544 int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
1545 enum isl_dim_type type, const char *name)
1547 if (!pw)
1548 return -1;
1549 return isl_space_find_dim_by_name(pw->dim, type, name);
1552 /* Return the position of the dimension of the given type and identifier
1553 * in "pw".
1554 * Return -1 if no such dimension can be found.
1556 static int FN(PW,find_dim_by_id)(__isl_keep PW *pw,
1557 enum isl_dim_type type, __isl_keep isl_id *id)
1559 isl_space *space;
1561 space = FN(PW,peek_space)(pw);
1562 return isl_space_find_dim_by_id(space, type, id);
1565 /* Does the piecewise expression "pw" depend in any way
1566 * on the parameter with identifier "id"?
1568 isl_bool FN(PW,involves_param_id)(__isl_keep PW *pw, __isl_keep isl_id *id)
1570 int pos;
1572 if (!pw || !id)
1573 return isl_bool_error;
1574 if (pw->n == 0)
1575 return isl_bool_false;
1577 pos = FN(PW,find_dim_by_id)(pw, isl_dim_param, id);
1578 if (pos < 0)
1579 return isl_bool_false;
1580 return FN(PW,involves_dims)(pw, isl_dim_param, pos, 1);
1583 /* Reset the space of "pw". Since we don't know if the elements
1584 * represent the spaces themselves or their domains, we pass along
1585 * both when we call their reset_space_and_domain.
1587 static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
1588 __isl_take isl_space *space, __isl_take isl_space *domain)
1590 int i;
1591 isl_size n;
1593 pw = FN(PW,cow)(pw);
1594 n = FN(PW,n_piece)(pw);
1595 if (n < 0 || !space || !domain)
1596 goto error;
1598 for (i = 0; i < n; ++i) {
1599 EL *el;
1601 pw->p[i].set = isl_set_reset_space(pw->p[i].set,
1602 isl_space_copy(domain));
1603 if (!pw->p[i].set)
1604 goto error;
1605 el = FN(PW,take_base_at)(pw, i);
1606 el = FN(EL,reset_space_and_domain)(el,
1607 isl_space_copy(space), isl_space_copy(domain));
1608 pw = FN(PW,restore_base_at)(pw, i, el);
1609 if (!pw)
1610 goto error;
1613 isl_space_free(domain);
1615 pw = FN(PW,restore_space)(pw, space);
1617 return pw;
1618 error:
1619 isl_space_free(domain);
1620 isl_space_free(space);
1621 FN(PW,free)(pw);
1622 return NULL;
1625 __isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
1626 __isl_take isl_space *domain)
1628 isl_space *space;
1630 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
1631 FN(PW,get_space)(pw));
1632 return FN(PW,reset_space_and_domain)(pw, space, domain);
1635 __isl_give PW *FN(PW,reset_space)(__isl_take PW *pw,
1636 __isl_take isl_space *space)
1638 isl_space *domain;
1640 domain = isl_space_domain(isl_space_copy(space));
1641 return FN(PW,reset_space_and_domain)(pw, space, domain);
1644 __isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
1645 __isl_take isl_id *id)
1647 isl_space *space;
1649 pw = FN(PW,cow)(pw);
1650 if (!pw)
1651 goto error;
1653 space = FN(PW,get_space)(pw);
1654 space = isl_space_set_tuple_id(space, type, id);
1656 return FN(PW,reset_space)(pw, space);
1657 error:
1658 isl_id_free(id);
1659 return FN(PW,free)(pw);
1662 /* Drop the id on the specified tuple.
1664 __isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
1666 isl_space *space;
1668 if (!pw)
1669 return NULL;
1670 if (!FN(PW,has_tuple_id)(pw, type))
1671 return pw;
1673 pw = FN(PW,cow)(pw);
1674 if (!pw)
1675 return NULL;
1677 space = FN(PW,get_space)(pw);
1678 space = isl_space_reset_tuple_id(space, type);
1680 return FN(PW,reset_space)(pw, space);
1683 __isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
1684 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
1686 isl_space *space;
1688 space = FN(PW,get_space)(pw);
1689 space = isl_space_set_dim_id(space, type, pos, id);
1690 return FN(PW,reset_space)(pw, space);
1693 /* Reset the user pointer on all identifiers of parameters and tuples
1694 * of the space of "pw".
1696 __isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
1698 isl_space *space;
1700 space = FN(PW,get_space)(pw);
1701 space = isl_space_reset_user(space);
1703 return FN(PW,reset_space)(pw, space);
1706 isl_size FN(PW,n_piece)(__isl_keep PW *pw)
1708 return pw ? pw->n : isl_size_error;
1711 isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
1712 isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
1713 void *user)
1715 int i;
1717 if (!pw)
1718 return isl_stat_error;
1720 for (i = 0; i < pw->n; ++i)
1721 if (fn(isl_set_copy(pw->p[i].set),
1722 FN(EL,copy)(pw->p[i].FIELD), user) < 0)
1723 return isl_stat_error;
1725 return isl_stat_ok;
1728 /* Does "test" succeed on every cell of "pw"?
1730 isl_bool FN(PW,every_piece)(__isl_keep PW *pw,
1731 isl_bool (*test)(__isl_keep isl_set *set,
1732 __isl_keep EL *el, void *user), void *user)
1734 int i;
1736 if (!pw)
1737 return isl_bool_error;
1739 for (i = 0; i < pw->n; ++i) {
1740 isl_bool r;
1742 r = test(pw->p[i].set, pw->p[i].FIELD, user);
1743 if (r < 0 || !r)
1744 return r;
1747 return isl_bool_true;
1750 /* Is "pw" defined over a single universe domain?
1752 * If the default value of this piecewise type is zero,
1753 * then a "pw" with a zero number of cells is also accepted
1754 * as it represents the default zero value.
1756 isl_bool FN(FN(PW,isa),BASE)(__isl_keep PW *pw)
1758 isl_size n;
1760 n = FN(PW,n_piece)(pw);
1761 if (n < 0)
1762 return isl_bool_error;
1763 if (DEFAULT_IS_ZERO && n == 0)
1764 return isl_bool_true;
1765 if (n != 1)
1766 return isl_bool_false;
1767 return isl_set_plain_is_universe(FN(PW,peek_domain_at)(pw, 0));
1770 /* Return a zero base expression in the same space (and of the same type)
1771 * as "pw".
1773 static __isl_give EL *FN(EL,zero_like_type)(__isl_take PW *pw OPT_TYPE_PARAM)
1775 isl_space *space;
1777 space = FN(PW,get_space)(pw);
1778 FN(PW,free)(pw);
1779 return FN(EL,zero_in_space)(space OPT_TYPE_ARG(NO_LOC));
1782 #ifndef HAS_TYPE
1783 /* Return a zero base expression in the same space as "pw".
1785 static __isl_give EL *FN(EL,zero_like)(__isl_take PW *pw)
1787 return FN(EL,zero_like_type)(pw);
1789 #else
1790 /* Return a zero base expression in the same space and of the same type
1791 * as "pw".
1793 * Pass along the type as an explicit argument for uniform handling
1794 * in isl_*_zero_like_type.
1796 static __isl_give EL *FN(EL,zero_like)(__isl_take PW *pw)
1798 enum isl_fold type;
1800 type = FN(PW,get_type)(pw);
1801 if (type < 0)
1802 goto error;
1803 return FN(EL,zero_like_type)(pw, type);
1804 error:
1805 FN(PW,free)(pw);
1806 return NULL;
1808 #endif
1810 /* Given that "pw" is defined over a single universe domain,
1811 * return the base expression associated to this domain.
1813 * If the number of cells is zero, then "pw" is of a piecewise type
1814 * with a default zero value and effectively represents zero.
1815 * In this case, create a zero base expression in the same space
1816 * (and with the same type).
1817 * Otherwise, simply extract the associated base expression.
1819 __isl_give EL *FN(FN(PW,as),BASE)(__isl_take PW *pw)
1821 isl_bool is_total;
1822 isl_size n;
1823 EL *el;
1825 is_total = FN(FN(PW,isa),BASE)(pw);
1826 if (is_total < 0)
1827 goto error;
1828 if (!is_total)
1829 isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
1830 "expecting single total function", goto error);
1831 n = FN(PW,n_piece)(pw);
1832 if (n < 0)
1833 goto error;
1834 if (n == 0)
1835 return FN(EL,zero_like)(pw);
1836 el = FN(PW,take_base_at)(pw, 0);
1837 FN(PW,free)(pw);
1838 return el;
1839 error:
1840 FN(PW,free)(pw);
1841 return NULL;
1844 #ifdef HAS_TYPE
1845 /* Negate the type of "pw".
1847 static __isl_give PW *FN(PW,negate_type)(__isl_take PW *pw)
1849 pw = FN(PW,cow)(pw);
1850 if (!pw)
1851 return NULL;
1852 pw->type = isl_fold_type_negate(pw->type);
1853 return pw;
1855 #else
1856 /* Negate the type of "pw".
1857 * Since "pw" does not have a type, do nothing.
1859 static __isl_give PW *FN(PW,negate_type)(__isl_take PW *pw)
1861 return pw;
1863 #endif
1865 __isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
1867 int i;
1868 isl_size n;
1870 if (isl_int_is_one(v))
1871 return pw;
1872 if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
1873 PW *zero;
1874 isl_space *space = FN(PW,get_space)(pw);
1875 zero = FN(PW,ZERO)(space OPT_TYPE_ARG(pw->));
1876 FN(PW,free)(pw);
1877 return zero;
1879 if (isl_int_is_neg(v))
1880 pw = FN(PW,negate_type)(pw);
1882 n = FN(PW,n_piece)(pw);
1883 if (n < 0)
1884 return FN(PW,free)(pw);
1885 for (i = 0; i < n; ++i) {
1886 EL *el;
1888 el = FN(PW,take_base_at)(pw, i);
1889 el = FN(EL,scale)(el, v);
1890 pw = FN(PW,restore_base_at)(pw, i, el);
1893 return pw;
1896 /* Multiply the pieces of "pw" by "v" and return the result.
1898 __isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
1900 int i;
1901 isl_size n;
1903 if (!pw || !v)
1904 goto error;
1906 if (isl_val_is_one(v)) {
1907 isl_val_free(v);
1908 return pw;
1910 if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
1911 PW *zero;
1912 isl_space *space = FN(PW,get_space)(pw);
1913 zero = FN(PW,ZERO)(space OPT_TYPE_ARG(pw->));
1914 FN(PW,free)(pw);
1915 isl_val_free(v);
1916 return zero;
1918 if (isl_val_is_neg(v))
1919 pw = FN(PW,negate_type)(pw);
1920 n = FN(PW,n_piece)(pw);
1921 if (n < 0)
1922 goto error;
1924 for (i = 0; i < n; ++i) {
1925 EL *el;
1927 el = FN(PW,take_base_at)(pw, i);
1928 el = FN(EL,scale_val)(el, isl_val_copy(v));
1929 pw = FN(PW,restore_base_at)(pw, i, el);
1932 isl_val_free(v);
1933 return pw;
1934 error:
1935 isl_val_free(v);
1936 FN(PW,free)(pw);
1937 return NULL;
1940 /* Divide the pieces of "pw" by "v" and return the result.
1942 __isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
1944 int i;
1945 isl_size n;
1947 if (!pw || !v)
1948 goto error;
1950 if (isl_val_is_one(v)) {
1951 isl_val_free(v);
1952 return pw;
1955 if (!isl_val_is_rat(v))
1956 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1957 "expecting rational factor", goto error);
1958 if (isl_val_is_zero(v))
1959 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1960 "cannot scale down by zero", goto error);
1962 if (isl_val_is_neg(v))
1963 pw = FN(PW,negate_type)(pw);
1964 n = FN(PW,n_piece)(pw);
1965 if (n < 0)
1966 goto error;
1968 for (i = 0; i < n; ++i) {
1969 EL *el;
1971 el = FN(PW,take_base_at)(pw, i);
1972 el = FN(EL,scale_down_val)(el, isl_val_copy(v));
1973 pw = FN(PW,restore_base_at)(pw, i, el);
1976 isl_val_free(v);
1977 return pw;
1978 error:
1979 isl_val_free(v);
1980 FN(PW,free)(pw);
1981 return NULL;
1984 __isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
1986 return FN(PW,mul_isl_int)(pw, v);
1989 /* Apply some normalization to "pw".
1990 * In particular, sort the pieces according to their function value
1991 * expressions, combining pairs of adjacent pieces with
1992 * the same such expression, and then normalize the domains of the pieces.
1994 * We normalize in place, but if anything goes wrong we need
1995 * to return NULL, so we need to make sure we don't change the
1996 * meaning of any possible other copies of "pw".
1998 __isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
2000 int i;
2001 isl_set *set;
2003 pw = FN(PW,sort_unique)(pw);
2004 if (!pw)
2005 return NULL;
2006 for (i = 0; i < pw->n; ++i) {
2007 set = isl_set_normalize(isl_set_copy(pw->p[i].set));
2008 if (!set)
2009 return FN(PW,free)(pw);
2010 isl_set_free(pw->p[i].set);
2011 pw->p[i].set = set;
2014 return pw;
2017 /* Is pw1 obviously equal to pw2?
2018 * That is, do they have obviously identical cells and obviously identical
2019 * elements on each cell?
2021 * If "pw1" or "pw2" contain any NaNs, then they are considered
2022 * not to be the same. A NaN is not equal to anything, not even
2023 * to another NaN.
2025 isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
2027 int i;
2028 isl_bool equal, has_nan;
2030 if (!pw1 || !pw2)
2031 return isl_bool_error;
2033 has_nan = FN(PW,involves_nan)(pw1);
2034 if (has_nan >= 0 && !has_nan)
2035 has_nan = FN(PW,involves_nan)(pw2);
2036 if (has_nan < 0 || has_nan)
2037 return isl_bool_not(has_nan);
2039 if (pw1 == pw2)
2040 return isl_bool_true;
2041 equal = FN(PW,has_equal_space)(pw1, pw2);
2042 if (equal < 0 || !equal)
2043 return equal;
2045 pw1 = FN(PW,copy)(pw1);
2046 pw2 = FN(PW,copy)(pw2);
2047 pw1 = FN(PW,normalize)(pw1);
2048 pw2 = FN(PW,normalize)(pw2);
2049 if (!pw1 || !pw2)
2050 goto error;
2052 equal = isl_bool_ok(pw1->n == pw2->n);
2053 for (i = 0; equal && i < pw1->n; ++i) {
2054 equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
2055 if (equal < 0)
2056 goto error;
2057 if (!equal)
2058 break;
2059 equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
2060 if (equal < 0)
2061 goto error;
2064 FN(PW,free)(pw1);
2065 FN(PW,free)(pw2);
2066 return equal;
2067 error:
2068 FN(PW,free)(pw1);
2069 FN(PW,free)(pw2);
2070 return isl_bool_error;
2073 /* Does "pw" involve any NaNs?
2075 isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
2077 int i;
2079 if (!pw)
2080 return isl_bool_error;
2081 if (pw->n == 0)
2082 return isl_bool_false;
2084 for (i = 0; i < pw->n; ++i) {
2085 isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
2086 if (has_nan < 0 || has_nan)
2087 return has_nan;
2090 return isl_bool_false;